Skip to main content

tiny_agent/sandbox/
host.rs

1use super::{ExecOutput, Sandbox, SandboxError};
2use async_trait::async_trait;
3use std::process::Stdio;
4use std::sync::Arc;
5use tokio::process::Command;
6
7/// 直接在宿主机上执行命令、读写真实文件系统的 sandbox。
8///
9/// 这是默认实现,行为等价于"不沙箱",不提供任何隔离。
10#[derive(Default)]
11pub struct HostSandbox;
12
13impl HostSandbox {
14    pub fn new() -> Self {
15        Self
16    }
17}
18
19#[async_trait]
20impl Sandbox for HostSandbox {
21    async fn open(self: Arc<Self>, _session_id: &str) -> Result<Arc<dyn Sandbox>, SandboxError> {
22        Ok(self)
23    }
24
25    async fn execute(&self, command: &str) -> Result<ExecOutput, SandboxError> {
26        let output = Command::new("bash")
27            .arg("-c")
28            .arg(command)
29            .stdin(Stdio::null())
30            .stdout(Stdio::piped())
31            .stderr(Stdio::piped())
32            .output()
33            .await?;
34        Ok(ExecOutput {
35            stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
36            stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
37            exit_code: output.status.code(),
38        })
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[tokio::test]
47    async fn execute_captures_stdout_and_exit_code() {
48        let sb = HostSandbox::new();
49        let out = sb.execute("echo hello").await.unwrap();
50        assert_eq!(out.stdout, "hello\n");
51        assert!(out.is_success());
52    }
53
54    #[tokio::test]
55    async fn execute_reports_nonzero_exit() {
56        let sb = HostSandbox::new();
57        let out = sb.execute("exit 3").await.unwrap();
58        assert_eq!(out.exit_code, Some(3));
59        assert!(!out.is_success());
60    }
61}