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.
This commit is contained in:
2026-04-27 08:18:41 +02:00
parent c77dbc10c3
commit 6e81866226
12 changed files with 158 additions and 81 deletions
+14 -14
View File
@@ -2,7 +2,7 @@ use crate::common::*;
#[test]
fn dry_run_prints_and_exits() {
let output = sandbox(&["--dry-run"])
let output = Sandbox::new(&["--dry-run"])
.args(["--", "bash", "-c", "exit 42"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -20,7 +20,7 @@ fn dry_run_prints_and_exits() {
#[test]
fn dry_run_output_is_copy_pasteable_shell() {
let dry = sandbox(&["--dry-run"])
let dry = Sandbox::new(&["--dry-run"])
.args(["--", "bash", "-c", "echo $HOME"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -34,7 +34,7 @@ fn dry_run_output_is_copy_pasteable_shell() {
#[test]
fn empty_home_rejected() {
let output = sandbox(&[])
let output = Sandbox::new(&[])
.env("HOME", "")
.args(["--", "true"])
.output()
@@ -53,7 +53,7 @@ fn empty_home_rejected() {
#[test]
fn config_missing_file_errors() {
let output = sandbox_withconfig(&["--config", "/nonexistent/config.toml"])
let output = Sandbox::new_with_config(&["--config", "/nonexistent/config.toml"])
.args(["--", "true"])
.output()
.expect("failed to execute");
@@ -70,7 +70,7 @@ fn config_missing_file_errors() {
fn config_invalid_toml_errors() {
let cfg = ConfigFile::new("not valid {{{{ toml");
let output = sandbox_withconfig(&["--config", &cfg])
let output = Sandbox::new_with_config(&["--config", &cfg])
.args(["--", "true"])
.output()
.expect("failed to execute");
@@ -87,7 +87,7 @@ fn config_invalid_toml_errors() {
fn config_unknown_key_errors() {
let cfg = ConfigFile::new("hardened = true\nbogus = \"nope\"\n");
let output = sandbox_withconfig(&["--config", &cfg])
let output = Sandbox::new_with_config(&["--config", &cfg])
.args(["--", "true"])
.output()
.expect("failed to execute");
@@ -102,7 +102,7 @@ fn config_unknown_key_errors() {
#[test]
fn bwrap_arg_setenv_passes_through() {
let output = sandbox(&["--bwrap-arg", "--setenv MYVAR hello"])
let output = Sandbox::new(&["--bwrap-arg", "--setenv MYVAR hello"])
.args(["--", "bash", "-c", "echo $MYVAR"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -123,7 +123,7 @@ fn config_entrypoint_appends_passthrough_args() {
"#,
);
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
let output = Sandbox::new_with_config(&["--config", &cfg, "--profile", "test"])
.args(["--", "echo entrypoint-works"])
.output()
.expect("failed to execute");
@@ -145,7 +145,7 @@ fn config_entrypoint_falls_back_to_command_defaults() {
"#,
);
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
let output = Sandbox::new_with_config(&["--config", &cfg, "--profile", "test"])
.output()
.expect("failed to execute");
@@ -165,7 +165,7 @@ fn config_entrypoint_alone_without_command_or_passthrough() {
"#,
);
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
let output = Sandbox::new_with_config(&["--config", &cfg, "--profile", "test"])
.output()
.expect("failed to execute");
@@ -178,7 +178,7 @@ fn config_entrypoint_alone_without_command_or_passthrough() {
#[test]
fn cli_entrypoint_appends_passthrough_args() {
let output = sandbox(&["--entrypoint", "bash"])
let output = Sandbox::new(&["--entrypoint", "bash"])
.args(["--", "-c", "echo cli-entrypoint-works"])
.output()
.expect("failed to execute");
@@ -198,7 +198,7 @@ fn cli_entrypoint_overrides_config_entrypoint() {
"#,
);
let output = sandbox_withconfig(&["--config", &cfg, "--entrypoint", "bash"])
let output = Sandbox::new_with_config(&["--config", &cfg, "--entrypoint", "bash"])
.args(["--", "-c", "echo override-works"])
.output()
.expect("failed to execute");
@@ -219,7 +219,7 @@ fn config_command_alone_without_passthrough() {
"#,
);
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
let output = Sandbox::new_with_config(&["--config", &cfg, "--profile", "test"])
.output()
.expect("failed to execute");
@@ -239,7 +239,7 @@ fn config_command_replaced_by_passthrough() {
"#,
);
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
let output = Sandbox::new_with_config(&["--config", &cfg, "--profile", "test"])
.args(["--", "bash", "-c", "echo replaced"])
.output()
.expect("failed to execute");
+77 -8
View File
@@ -1,18 +1,87 @@
use std::fs;
use std::ops::{Deref, DerefMut};
use std::process::Command;
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use tempfile::TempDir;
pub fn sandbox_withconfig(extra_args: &[&str]) -> Command {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_agent-sandbox"));
cmd.args(extra_args);
cmd
// Blacklist mode globs the host filesystem at sandbox startup to find
// sensitive paths to mask. A matching host file that vanishes mid-startup
// makes bwrap fail in any concurrent blacklist sandbox.
pub struct HostGlobsLock;
impl HostGlobsLock {
/// Acquire shared access. Hold while running a blacklist sandbox.
pub fn for_scan() -> RwLockReadGuard<'static, ()> {
LOCK.read().unwrap()
}
/// Acquire exclusive access. Hold while creating or deleting a host
/// path that may match a blacklist glob (e.g. `/tmp/ssh-*`).
pub fn for_mutation() -> RwLockWriteGuard<'static, ()> {
LOCK.write().unwrap()
}
}
pub fn sandbox(extra_args: &[&str]) -> Command {
let mut cmd = sandbox_withconfig(&["--no-config"]);
cmd.args(extra_args);
cmd
static LOCK: RwLock<()> = RwLock::new(());
#[allow(dead_code)]
enum HostGlobsGuard {
Scan(RwLockReadGuard<'static, ()>),
Mutation(RwLockWriteGuard<'static, ()>),
}
pub struct Sandbox {
cmd: Command,
_guard: Option<HostGlobsGuard>,
}
impl Sandbox {
pub fn new(extra_args: &[&str]) -> Self {
Self::build(&["--no-config"], extra_args, scan_guard_for(extra_args))
}
pub fn new_with_config(extra_args: &[&str]) -> Self {
Self::build(&[], extra_args, scan_guard_for(extra_args))
}
pub fn new_for_host_mutation(extra_args: &[&str]) -> Self {
debug_assert!(
extra_args.contains(&"--blacklist"),
"new_for_host_mutation is only meaningful for blacklist sandboxes"
);
Self::build(
&["--no-config"],
extra_args,
Some(HostGlobsGuard::Mutation(HostGlobsLock::for_mutation())),
)
}
fn build(prefix: &[&str], extra_args: &[&str], guard: Option<HostGlobsGuard>) -> Self {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_agent-sandbox"));
cmd.args(prefix);
cmd.args(extra_args);
Self { cmd, _guard: guard }
}
}
fn scan_guard_for(extra_args: &[&str]) -> Option<HostGlobsGuard> {
extra_args
.contains(&"--blacklist")
.then(|| HostGlobsGuard::Scan(HostGlobsLock::for_scan()))
}
impl Deref for Sandbox {
type Target = Command;
fn deref(&self) -> &Command {
&self.cmd
}
}
impl DerefMut for Sandbox {
fn deref_mut(&mut self) -> &mut Command {
&mut self.cmd
}
}
pub struct ConfigFile {
+16 -8
View File
@@ -6,7 +6,7 @@ fn printenv_inside(args: &[&str], vars: &[(&str, &str)], query: &[&str]) -> Stri
.map(|v| format!("printenv {v} || echo MISSING:{v}"))
.collect::<Vec<_>>()
.join("; ");
let mut cmd = sandbox(args);
let mut cmd = Sandbox::new(args);
for (k, v) in vars {
cmd.env(k, v);
}
@@ -219,7 +219,7 @@ fn whitelist_unsetenv_overrides_kept_var() {
#[test]
fn blacklist_drops_token_and_secret_vars() {
let stdout = printenv_inside(
&[],
&["--blacklist"],
&[
("GH_TOKEN", "gh-secret"),
("AWS_SECRET_ACCESS_KEY", "aws-secret"),
@@ -252,7 +252,7 @@ fn blacklist_drops_token_and_secret_vars() {
#[test]
fn blacklist_carves_out_vendor_api_keys() {
let stdout = printenv_inside(
&[],
&["--blacklist"],
&[
("ANTHROPIC_API_KEY", "anthropic-key"),
("OPENAI_API_KEY", "openai-key"),
@@ -272,7 +272,7 @@ fn blacklist_carves_out_vendor_api_keys() {
#[test]
fn blacklist_suffix_match_does_not_catch_substring() {
let stdout = printenv_inside(
&[],
&["--blacklist"],
&[
("TOKENIZER_PATH", "/opt/tok"),
("MY_TOKEN_HOLDER", "holder"),
@@ -291,14 +291,18 @@ fn blacklist_suffix_match_does_not_catch_substring() {
#[test]
fn blacklist_keeps_unrelated_host_var() {
let stdout = printenv_inside(&[], &[("MY_NICE_VAR", "hello")], &["MY_NICE_VAR"]);
let stdout = printenv_inside(
&["--blacklist"],
&[("MY_NICE_VAR", "hello")],
&["MY_NICE_VAR"],
);
assert!(stdout.contains("hello"), "MY_NICE_VAR stripped: {stdout}");
}
#[test]
fn blacklist_keeps_dbus_vars() {
let stdout = printenv_inside(
&[],
&["--blacklist"],
&[
("DBUS_SESSION_BUS_ADDRESS", "unix:path=/tmp/fake"),
("DBUS_SYSTEM_BUS_ADDRESS", "unix:path=/tmp/fake-system"),
@@ -324,7 +328,11 @@ fn no_env_filter_whitelist_keeps_arbitrary_host_var() {
#[test]
fn no_env_filter_blacklist_keeps_secrets() {
let stdout = printenv_inside(&["--no-env-filter"], &[("GH_TOKEN", "kept")], &["GH_TOKEN"]);
let stdout = printenv_inside(
&["--blacklist", "--no-env-filter"],
&[("GH_TOKEN", "kept")],
&["GH_TOKEN"],
);
assert!(
stdout.contains("kept"),
"expected --no-env-filter to pass secrets through, got: {stdout}"
@@ -347,7 +355,7 @@ fn no_env_filter_still_honors_user_env() {
#[test]
fn blacklist_env_overrides_builtin_deny() {
let stdout = printenv_inside(
&["--env", "GH_TOKEN=overridden"],
&["--blacklist", "--env", "GH_TOKEN=overridden"],
&[("GH_TOKEN", "original")],
&["GH_TOKEN"],
);
+10 -10
View File
@@ -2,7 +2,7 @@ use crate::common::*;
#[test]
fn whitelist_hides_home_contents() {
let output = sandbox(&["--whitelist"])
let output = Sandbox::new(&["--whitelist"])
.args(["--", "bash", "-c", "ls ~/Documents 2>&1 || echo hidden"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -16,7 +16,7 @@ fn whitelist_hides_home_contents() {
#[test]
fn whitelist_sys_is_readable() {
let output = sandbox(&["--whitelist"])
let output = Sandbox::new(&["--whitelist"])
.args(["--", "bash", "-c", "cat /sys/class/net/lo/address"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -30,7 +30,7 @@ fn whitelist_sys_is_readable() {
#[test]
fn blacklist_run_is_tmpfs() {
let output = sandbox(&[])
let output = Sandbox::new(&["--blacklist"])
.args([
"--",
"bash",
@@ -49,7 +49,7 @@ fn blacklist_run_is_tmpfs() {
#[test]
fn blacklist_run_dbus_socket_accessible() {
let output = sandbox(&[])
let output = Sandbox::new(&["--blacklist"])
.args([
"--",
"bash",
@@ -71,7 +71,7 @@ fn blacklist_runuser_is_tmpfs() {
let run_user = agent_sandbox::require_run_user().expect("failed to determine XDG_RUNTIME_DIR");
let script = format!("ls -A {} | grep -v '^bus$'", run_user);
let output = sandbox(&[])
let output = Sandbox::new(&["--blacklist"])
.args(["--", "bash", "-c", &script])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -86,7 +86,7 @@ fn blacklist_runuser_is_tmpfs() {
#[test]
fn blacklist_dev_input_hidden() {
let output = sandbox(&[])
let output = Sandbox::new(&["--blacklist"])
.args(["--", "bash", "-c", "ls /dev/input/ 2>/dev/null | wc -l"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -100,7 +100,7 @@ fn blacklist_dev_input_hidden() {
#[test]
fn blacklist_root_is_readonly() {
let output = sandbox(&[])
let output = Sandbox::new(&["--blacklist"])
.args([
"--",
"bash",
@@ -124,7 +124,7 @@ fn blacklist_root_is_readonly() {
#[test]
fn whitelist_root_is_readonly() {
let output = sandbox(&["--whitelist"])
let output = Sandbox::new(&["--whitelist"])
.args([
"--",
"bash",
@@ -148,7 +148,7 @@ fn whitelist_root_is_readonly() {
#[test]
fn whitelist_mountpoint_parents_are_readonly() {
let output = sandbox(&["--whitelist"])
let output = Sandbox::new(&["--whitelist"])
.args([
"--",
"bash",
@@ -177,7 +177,7 @@ fn whitelist_mountpoint_parents_are_readonly() {
#[test]
fn whitelist_tmp_still_writable() {
let output = sandbox(&["--whitelist"])
let output = Sandbox::new(&["--whitelist"])
.args([
"--",
"bash",
+20 -18
View File
@@ -16,7 +16,7 @@ impl Drop for CleanupFile {
fn cwd_is_writable() {
let _cleanup = CleanupFile("./sandbox_canary");
let output = sandbox(&[])
let output = Sandbox::new(&[])
.args(["--", "bash", "-c", "touch ./sandbox_canary && echo ok"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -30,7 +30,7 @@ fn cwd_is_writable() {
#[test]
fn host_fs_is_readonly() {
let output = sandbox(&[])
let output = Sandbox::new(&[])
.args(["--", "bash", "-c", "touch /etc/pwned 2>&1 || echo readonly"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -45,7 +45,7 @@ fn host_fs_is_readonly() {
#[test]
fn ssh_dir_is_hidden() {
let output = sandbox(&[])
let output = Sandbox::new(&[])
.args(["--", "bash", "-c", "ls ~/.ssh 2>/dev/null | wc -l"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -60,7 +60,7 @@ fn extra_ro_mount() {
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])
let output = Sandbox::new(&["--ro", dir_str])
.args([
"--",
"bash",
@@ -86,7 +86,7 @@ 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])
let output = Sandbox::new(&["--rw", dir_str])
.args([
"--",
"bash",
@@ -111,7 +111,7 @@ fn ro_mount_with_remapped_target() {
let src_str = dir.path().to_str().unwrap();
let target = "/tmp/agent-sandbox-remap-test";
let output = sandbox(&["--ro", &format!("{src_str}:{target}")])
let output = Sandbox::new(&["--ro", &format!("{src_str}:{target}")])
.args([
"--",
"bash",
@@ -138,7 +138,7 @@ fn rw_refines_ro_parent() {
let parent_str = parent.path().to_str().unwrap();
let child_str = child.to_str().unwrap();
let output = sandbox(&["--ro", parent_str, "--rw", child_str])
let output = Sandbox::new(&["--ro", parent_str, "--rw", child_str])
.args([
"--",
"bash",
@@ -164,10 +164,11 @@ fn rw_refines_ro_parent() {
#[test]
fn blacklist_overlays_survive_tmp_bind() {
let mut sandbox = Sandbox::new_for_host_mutation(&["--blacklist"]);
fs::write("/tmp/ssh-sandbox-test", "secret").expect("failed to write sentinel");
let _cleanup = CleanupFile("/tmp/ssh-sandbox-test");
let output = sandbox(&[])
let output = sandbox
.args([
"--",
"bash",
@@ -190,7 +191,7 @@ fn blacklist_overlays_survive_tmp_bind() {
#[test]
fn relative_chdir_works() {
let output = sandbox(&["--chdir", "src"])
let output = Sandbox::new(&["--chdir", "src"])
.args(["--", "bash", "-c", "pwd"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -209,7 +210,7 @@ fn relative_chdir_works() {
#[test]
fn relative_rw_path_works() {
let output = sandbox(&["--rw", "src"])
let output = Sandbox::new(&["--rw", "src"])
.args(["--", "bash", "-c", "echo ok"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -223,7 +224,7 @@ fn relative_rw_path_works() {
#[test]
fn relative_ro_path_works() {
let output = sandbox(&["--ro", "src"])
let output = Sandbox::new(&["--ro", "src"])
.args(["--", "bash", "-c", "echo ok"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -237,7 +238,7 @@ fn relative_ro_path_works() {
#[test]
fn rw_missing_path_errors() {
let output = sandbox(&["--rw", "/nonexistent/xyz"])
let output = Sandbox::new(&["--rw", "/nonexistent/xyz"])
.args(["--", "true"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -259,7 +260,7 @@ fn mask_hides_directory() {
fs::write(dir.path().join("secret.txt"), "sensitive").expect("failed to write");
let dir_str = dir.path().canonicalize().unwrap();
let output = sandbox(&["--mask", dir_str.to_str().unwrap()])
let output = Sandbox::new(&["--mask", dir_str.to_str().unwrap()])
.args([
"--",
"bash",
@@ -283,7 +284,7 @@ fn mask_hides_file() {
fs::write(&file, "sensitive").expect("failed to write");
let file_str = file.canonicalize().unwrap();
let output = sandbox(&["--mask", file_str.to_str().unwrap()])
let output = Sandbox::new(&["--mask", file_str.to_str().unwrap()])
.args([
"--",
"bash",
@@ -309,7 +310,7 @@ fn whitelist_ro_symlink_visible_at_link_path() {
std::os::unix::fs::symlink(&target, &link).expect("failed to create symlink");
let link_str = link.to_str().unwrap();
let output = sandbox(&["--whitelist", "--ro", link_str])
let output = Sandbox::new(&["--whitelist", "--ro", link_str])
.args(["--", "cat", link_str])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -328,7 +329,7 @@ fn mask_nonexistent_path_becomes_tmpfs() {
let fake = dir.path().join("does_not_exist");
let fake_str = fake.to_str().unwrap();
let output = sandbox(&["--mask", fake_str])
let output = Sandbox::new(&["--mask", fake_str])
.args([
"--",
"bash",
@@ -357,7 +358,8 @@ fn blacklist_overlays_survive_absolute_var_run_symlink() {
// like --tmpfs /var/run/dbus trip bwrap's re-rooted symlink resolution.
// Arch ships /var/run -> ../run (relative) so we synthesize the absolute
// layout inside the sandbox to reproduce on any host.
let mut bwrap_args = build_bwrap_command(&["--no-seccomp", "--", "true"]);
let _guard = HostGlobsLock::for_scan();
let mut bwrap_args = build_bwrap_command(&["--blacklist", "--no-seccomp", "--", "true"]);
inject_absolute_var_run_symlink(&mut bwrap_args);
let output = Command::new(&bwrap_args[0])
@@ -373,7 +375,7 @@ fn blacklist_overlays_survive_absolute_var_run_symlink() {
);
}
fn build_bwrap_command(sandbox_args: &[&str]) -> Vec<String> {
let output = sandbox(&["--dry-run"])
let output = Sandbox::new(&["--dry-run"])
.args(sandbox_args)
.output()
.expect("agent-sandbox binary failed to execute");
+8 -8
View File
@@ -13,7 +13,7 @@ fn read_sid_from_stat(stat: &str) -> u32 {
}
fn read_sid_inside_sandbox(extra_args: &[&str]) -> u32 {
let output = sandbox(extra_args)
let output = Sandbox::new(extra_args)
.args(["--", "bash", "-c", "cat /proc/self/stat"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -26,7 +26,7 @@ fn read_sid_current_process() -> u32 {
}
#[test]
fn unshare_net_blocks_network() {
let output = sandbox(&["--unshare-net"])
let output = Sandbox::new(&["--unshare-net"])
.args([
"--",
"bash",
@@ -45,7 +45,7 @@ fn unshare_net_blocks_network() {
#[test]
fn hardened_pid_namespace() {
let output = sandbox(&["--hardened"])
let output = Sandbox::new(&["--hardened"])
.args(["--", "bash", "-c", "ls /proc | grep -cE '^[0-9]+$'"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -65,7 +65,7 @@ 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])
let output = Sandbox::new(&["--chdir", dir_str])
.args(["--", "bash", "-c", "pwd"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -82,7 +82,7 @@ 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])
let output = Sandbox::new(&["--hardened", "--chdir", dir_str])
.args(["--", "bash", "-c", "pwd && touch ./ok && echo done"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -106,12 +106,12 @@ fn hardened_isolates_sid() {
}
#[test]
fn default_mode_shares_session() {
let inner_sid = read_sid_inside_sandbox(&[]);
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,
"default-mode sandbox should share the session ID (got {inner_sid} != {outer_sid})"
"blacklist-mode sandbox should share the session ID (got {inner_sid} != {outer_sid})"
);
}
+8 -8
View File
@@ -2,7 +2,7 @@ use crate::common::*;
#[test]
fn seccomp_on_by_default_blocks_unshare() {
let output = sandbox(&[])
let output = Sandbox::new(&[])
.args(["--", "unshare", "--user", "--map-root-user", "/bin/true"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -15,7 +15,7 @@ fn seccomp_on_by_default_blocks_unshare() {
#[test]
fn seccomp_off_allows_blocked_syscall() {
let output = sandbox(&["--no-seccomp"])
let output = Sandbox::new(&["--no-seccomp"])
.args(["--", "unshare", "--user", "--map-root-user", "/bin/true"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -29,7 +29,7 @@ fn seccomp_off_allows_blocked_syscall() {
#[test]
fn seccomp_dry_run_emits_seccomp_arg() {
let output = sandbox(&["--dry-run"])
let output = Sandbox::new(&["--dry-run"])
.args(["--", "/bin/true"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -43,7 +43,7 @@ fn seccomp_dry_run_emits_seccomp_arg() {
#[test]
fn seccomp_dry_run_no_seccomp_omits_arg() {
let output = sandbox(&["--dry-run", "--no-seccomp"])
let output = Sandbox::new(&["--dry-run", "--no-seccomp"])
.args(["--", "/bin/true"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -57,7 +57,7 @@ fn seccomp_dry_run_no_seccomp_omits_arg() {
#[test]
fn seccomp_normal_workload_succeeds() {
let output = sandbox(&[])
let output = Sandbox::new(&[])
.args(["--", "bash", "-c", "ls /etc > /dev/null && date"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -72,7 +72,7 @@ fn seccomp_normal_workload_succeeds() {
fn seccomp_bash_pthread_fallback_works() {
// Verifies the ENOSYS-not-EPERM choice for clone3 doesn't break libc's
// clone3 -> clone fallback path that bash uses internally.
let output = sandbox(&[])
let output = Sandbox::new(&[])
.args(["--", "bash", "-c", "true"])
.output()
.expect("agent-sandbox binary failed to execute");
@@ -92,7 +92,7 @@ fn seccomp_blocks_tiocsti() {
// On kernels >= 6.2 with CONFIG_LEGACY_TIOCSTI=n, the kernel blocks TIOCSTI
// before seccomp sees it. We test with --no-seccomp first to detect that and
// skip, so the test only asserts our filter's behaviour.
let baseline = sandbox(&["--no-seccomp"])
let baseline = Sandbox::new(&["--no-seccomp"])
.args([
"--",
"python3",
@@ -107,7 +107,7 @@ fn seccomp_blocks_tiocsti() {
return;
}
let output = sandbox(&[])
let output = Sandbox::new(&[])
.args([
"--",
"python3",
+1 -1
View File
@@ -405,7 +405,7 @@ fn build_cli_command_overrides_config() {
#[test]
fn build_no_file_config() {
let config = build(args_with_command(), None).unwrap();
assert!(matches!(config.mode, SandboxMode::Blacklist));
assert!(matches!(config.mode, SandboxMode::Whitelist));
assert!(!config.hardened);
}