pmcp_code_mode/policy/
mod.rs1pub mod types;
12
13#[cfg(feature = "cedar")]
14pub mod cedar;
15
16pub use types::*;
17
18#[derive(Debug, thiserror::Error)]
20pub enum PolicyEvaluationError {
21 #[error("Policy configuration error: {0}")]
22 ConfigError(String),
23
24 #[error("Policy evaluation error: {0}")]
25 EvaluationError(String),
26
27 #[error("Authorization denied: {0}")]
28 Denied(String),
29}
30
31#[async_trait::async_trait]
38pub trait PolicyEvaluator: Send + Sync {
39 async fn evaluate_operation(
41 &self,
42 operation: &OperationEntity,
43 server_config: &ServerConfigEntity,
44 ) -> Result<AuthorizationDecision, PolicyEvaluationError>;
45
46 #[cfg(feature = "openapi-code-mode")]
49 async fn evaluate_script(
50 &self,
51 _script: &ScriptEntity,
52 _server: &OpenAPIServerEntity,
53 ) -> Result<AuthorizationDecision, PolicyEvaluationError> {
54 Ok(AuthorizationDecision {
55 allowed: false,
56 determining_policies: vec!["default_deny_scripts".to_string()],
57 errors: vec!["Script evaluation not supported by this policy evaluator".to_string()],
58 })
59 }
60
61 #[cfg(feature = "sql-code-mode")]
64 async fn evaluate_statement(
65 &self,
66 _statement: &StatementEntity,
67 _server: &SqlServerEntity,
68 ) -> Result<AuthorizationDecision, PolicyEvaluationError> {
69 Ok(AuthorizationDecision {
70 allowed: false,
71 determining_policies: vec!["default_deny_statements".to_string()],
72 errors: vec![
73 "SQL statement evaluation not supported by this policy evaluator".to_string(),
74 ],
75 })
76 }
77
78 async fn batch_evaluate(
80 &self,
81 requests: Vec<(OperationEntity, ServerConfigEntity)>,
82 ) -> Result<Vec<AuthorizationDecision>, PolicyEvaluationError> {
83 let mut results = Vec::with_capacity(requests.len());
84 for (op, config) in &requests {
85 results.push(self.evaluate_operation(op, config).await?);
86 }
87 Ok(results)
88 }
89
90 fn is_configured(&self) -> bool {
92 true
93 }
94
95 fn name(&self) -> &str;
97}
98
99pub struct NoopPolicyEvaluator;
120
121impl NoopPolicyEvaluator {
122 pub fn new() -> Self {
127 Self
128 }
129}
130
131impl Default for NoopPolicyEvaluator {
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137#[async_trait::async_trait]
138impl PolicyEvaluator for NoopPolicyEvaluator {
139 async fn evaluate_operation(
140 &self,
141 _operation: &OperationEntity,
142 _server_config: &ServerConfigEntity,
143 ) -> Result<AuthorizationDecision, PolicyEvaluationError> {
144 Ok(AuthorizationDecision {
145 allowed: true,
146 determining_policies: vec!["noop_allow_all".to_string()],
147 errors: vec![],
148 })
149 }
150
151 #[cfg(feature = "openapi-code-mode")]
152 async fn evaluate_script(
153 &self,
154 _script: &ScriptEntity,
155 _server: &OpenAPIServerEntity,
156 ) -> Result<AuthorizationDecision, PolicyEvaluationError> {
157 Ok(AuthorizationDecision {
158 allowed: true,
159 determining_policies: vec!["noop_allow_all_scripts".to_string()],
160 errors: vec![],
161 })
162 }
163
164 #[cfg(feature = "sql-code-mode")]
165 async fn evaluate_statement(
166 &self,
167 _statement: &StatementEntity,
168 _server: &SqlServerEntity,
169 ) -> Result<AuthorizationDecision, PolicyEvaluationError> {
170 Ok(AuthorizationDecision {
171 allowed: true,
172 determining_policies: vec!["noop_allow_all_statements".to_string()],
173 errors: vec![],
174 })
175 }
176
177 fn name(&self) -> &str {
178 "noop"
179 }
180}
181
182#[cfg(test)]
183mod noop_tests {
184 use super::*;
185
186 #[tokio::test]
187 async fn noop_evaluator_allows_all_operations() {
188 let evaluator = NoopPolicyEvaluator::new();
189 let operation = OperationEntity {
190 id: "test-op".to_string(),
191 operation_type: "query".to_string(),
192 operation_name: "GetUsers".to_string(),
193 root_fields: ["users"].iter().map(|s| s.to_string()).collect(),
194 accessed_types: ["User"].iter().map(|s| s.to_string()).collect(),
195 accessed_fields: ["User.id", "User.name"]
196 .iter()
197 .map(|s| s.to_string())
198 .collect(),
199 depth: 2,
200 field_count: 2,
201 estimated_cost: 2,
202 has_introspection: false,
203 accesses_sensitive_data: false,
204 sensitive_categories: std::collections::HashSet::new(),
205 };
206 let config = ServerConfigEntity::default();
207 let result = evaluator
208 .evaluate_operation(&operation, &config)
209 .await
210 .unwrap();
211 assert!(result.allowed);
212 assert_eq!(result.determining_policies, vec!["noop_allow_all"]);
213 }
214
215 #[test]
216 fn noop_evaluator_name() {
217 let evaluator = NoopPolicyEvaluator::new();
218 assert_eq!(evaluator.name(), "noop");
219 }
220
221 #[test]
222 fn noop_evaluator_default() {
223 let evaluator = NoopPolicyEvaluator::default();
224 assert_eq!(evaluator.name(), "noop");
225 }
226}