Skip to main content

pmcp_code_mode/policy/
mod.rs

1//! Policy evaluation for Code Mode.
2//!
3//! This module provides a trait-based abstraction for policy evaluation,
4//! allowing different backends (AVP, local Cedar, etc.) to be used
5//! interchangeably.
6
7pub mod types;
8
9#[cfg(feature = "cedar")]
10pub mod cedar;
11
12pub use types::*;
13
14/// Error type for policy evaluation.
15#[derive(Debug, thiserror::Error)]
16pub enum PolicyEvaluationError {
17    #[error("Policy configuration error: {0}")]
18    ConfigError(String),
19
20    #[error("Policy evaluation error: {0}")]
21    EvaluationError(String),
22
23    #[error("Authorization denied: {0}")]
24    Denied(String),
25}
26
27/// Trait for policy evaluation backends.
28///
29/// Implementations can use different backends:
30/// - `AvpPolicyEvaluator` (in mcp-server-common): Uses AWS AVP
31/// - `CedarPolicyEvaluator` (in this crate): Uses local Cedar engine
32/// - Custom implementations for testing or other policy engines
33#[async_trait::async_trait]
34pub trait PolicyEvaluator: Send + Sync {
35    /// Evaluate a GraphQL operation against policies.
36    async fn evaluate_operation(
37        &self,
38        operation: &OperationEntity,
39        server_config: &ServerConfigEntity,
40    ) -> Result<AuthorizationDecision, PolicyEvaluationError>;
41
42    /// Evaluate a JavaScript script against policies (OpenAPI Code Mode).
43    /// Default: denies all scripts (override for OpenAPI support).
44    #[cfg(feature = "openapi-code-mode")]
45    async fn evaluate_script(
46        &self,
47        _script: &ScriptEntity,
48        _server: &OpenAPIServerEntity,
49    ) -> Result<AuthorizationDecision, PolicyEvaluationError> {
50        Ok(AuthorizationDecision {
51            allowed: false,
52            determining_policies: vec!["default_deny_scripts".to_string()],
53            errors: vec!["Script evaluation not supported by this policy evaluator".to_string()],
54        })
55    }
56
57    /// Batch evaluation (default: sequential).
58    async fn batch_evaluate(
59        &self,
60        requests: Vec<(OperationEntity, ServerConfigEntity)>,
61    ) -> Result<Vec<AuthorizationDecision>, PolicyEvaluationError> {
62        let mut results = Vec::with_capacity(requests.len());
63        for (op, config) in &requests {
64            results.push(self.evaluate_operation(op, config).await?);
65        }
66        Ok(results)
67    }
68
69    /// Whether this evaluator is configured and ready.
70    fn is_configured(&self) -> bool {
71        true
72    }
73
74    /// Human-readable name for logging.
75    fn name(&self) -> &str;
76}