Files
agent-sandbox/tests/e2e/namespaces.rs
T
mrtoth 6e81866226 Default to whitelist mode and parallelize tests
Flips the default sandbox mode from blacklist to whitelist and
replaces the global RUST_TEST_THREADS=1 with a targeted RwLock
that only serializes blacklist sandboxes against tests mutating
glob-matching host paths. A new Sandbox newtype acquires the
guard automatically when --blacklist is in args.
2026-04-27 08:18:41 +02:00

118 lines
3.3 KiB
Rust

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::new(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::new(&["--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::new(&["--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::new(&["--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::new(&["--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 blacklist_mode_shares_session() {
let inner_sid = read_sid_inside_sandbox(&["--blacklist"]);
let outer_sid = read_sid_current_process();
assert_eq!(
inner_sid, outer_sid,
"blacklist-mode sandbox should share the session ID (got {inner_sid} != {outer_sid})"
);
}