zeroclaw/src/security/docker.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

120 lines
2.7 KiB
Rust

//! Docker sandbox (container isolation)
use crate::security::traits::Sandbox;
use std::process::Command;
/// Docker sandbox backend
#[derive(Debug, Clone)]
pub struct DockerSandbox {
image: String,
}
impl Default for DockerSandbox {
fn default() -> Self {
Self {
image: "alpine:latest".to_string(),
}
}
}
impl DockerSandbox {
pub fn new() -> std::io::Result<Self> {
if Self::is_installed() {
Ok(Self::default())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Docker not found",
))
}
}
pub fn with_image(image: String) -> std::io::Result<Self> {
if Self::is_installed() {
Ok(Self { image })
} else {
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Docker not found",
))
}
}
pub fn probe() -> std::io::Result<Self> {
Self::new()
}
fn is_installed() -> bool {
Command::new("docker")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}
}
impl Sandbox for DockerSandbox {
fn wrap_command(&self, cmd: &mut Command) -> std::io::Result<()> {
let program = cmd.get_program().to_string_lossy().to_string();
let args: Vec<String> = cmd
.get_args()
.map(|s| s.to_string_lossy().to_string())
.collect();
let mut docker_cmd = Command::new("docker");
docker_cmd.args([
"run",
"--rm",
"--memory",
"512m",
"--cpus",
"1.0",
"--network",
"none",
]);
docker_cmd.arg(&self.image);
docker_cmd.arg(&program);
docker_cmd.args(&args);
*cmd = docker_cmd;
Ok(())
}
fn is_available(&self) -> bool {
Self::is_installed()
}
fn name(&self) -> &str {
"docker"
}
fn description(&self) -> &str {
"Docker container isolation (requires docker)"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn docker_sandbox_name() {
let sandbox = DockerSandbox::default();
assert_eq!(sandbox.name(), "docker");
}
#[test]
fn docker_sandbox_default_image() {
let sandbox = DockerSandbox::default();
assert_eq!(sandbox.image, "alpine:latest");
}
#[test]
fn docker_with_custom_image() {
let result = DockerSandbox::with_image("ubuntu:latest".to_string());
match result {
Ok(sandbox) => assert_eq!(sandbox.image, "ubuntu:latest"),
Err(_) => assert!(!DockerSandbox::is_installed()),
}
}
}