use std::fs; use tempfile::TempDir; use crate::common::*; fn read_sid_from_stat(stat: &str) -> u32 { stat.split_whitespace() .nth(5) .expect("missing field 6 in /proc/self/stat") .parse() .expect("failed to parse session ID") } fn read_sid_inside_sandbox(extra_args: &[&str]) -> u32 { let output = sandbox(extra_args) .args(["--", "bash", "-c", "cat /proc/self/stat"]) .output() .expect("agent-sandbox binary failed to execute"); read_sid_from_stat(&String::from_utf8_lossy(&output.stdout)) } fn read_sid_current_process() -> u32 { let stat = fs::read_to_string("/proc/self/stat").expect("failed to read /proc/self/stat"); read_sid_from_stat(&stat) } #[test] fn unshare_net_blocks_network() { let output = sandbox(&["--unshare-net"]) .args([ "--", "bash", "-c", "curl -s --max-time 2 http://1.1.1.1 2>&1; echo $?", ]) .output() .expect("agent-sandbox binary failed to execute"); let stdout = String::from_utf8_lossy(&output.stdout); assert!( !stdout.trim().ends_with("0"), "expected curl to fail, got: {stdout}" ); } #[test] fn hardened_pid_namespace() { let output = sandbox(&["--hardened"]) .args(["--", "bash", "-c", "ls /proc | grep -cE '^[0-9]+$'"]) .output() .expect("agent-sandbox binary failed to execute"); let count: u32 = String::from_utf8_lossy(&output.stdout) .trim() .parse() .unwrap_or(999); assert!( count < 10, "expected isolated PID namespace with few PIDs, got {count}" ); } #[test] fn chdir_override() { let dir = TempDir::new().expect("failed to create temp dir"); let dir_str = dir.path().to_str().unwrap(); let output = sandbox(&["--chdir", dir_str]) .args(["--", "bash", "-c", "pwd"]) .output() .expect("agent-sandbox binary failed to execute"); let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string(); assert_eq!( stdout, dir_str, "expected cwd to be {dir_str}, got: {stdout}" ); } #[test] fn chdir_under_hardened_tmp() { let dir = TempDir::new().expect("failed to create temp dir"); let dir_str = dir.path().to_str().unwrap(); let output = sandbox(&["--hardened", "--chdir", dir_str]) .args(["--", "bash", "-c", "pwd && touch ./ok && echo done"]) .output() .expect("agent-sandbox binary failed to execute"); let stdout = String::from_utf8_lossy(&output.stdout); assert!( stdout.contains("done"), "expected chdir under /tmp to work with --hardened, got: {stdout}" ); } #[test] fn hardened_isolates_sid() { let inner_sid = read_sid_inside_sandbox(&["--hardened"]); let outer_sid = read_sid_current_process(); assert_ne!( inner_sid, outer_sid, "sandboxed process should have a different session ID (got {inner_sid} == {outer_sid})" ); } #[test] fn default_mode_shares_session() { let inner_sid = read_sid_inside_sandbox(&[]); let outer_sid = read_sid_current_process(); assert_eq!( inner_sid, outer_sid, "default-mode sandbox should share the session ID (got {inner_sid} != {outer_sid})" ); }