a3s_code_core/permissions/
manager.rs1use std::collections::HashMap;
2
3use super::{PermissionDecision, PermissionPolicy};
4
5#[derive(Debug, Default, Clone)]
7pub struct MatchingRules {
8 pub deny: Vec<String>,
9 pub allow: Vec<String>,
10 pub ask: Vec<String>,
11}
12
13impl MatchingRules {
14 pub fn is_empty(&self) -> bool {
15 self.deny.is_empty() && self.allow.is_empty() && self.ask.is_empty()
16 }
17}
18
19#[derive(Debug)]
21pub struct PermissionManager {
22 global_policy: PermissionPolicy,
24 session_policies: HashMap<String, PermissionPolicy>,
26}
27
28impl Default for PermissionManager {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl PermissionManager {
35 pub fn new() -> Self {
37 Self {
38 global_policy: PermissionPolicy::default(),
39 session_policies: HashMap::new(),
40 }
41 }
42
43 pub fn with_global_policy(policy: PermissionPolicy) -> Self {
45 Self {
46 global_policy: policy,
47 session_policies: HashMap::new(),
48 }
49 }
50
51 pub fn set_global_policy(&mut self, policy: PermissionPolicy) {
53 self.global_policy = policy;
54 }
55
56 pub fn global_policy(&self) -> &PermissionPolicy {
58 &self.global_policy
59 }
60
61 pub fn set_session_policy(&mut self, session_id: &str, policy: PermissionPolicy) {
63 self.session_policies.insert(session_id.to_string(), policy);
64 }
65
66 pub fn remove_session_policy(&mut self, session_id: &str) {
68 self.session_policies.remove(session_id);
69 }
70
71 pub fn get_effective_policy(&self, session_id: &str) -> &PermissionPolicy {
76 self.session_policies
77 .get(session_id)
78 .unwrap_or(&self.global_policy)
79 }
80
81 pub fn check(
83 &self,
84 session_id: &str,
85 tool_name: &str,
86 args: &serde_json::Value,
87 ) -> PermissionDecision {
88 let policy = self.get_effective_policy(session_id);
90
91 for rule in &policy.deny {
93 if rule.matches(tool_name, args) {
94 return PermissionDecision::Deny;
95 }
96 }
97
98 if !self.session_policies.contains_key(session_id) {
100 } else {
102 for rule in &self.global_policy.deny {
103 if rule.matches(tool_name, args) {
104 return PermissionDecision::Deny;
105 }
106 }
107 }
108
109 for rule in &policy.allow {
111 if rule.matches(tool_name, args) {
112 return PermissionDecision::Allow;
113 }
114 }
115
116 for rule in &policy.ask {
118 if rule.matches(tool_name, args) {
119 return PermissionDecision::Ask;
120 }
121 }
122
123 policy.default_decision
125 }
126}