Skip to main content

sparrow/tools/
code_exec.rs

1//! Code execution in sandbox — runs code with timeout.
2
3use std::process::Command;
4
5pub fn execute_code(code: &str, language: &str, timeout_secs: u64) -> anyhow::Result<ExecResult> {
6    let tmpdir = std::env::temp_dir().join("sparrow_exec");
7    std::fs::create_dir_all(&tmpdir)?;
8
9    let (ext, runner, args): (&str, &str, Vec<&str>) = match language {
10        "python" | "py" => ("py", "python3", vec![]),
11        "javascript" | "js" => ("js", "node", vec![]),
12        "bash" | "sh" => ("sh", "bash", vec![]),
13        "ruby" | "rb" => ("rb", "ruby", vec![]),
14        _ => anyhow::bail!("Unsupported: {language}. Use python, js, bash, or ruby."),
15    };
16
17    let file = tmpdir.join(format!("code_{}.{}", uuid::Uuid::new_v4(), ext));
18    std::fs::write(&file, code)?;
19
20    let output = Command::new("timeout")
21        .arg(timeout_secs.to_string())
22        .arg(runner)
23        .args(&args)
24        .arg(&file)
25        .output()?;
26
27    Ok(ExecResult {
28        success: output.status.success(),
29        stdout: String::from_utf8_lossy(&output.stdout).to_string(),
30        stderr: String::from_utf8_lossy(&output.stderr).to_string(),
31        exit_code: output.status.code().unwrap_or(-1),
32        language: language.to_string(),
33    })
34}
35
36#[derive(Debug, Clone, serde::Serialize)]
37pub struct ExecResult {
38    pub success: bool,
39    pub stdout: String,
40    pub stderr: String,
41    pub exit_code: i32,
42    pub language: String,
43}