Initial commit
This commit is contained in:
220
tests/integration.rs
Normal file
220
tests/integration.rs
Normal file
@@ -0,0 +1,220 @@
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn sandbox(extra_args: &[&str]) -> Command {
|
||||
let mut cmd = Command::new(env!("CARGO_BIN_EXE_agent-sandbox"));
|
||||
cmd.args(extra_args);
|
||||
cmd
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cwd_is_writable() {
|
||||
let output = sandbox(&[])
|
||||
.args(["--", "bash", "-c", "touch ./sandbox_canary && echo ok"])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(
|
||||
stdout.contains("ok"),
|
||||
"expected 'ok' in stdout, got: {stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_fs_is_readonly() {
|
||||
let output = sandbox(&[])
|
||||
.args(["--", "bash", "-c", "touch /etc/pwned 2>&1 || echo readonly"])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(
|
||||
stdout.contains("readonly"),
|
||||
"expected 'readonly' in stdout, got: {stdout}"
|
||||
);
|
||||
assert!(!std::path::Path::new("/etc/pwned").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssh_dir_is_hidden() {
|
||||
let output = sandbox(&[])
|
||||
.args(["--", "bash", "-c", "ls ~/.ssh 2>/dev/null | wc -l"])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
assert_eq!(stdout, "0", "expected empty ~/.ssh, got {stdout} entries");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_net_blocks_network() {
|
||||
let output = sandbox(&["--no-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 whitelist_hides_home_contents() {
|
||||
let output = sandbox(&["--whitelist"])
|
||||
.args(["--", "bash", "-c", "ls ~/Documents 2>&1 || echo hidden"])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(
|
||||
stdout.contains("hidden"),
|
||||
"expected ~/Documents to be hidden, got: {stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extra_ro_mount() {
|
||||
let dir = TempDir::new().expect("failed to create temp dir");
|
||||
fs::write(dir.path().join("hello.txt"), "hi").expect("failed to write test file");
|
||||
let dir_str = dir.path().to_str().unwrap();
|
||||
|
||||
let output = sandbox(&["--ro", dir_str])
|
||||
.args([
|
||||
"--",
|
||||
"bash",
|
||||
"-c",
|
||||
&format!("cat {dir_str}/hello.txt && touch {dir_str}/new 2>&1 || echo readonly"),
|
||||
])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(
|
||||
stdout.contains("hi"),
|
||||
"expected file content 'hi', got: {stdout}"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("readonly"),
|
||||
"expected ro mount to block writes, got: {stdout}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extra_rw_mount() {
|
||||
let dir = TempDir::new().expect("failed to create temp dir");
|
||||
let dir_str = dir.path().to_str().unwrap();
|
||||
|
||||
let output = sandbox(&["--rw", dir_str])
|
||||
.args([
|
||||
"--",
|
||||
"bash",
|
||||
"-c",
|
||||
&format!("touch {dir_str}/canary && echo ok"),
|
||||
])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(stdout.contains("ok"), "expected 'ok', got: {stdout}");
|
||||
assert!(
|
||||
dir.path().join("canary").exists(),
|
||||
"canary file should exist on host after rw mount"
|
||||
);
|
||||
}
|
||||
|
||||
#[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 dry_run_prints_and_exits() {
|
||||
let output = sandbox(&["--dry-run"])
|
||||
.args(["--", "bash", "-c", "exit 42"])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(
|
||||
stdout.contains("bwrap"),
|
||||
"expected bwrap command in dry-run output, got: {stdout}"
|
||||
);
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"dry-run should exit 0, not 42 from the inner command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rw_missing_path_errors() {
|
||||
let output = sandbox(&["--rw", "/nonexistent/xyz"])
|
||||
.args(["--", "true"])
|
||||
.output()
|
||||
.expect("agent-sandbox binary failed to execute");
|
||||
|
||||
assert!(
|
||||
!output.status.success(),
|
||||
"expected non-zero exit for missing --rw path"
|
||||
);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert!(
|
||||
stderr.contains("/nonexistent/xyz"),
|
||||
"expected path in error message, got: {stderr}"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user