a3s_code_core/permissions/mod.rs
1//! Permission system for tool execution control
2//!
3//! Implements a declarative permission system similar to Claude Code's permissions.
4//! Supports pattern matching with wildcards and three-tier evaluation:
5//! 1. Deny rules - checked first, any match = immediate denial
6//! 2. Allow rules - checked second, any match = auto-approval
7//! 3. Ask rules - checked third, forces confirmation prompt
8//! 4. Default behavior - falls back to HITL policy
9
10mod interactive;
11mod manager;
12mod policy;
13mod risk;
14mod rule;
15mod style_specialty;
16
17#[cfg(test)]
18mod tests;
19
20use serde::{Deserialize, Serialize};
21use std::sync::Arc;
22
23pub use crate::tool_name::canonical_tool_name;
24pub use interactive::{InteractiveApprovalMode, InteractiveToolGuardrail};
25pub use manager::{MatchingRules, PermissionManager};
26pub use policy::PermissionPolicy;
27pub use risk::{
28 EnvironmentSensitivity, ImpactScope, OperationTarget, Reversibility, ToolRiskAction,
29 ToolRiskAssessment, ToolRiskDimensions, ToolRiskLevel, ToolRiskReason, ToolRiskType,
30};
31pub use rule::PermissionRule;
32pub use style_specialty::specialty_permission_policy;
33
34/// Trait for checking tool execution permissions.
35///
36/// Implement this trait to provide custom permission logic.
37/// The built-in `PermissionPolicy` implements this trait using
38/// declarative allow/deny/ask rules with pattern matching.
39pub trait PermissionChecker: Send + Sync {
40 /// Freeze any mutable host policy for one agent run.
41 ///
42 /// Stateless checkers can keep the default and will be shared as-is.
43 /// Interactive hosts whose policy changes between turns should return an
44 /// immutable checker here so an in-flight or background child cannot gain
45 /// or lose authority when the next turn selects a different mode.
46 fn snapshot_for_run(&self) -> Option<Arc<dyn PermissionChecker>> {
47 None
48 }
49
50 /// Whether a tool definition should be exposed to the model.
51 ///
52 /// This controls model-visible capabilities only. [`Self::check`] remains
53 /// the authoritative execution-time decision for any tool invocation.
54 /// Existing checkers expose every tool unless they explicitly override
55 /// this method.
56 fn expose_to_model(&self, _tool_name: &str) -> bool {
57 true
58 }
59
60 /// Check whether a tool invocation is allowed, denied, or requires confirmation.
61 fn check(&self, tool_name: &str, args: &serde_json::Value) -> PermissionDecision;
62}
63
64/// Permission decision result
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "snake_case")]
67pub enum PermissionDecision {
68 /// Automatically allow without user confirmation
69 Allow,
70 /// Deny execution
71 Deny,
72 /// Ask user for confirmation
73 Ask,
74}