use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EffectClass {
ReadOnly,
WorkspaceWrite,
Network,
ExternalSideEffect,
SecretAccess,
}
impl EffectClass {
pub fn default_policy(&self) -> PolicyDecision {
match self {
Self::ReadOnly => PolicyDecision::Allow,
Self::WorkspaceWrite | Self::Network => PolicyDecision::RequireApproval {
reason: "mutable or networked tool call requires explicit policy allowance".into(),
},
Self::ExternalSideEffect | Self::SecretAccess => PolicyDecision::Deny {
reason: "external side effects and secret access fail closed by default".into(),
},
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "decision")]
pub enum PolicyDecision {
Allow,
RequireApproval {
reason: String,
},
Deny {
reason: String,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn external_side_effects_fail_closed_by_default() {
assert!(matches!(
EffectClass::ExternalSideEffect.default_policy(),
PolicyDecision::Deny { .. }
));
}
#[test]
fn read_only_is_allowed_by_default() {
assert!(matches!(
EffectClass::ReadOnly.default_policy(),
PolicyDecision::Allow
));
}
}