pub mod types;
#[cfg(feature = "cedar")]
pub mod cedar;
pub use types::*;
#[derive(Debug, thiserror::Error)]
pub enum PolicyEvaluationError {
#[error("Policy configuration error: {0}")]
ConfigError(String),
#[error("Policy evaluation error: {0}")]
EvaluationError(String),
#[error("Authorization denied: {0}")]
Denied(String),
}
#[async_trait::async_trait]
pub trait PolicyEvaluator: Send + Sync {
async fn evaluate_operation(
&self,
operation: &OperationEntity,
server_config: &ServerConfigEntity,
) -> Result<AuthorizationDecision, PolicyEvaluationError>;
#[cfg(feature = "openapi-code-mode")]
async fn evaluate_script(
&self,
_script: &ScriptEntity,
_server: &OpenAPIServerEntity,
) -> Result<AuthorizationDecision, PolicyEvaluationError> {
Ok(AuthorizationDecision {
allowed: false,
determining_policies: vec!["default_deny_scripts".to_string()],
errors: vec!["Script evaluation not supported by this policy evaluator".to_string()],
})
}
#[cfg(feature = "sql-code-mode")]
async fn evaluate_statement(
&self,
_statement: &StatementEntity,
_server: &SqlServerEntity,
) -> Result<AuthorizationDecision, PolicyEvaluationError> {
Ok(AuthorizationDecision {
allowed: false,
determining_policies: vec!["default_deny_statements".to_string()],
errors: vec![
"SQL statement evaluation not supported by this policy evaluator".to_string(),
],
})
}
async fn batch_evaluate(
&self,
requests: Vec<(OperationEntity, ServerConfigEntity)>,
) -> Result<Vec<AuthorizationDecision>, PolicyEvaluationError> {
let mut results = Vec::with_capacity(requests.len());
for (op, config) in &requests {
results.push(self.evaluate_operation(op, config).await?);
}
Ok(results)
}
fn is_configured(&self) -> bool {
true
}
fn name(&self) -> &str;
}
pub struct NoopPolicyEvaluator;
impl NoopPolicyEvaluator {
pub fn new() -> Self {
Self
}
}
impl Default for NoopPolicyEvaluator {
fn default() -> Self {
Self::new()
}
}
#[async_trait::async_trait]
impl PolicyEvaluator for NoopPolicyEvaluator {
async fn evaluate_operation(
&self,
_operation: &OperationEntity,
_server_config: &ServerConfigEntity,
) -> Result<AuthorizationDecision, PolicyEvaluationError> {
Ok(AuthorizationDecision {
allowed: true,
determining_policies: vec!["noop_allow_all".to_string()],
errors: vec![],
})
}
#[cfg(feature = "openapi-code-mode")]
async fn evaluate_script(
&self,
_script: &ScriptEntity,
_server: &OpenAPIServerEntity,
) -> Result<AuthorizationDecision, PolicyEvaluationError> {
Ok(AuthorizationDecision {
allowed: true,
determining_policies: vec!["noop_allow_all_scripts".to_string()],
errors: vec![],
})
}
#[cfg(feature = "sql-code-mode")]
async fn evaluate_statement(
&self,
_statement: &StatementEntity,
_server: &SqlServerEntity,
) -> Result<AuthorizationDecision, PolicyEvaluationError> {
Ok(AuthorizationDecision {
allowed: true,
determining_policies: vec!["noop_allow_all_statements".to_string()],
errors: vec![],
})
}
fn name(&self) -> &str {
"noop"
}
}
#[cfg(test)]
mod noop_tests {
use super::*;
#[tokio::test]
async fn noop_evaluator_allows_all_operations() {
let evaluator = NoopPolicyEvaluator::new();
let operation = OperationEntity {
id: "test-op".to_string(),
operation_type: "query".to_string(),
operation_name: "GetUsers".to_string(),
root_fields: ["users"].iter().map(|s| s.to_string()).collect(),
accessed_types: ["User"].iter().map(|s| s.to_string()).collect(),
accessed_fields: ["User.id", "User.name"]
.iter()
.map(|s| s.to_string())
.collect(),
depth: 2,
field_count: 2,
estimated_cost: 2,
has_introspection: false,
accesses_sensitive_data: false,
sensitive_categories: std::collections::HashSet::new(),
};
let config = ServerConfigEntity::default();
let result = evaluator
.evaluate_operation(&operation, &config)
.await
.unwrap();
assert!(result.allowed);
assert_eq!(result.determining_policies, vec!["noop_allow_all"]);
}
#[test]
fn noop_evaluator_name() {
let evaluator = NoopPolicyEvaluator::new();
assert_eq!(evaluator.name(), "noop");
}
#[test]
fn noop_evaluator_default() {
let evaluator = NoopPolicyEvaluator::default();
assert_eq!(evaluator.name(), "noop");
}
}