Skip to main content

adk_sandbox/
backend.rs

1//! The [`SandboxBackend`] trait and [`BackendCapabilities`] descriptor.
2
3use async_trait::async_trait;
4
5use crate::error::SandboxError;
6use crate::types::{ExecRequest, ExecResult, Language};
7
8/// Async trait for isolated code execution backends.
9///
10/// Implementations provide a single `execute()` method that runs code in
11/// isolation and returns the result. The trait is intentionally minimal —
12/// no lifecycle methods (start/stop/restart). `ProcessBackend` is stateless
13/// and `WasmBackend` creates a fresh instance per call.
14///
15/// # Example
16///
17/// ```rust,ignore
18/// use adk_sandbox::{SandboxBackend, ExecRequest, ExecResult, SandboxError};
19///
20/// struct MyBackend;
21///
22/// #[async_trait::async_trait]
23/// impl SandboxBackend for MyBackend {
24///     fn name(&self) -> &str { "my-backend" }
25///     fn capabilities(&self) -> BackendCapabilities { /* ... */ }
26///     async fn execute(&self, request: ExecRequest) -> Result<ExecResult, SandboxError> {
27///         // Execute code in isolation
28///         todo!()
29///     }
30/// }
31/// ```
32#[async_trait]
33pub trait SandboxBackend: Send + Sync {
34    /// Returns the backend name (e.g., `"process"`, `"wasm"`).
35    fn name(&self) -> &str;
36
37    /// Returns the capabilities and enforced limits of this backend.
38    fn capabilities(&self) -> BackendCapabilities;
39
40    /// Executes code in isolation according to the request parameters.
41    ///
42    /// # Errors
43    ///
44    /// Returns [`SandboxError`] if execution cannot complete (timeout,
45    /// memory exceeded, invalid request, etc.). A non-zero exit code
46    /// is **not** an error — it is returned in [`ExecResult::exit_code`].
47    async fn execute(&self, request: ExecRequest) -> Result<ExecResult, SandboxError>;
48}
49
50/// Describes what a backend supports and enforces.
51///
52/// Callers can inspect capabilities to choose the right backend or to
53/// understand what isolation guarantees are provided.
54///
55/// # Example
56///
57/// ```rust
58/// use adk_sandbox::{BackendCapabilities, EnforcedLimits, Language};
59///
60/// let caps = BackendCapabilities {
61///     supported_languages: vec![Language::Python, Language::JavaScript],
62///     isolation_class: "process".to_string(),
63///     enforced_limits: EnforcedLimits {
64///         timeout: true,
65///         memory: false,
66///         network_isolation: false,
67///         filesystem_isolation: false,
68///         environment_isolation: true,
69///     },
70/// };
71/// assert!(caps.enforced_limits.timeout);
72/// ```
73#[derive(Debug, Clone)]
74pub struct BackendCapabilities {
75    /// Languages this backend can execute.
76    pub supported_languages: Vec<Language>,
77    /// Isolation class identifier (e.g., `"process"`, `"wasm"`, `"container"`).
78    pub isolation_class: String,
79    /// Which resource limits the backend actually enforces.
80    pub enforced_limits: EnforcedLimits,
81}
82
83/// Describes which resource limits a backend enforces.
84///
85/// Backends are honest about what they enforce. For example,
86/// `ProcessBackend` enforces timeout and environment isolation
87/// but not memory or network isolation.
88#[derive(Debug, Clone)]
89pub struct EnforcedLimits {
90    /// Whether the backend enforces execution timeout.
91    pub timeout: bool,
92    /// Whether the backend enforces memory limits.
93    pub memory: bool,
94    /// Whether the backend isolates network access.
95    pub network_isolation: bool,
96    /// Whether the backend isolates filesystem access.
97    pub filesystem_isolation: bool,
98    /// Whether the backend isolates environment variables.
99    pub environment_isolation: bool,
100}