Skip to main content

leviath_runtime/pipeline/
gate.rs

1//! Taint-gate policy resources and the gate's block message.
2
3use super::*;
4
5/// Per-tool output sensitivity for an agent, populated by the taint-gate system
6/// when taint tracking is enabled. Absent ⇒ taint off ⇒ results tagged Public.
7#[derive(Component, Debug, Clone, Default)]
8pub struct ToolSensitivities(pub std::collections::HashMap<String, leviath_core::TaintLevel>);
9
10/// The tool allowlist policy (`policy.toml`), as a world resource. The daemon
11/// inserts it; a taint-gated agent's outbound calls are checked against it. When
12/// absent, the gate falls back to an empty policy (deny-by-clearance only).
13#[derive(Resource, Default)]
14pub struct PolicyGate(pub leviath_core::PolicyConfig);
15
16/// The scripted gate rules (`~/.config/leviath/rules/*.rhai`), as a world
17/// resource. The daemon builds the checker (it owns the Rhai engine); the gate
18/// consults it after the static allowlist. Absent ⇒ no scripted rules.
19#[derive(Resource, Clone)]
20pub struct GateScriptRules(pub std::sync::Arc<crate::taint::ScriptRuleChecker>);
21
22/// The `[blocked]` tool result produced when the taint gate denies an outbound
23/// call: enough for the model to understand why and adjust.
24pub(crate) fn taint_block_message(decision: &leviath_core::taint::GateDecision) -> String {
25    match decision {
26        leviath_core::taint::GateDecision::Blocked {
27            taint_level,
28            clearance,
29            tool_name,
30            source_regions,
31        } => format!(
32            "[blocked] Tool '{tool_name}' would send {taint_level:?}-level data over a channel \
33             cleared only for {clearance:?} (tainted by: {}). Add an allowlist rule with \
34             `lev policy add` to permit it.",
35            if source_regions.is_empty() {
36                "context".to_string()
37            } else {
38                source_regions.join(", ")
39            }
40        ),
41        // Only ever called on a Blocked decision.
42        leviath_core::taint::GateDecision::Allowed => "[blocked] tool call denied".to_string(),
43    }
44}