a3s_code_core/permissions/
policy.rs1use serde::{Deserialize, Serialize};
2
3use super::{MatchingRules, PermissionChecker, PermissionDecision, PermissionRule};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct PermissionPolicy {
14 #[serde(default)]
16 pub deny: Vec<PermissionRule>,
17
18 #[serde(default)]
20 pub allow: Vec<PermissionRule>,
21
22 #[serde(default)]
24 pub ask: Vec<PermissionRule>,
25
26 #[serde(default = "default_decision")]
28 pub default_decision: PermissionDecision,
29
30 #[serde(default = "default_enabled")]
32 pub enabled: bool,
33}
34
35fn default_decision() -> PermissionDecision {
36 PermissionDecision::Ask
37}
38
39fn default_enabled() -> bool {
40 true
41}
42
43impl Default for PermissionPolicy {
44 fn default() -> Self {
45 Self {
46 deny: Vec::new(),
47 allow: Vec::new(),
48 ask: Vec::new(),
49 default_decision: PermissionDecision::Ask,
50 enabled: true,
51 }
52 }
53}
54
55impl PermissionPolicy {
56 pub fn new() -> Self {
58 Self::default()
59 }
60
61 pub fn strict() -> Self {
63 Self {
64 deny: Vec::new(),
65 allow: Vec::new(),
66 ask: Vec::new(),
67 default_decision: PermissionDecision::Ask,
68 enabled: true,
69 }
70 }
71
72 pub fn deny(mut self, rule: &str) -> Self {
74 self.deny.push(PermissionRule::new(rule));
75 self
76 }
77
78 pub fn allow(mut self, rule: &str) -> Self {
80 self.allow.push(PermissionRule::new(rule));
81 self
82 }
83
84 pub fn ask(mut self, rule: &str) -> Self {
86 self.ask.push(PermissionRule::new(rule));
87 self
88 }
89
90 pub fn deny_all(mut self, rules: &[&str]) -> Self {
92 for rule in rules {
93 self.deny.push(PermissionRule::new(rule));
94 }
95 self
96 }
97
98 pub fn allow_all(mut self, rules: &[&str]) -> Self {
100 for rule in rules {
101 self.allow.push(PermissionRule::new(rule));
102 }
103 self
104 }
105
106 pub fn ask_all(mut self, rules: &[&str]) -> Self {
108 for rule in rules {
109 self.ask.push(PermissionRule::new(rule));
110 }
111 self
112 }
113
114 pub fn check(&self, tool_name: &str, args: &serde_json::Value) -> PermissionDecision {
122 if !self.enabled {
123 return PermissionDecision::Allow;
124 }
125
126 for rule in &self.deny {
128 if rule.matches(tool_name, args) {
129 return PermissionDecision::Deny;
130 }
131 }
132
133 for rule in &self.allow {
135 if rule.matches(tool_name, args) {
136 return PermissionDecision::Allow;
137 }
138 }
139
140 for rule in &self.ask {
142 if rule.matches(tool_name, args) {
143 return PermissionDecision::Ask;
144 }
145 }
146
147 self.default_decision
149 }
150
151 pub fn is_allowed(&self, tool_name: &str, args: &serde_json::Value) -> bool {
153 matches!(self.check(tool_name, args), PermissionDecision::Allow)
154 }
155
156 pub fn is_denied(&self, tool_name: &str, args: &serde_json::Value) -> bool {
158 matches!(self.check(tool_name, args), PermissionDecision::Deny)
159 }
160
161 pub fn requires_confirmation(&self, tool_name: &str, args: &serde_json::Value) -> bool {
163 matches!(self.check(tool_name, args), PermissionDecision::Ask)
164 }
165
166 pub fn get_matching_rules(&self, tool_name: &str, args: &serde_json::Value) -> MatchingRules {
168 let mut result = MatchingRules::default();
169
170 for rule in &self.deny {
171 if rule.matches(tool_name, args) {
172 result.deny.push(rule.rule.clone());
173 }
174 }
175
176 for rule in &self.allow {
177 if rule.matches(tool_name, args) {
178 result.allow.push(rule.rule.clone());
179 }
180 }
181
182 for rule in &self.ask {
183 if rule.matches(tool_name, args) {
184 result.ask.push(rule.rule.clone());
185 }
186 }
187
188 result
189 }
190}
191
192impl PermissionChecker for PermissionPolicy {
193 fn check(&self, tool_name: &str, args: &serde_json::Value) -> PermissionDecision {
194 self.check(tool_name, args)
195 }
196}