sigil_protocol/policy.rs
1//! Policy — permission and rate-limiting enforcement.
2//!
3//! SIGIL defines the risk model and policy trait.
4//! Implementations configure their own rules (allowlists, rate limits,
5//! confirmation requirements, etc.).
6
7use serde::{Deserialize, Serialize};
8
9/// Risk level classification for actions.
10///
11/// Every action in a SIGIL-protected system is classified into one
12/// of these three levels. The policy then decides what to do.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14pub enum RiskLevel {
15 /// Safe actions (read-only, within workspace).
16 Low,
17 /// Actions that modify state but are recoverable.
18 Medium,
19 /// Destructive, external, or irreversible actions.
20 High,
21}
22
23impl std::fmt::Display for RiskLevel {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 RiskLevel::Low => write!(f, "low"),
27 RiskLevel::Medium => write!(f, "medium"),
28 RiskLevel::High => write!(f, "high"),
29 }
30 }
31}
32
33/// Trait for security policy enforcement.
34///
35/// Implementations define their own rules for what actions are allowed,
36/// what requires confirmation, and how rate limiting works.
37///
38/// # Protocol Requirements
39///
40/// A conforming implementation MUST:
41/// 1. Classify all actions by `RiskLevel`
42/// 2. Enforce rate limiting via `record_action()`
43/// 3. Gate high-risk actions through `requires_confirmation()`
44///
45/// # Example
46///
47/// ```rust,no_run
48/// use sigil_protocol::{SecurityPolicy, RiskLevel};
49///
50/// struct StrictPolicy;
51///
52/// impl SecurityPolicy for StrictPolicy {
53/// fn is_action_allowed(&self, action: &str) -> bool { false }
54/// fn risk_level(&self, action: &str) -> RiskLevel { RiskLevel::High }
55/// fn requires_confirmation(&self, action: &str) -> bool { true }
56/// fn record_action(&self) -> bool { true }
57/// fn is_rate_limited(&self) -> bool { false }
58/// }
59/// ```
60pub trait SecurityPolicy: Send + Sync {
61 /// Check if an action (tool/command name) is allowed to execute.
62 fn is_action_allowed(&self, action: &str) -> bool;
63
64 /// Classify the risk level of an action.
65 fn risk_level(&self, action: &str) -> RiskLevel;
66
67 /// Check if an action requires explicit user confirmation.
68 fn requires_confirmation(&self, action: &str) -> bool;
69
70 /// Record an action execution for rate limiting.
71 /// Returns `true` if the action is within rate limits, `false` if exceeded.
72 fn record_action(&self) -> bool;
73
74 /// Check if the rate limit would be exceeded (without recording).
75 fn is_rate_limited(&self) -> bool;
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn risk_level_display() {
84 assert_eq!(format!("{}", RiskLevel::Low), "low");
85 assert_eq!(format!("{}", RiskLevel::Medium), "medium");
86 assert_eq!(format!("{}", RiskLevel::High), "high");
87 }
88
89 #[test]
90 fn risk_level_serializes() {
91 let json = serde_json::to_string(&RiskLevel::High).unwrap();
92 let parsed: RiskLevel = serde_json::from_str(&json).unwrap();
93 assert_eq!(parsed, RiskLevel::High);
94 }
95}