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}