Skip to main content

agentzero_core/security/
policy.rs

1use std::str::FromStr;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum RiskTier {
5    P0Critical,
6    P1High,
7    P2Moderate,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum RiskDomain {
12    ToolExecution,
13    ProviderNetwork,
14    ChannelIngress,
15    RemoteMemory,
16    PrivacyRelay,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct RequiredControls {
21    pub deny_by_default: bool,
22    pub requires_explicit_allowlist: bool,
23    pub requires_redaction: bool,
24    pub requires_timeout: bool,
25}
26
27impl FromStr for RiskDomain {
28    type Err = String;
29
30    fn from_str(value: &str) -> Result<Self, Self::Err> {
31        match value {
32            "tool_execution" => Ok(Self::ToolExecution),
33            "provider_network" => Ok(Self::ProviderNetwork),
34            "channel_ingress" => Ok(Self::ChannelIngress),
35            "remote_memory" => Ok(Self::RemoteMemory),
36            "privacy_relay" => Ok(Self::PrivacyRelay),
37            other => Err(format!("unsupported risk domain: {other}")),
38        }
39    }
40}
41
42pub fn baseline_version() -> &'static str {
43    "2026-02-27"
44}
45
46pub fn tier_for(domain: RiskDomain) -> RiskTier {
47    match domain {
48        RiskDomain::ToolExecution => RiskTier::P0Critical,
49        RiskDomain::ChannelIngress => RiskTier::P0Critical,
50        RiskDomain::ProviderNetwork => RiskTier::P1High,
51        RiskDomain::RemoteMemory => RiskTier::P1High,
52        RiskDomain::PrivacyRelay => RiskTier::P1High,
53    }
54}
55
56pub fn controls_for(domain: RiskDomain) -> RequiredControls {
57    match domain {
58        RiskDomain::ToolExecution => RequiredControls {
59            deny_by_default: true,
60            requires_explicit_allowlist: true,
61            requires_redaction: true,
62            requires_timeout: true,
63        },
64        RiskDomain::ChannelIngress => RequiredControls {
65            deny_by_default: true,
66            requires_explicit_allowlist: true,
67            requires_redaction: true,
68            requires_timeout: true,
69        },
70        RiskDomain::ProviderNetwork => RequiredControls {
71            deny_by_default: false,
72            requires_explicit_allowlist: false,
73            requires_redaction: true,
74            requires_timeout: true,
75        },
76        RiskDomain::RemoteMemory => RequiredControls {
77            deny_by_default: false,
78            requires_explicit_allowlist: false,
79            requires_redaction: true,
80            requires_timeout: true,
81        },
82        RiskDomain::PrivacyRelay => RequiredControls {
83            deny_by_default: true,
84            requires_explicit_allowlist: true,
85            requires_redaction: true,
86            requires_timeout: true,
87        },
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::{controls_for, tier_for, RiskDomain, RiskTier};
94    use std::str::FromStr;
95
96    #[test]
97    fn policy_marks_tool_execution_as_critical() {
98        assert_eq!(tier_for(RiskDomain::ToolExecution), RiskTier::P0Critical);
99        assert!(controls_for(RiskDomain::ToolExecution).deny_by_default);
100    }
101
102    #[test]
103    fn parsing_unknown_domain_fails() {
104        let parse = RiskDomain::from_str("unknown-domain");
105        assert!(parse.is_err());
106    }
107
108    #[test]
109    fn privacy_relay_domain_is_high_risk_with_deny_by_default() {
110        assert_eq!(tier_for(RiskDomain::PrivacyRelay), RiskTier::P1High);
111        let controls = controls_for(RiskDomain::PrivacyRelay);
112        assert!(controls.deny_by_default);
113        assert!(controls.requires_explicit_allowlist);
114        assert!(controls.requires_redaction);
115        assert!(controls.requires_timeout);
116    }
117
118    #[test]
119    fn privacy_relay_domain_parses_from_string() {
120        let domain = RiskDomain::from_str("privacy_relay").unwrap();
121        assert_eq!(domain, RiskDomain::PrivacyRelay);
122    }
123}