use super::{ExecOutput, Sandbox, SandboxError};
use async_trait::async_trait;
use std::process::Stdio;
use std::sync::Arc;
use tokio::process::Command;
#[derive(Default)]
pub struct HostSandbox;
impl HostSandbox {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl Sandbox for HostSandbox {
async fn open(self: Arc<Self>, _session_id: &str) -> Result<Arc<dyn Sandbox>, SandboxError> {
Ok(self)
}
async fn execute(&self, command: &str) -> Result<ExecOutput, SandboxError> {
let output = Command::new("bash")
.arg("-c")
.arg(command)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.await?;
Ok(ExecOutput {
stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
exit_code: output.status.code(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn execute_captures_stdout_and_exit_code() {
let sb = HostSandbox::new();
let out = sb.execute("echo hello").await.unwrap();
assert_eq!(out.stdout, "hello\n");
assert!(out.is_success());
}
#[tokio::test]
async fn execute_reports_nonzero_exit() {
let sb = HostSandbox::new();
let out = sb.execute("exit 3").await.unwrap();
assert_eq!(out.exit_code, Some(3));
assert!(!out.is_success());
}
}