zeroclaw/src/security/traits.rs
Chummy 9d29f30a31
fix(channels): execute tool calls in channel runtime (#302)
* fix(channels): execute tool calls in channel runtime (#302)

* chore(fmt): align repo formatting with rustfmt 1.92
2026-02-16 05:07:01 -05:00

81 lines
2 KiB
Rust

//! Sandbox trait for pluggable OS-level isolation
use async_trait::async_trait;
use std::process::Command;
/// Sandbox backend for OS-level isolation
#[async_trait]
pub trait Sandbox: Send + Sync {
/// Wrap a command with sandbox protection
fn wrap_command(&self, cmd: &mut Command) -> std::io::Result<()>;
/// Check if this sandbox backend is available on the current platform
fn is_available(&self) -> bool;
/// Human-readable name of this sandbox backend
fn name(&self) -> &str;
/// Description of what this sandbox provides
fn description(&self) -> &str;
}
/// No-op sandbox (always available, provides no additional isolation)
#[derive(Debug, Clone, Default)]
pub struct NoopSandbox;
impl Sandbox for NoopSandbox {
fn wrap_command(&self, _cmd: &mut Command) -> std::io::Result<()> {
// Pass through unchanged
Ok(())
}
fn is_available(&self) -> bool {
true
}
fn name(&self) -> &str {
"none"
}
fn description(&self) -> &str {
"No sandboxing (application-layer security only)"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn noop_sandbox_name() {
assert_eq!(NoopSandbox.name(), "none");
}
#[test]
fn noop_sandbox_is_always_available() {
assert!(NoopSandbox.is_available());
}
#[test]
fn noop_sandbox_wrap_command_is_noop() {
let mut cmd = Command::new("echo");
cmd.arg("test");
let original_program = cmd.get_program().to_string_lossy().to_string();
let original_args: Vec<String> = cmd
.get_args()
.map(|s| s.to_string_lossy().to_string())
.collect();
let sandbox = NoopSandbox;
assert!(sandbox.wrap_command(&mut cmd).is_ok());
// Command should be unchanged
assert_eq!(cmd.get_program().to_string_lossy(), original_program);
assert_eq!(
cmd.get_args()
.map(|s| s.to_string_lossy().to_string())
.collect::<Vec<_>>(),
original_args
);
}
}