Skip to main content

synwire_core/sandbox/
approval.rs

1//! Approval gates for risky operations.
2
3use crate::BoxFuture;
4use serde::{Deserialize, Serialize};
5
6/// Risk classification for an operation.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
8#[non_exhaustive]
9pub enum RiskLevel {
10    /// No meaningful risk (read-only).
11    None,
12    /// Low risk (reversible writes).
13    Low,
14    /// Medium risk (file deletions, overwrites).
15    Medium,
16    /// High risk (system changes, process spawning).
17    High,
18    /// Critical risk (irreversible, destructive).
19    Critical,
20}
21
22/// Request for human or automated approval.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ApprovalRequest {
25    /// Operation identifier.
26    pub operation: String,
27    /// Human-readable description of what will happen.
28    pub description: String,
29    /// Risk classification.
30    pub risk: RiskLevel,
31    /// Optional timeout in seconds (None = no timeout).
32    pub timeout_secs: Option<u64>,
33    /// Arguments or context for the operation.
34    pub context: serde_json::Value,
35}
36
37/// Decision returned by an approval gate.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39#[non_exhaustive]
40pub enum ApprovalDecision {
41    /// Allow this invocation.
42    Allow,
43    /// Deny this invocation.
44    Deny,
45    /// Allow this invocation and all future invocations of the same operation.
46    AllowAlways,
47    /// Abort the entire agent run.
48    Abort,
49    /// Allow but with modified input.
50    AllowModified {
51        /// Modified context to use instead.
52        modified_context: serde_json::Value,
53    },
54}
55
56/// Trait for approval gate callbacks.
57///
58/// Implementors decide whether a risky operation should proceed.
59pub trait ApprovalCallback: Send + Sync {
60    /// Evaluate an approval request and return a decision.
61    fn request(&self, req: ApprovalRequest) -> BoxFuture<'_, ApprovalDecision>;
62}
63
64/// Approval callback that auto-approves everything.
65#[derive(Debug, Clone, Default)]
66pub struct AutoApproveCallback;
67
68impl ApprovalCallback for AutoApproveCallback {
69    fn request(&self, _req: ApprovalRequest) -> BoxFuture<'_, ApprovalDecision> {
70        Box::pin(async { ApprovalDecision::Allow })
71    }
72}
73
74/// Approval callback that auto-denies everything.
75#[derive(Debug, Clone, Default)]
76pub struct AutoDenyCallback;
77
78impl ApprovalCallback for AutoDenyCallback {
79    fn request(&self, _req: ApprovalRequest) -> BoxFuture<'_, ApprovalDecision> {
80        Box::pin(async { ApprovalDecision::Deny })
81    }
82}