253 lines
7.0 KiB
Rust
253 lines
7.0 KiB
Rust
use crate::common::*;
|
|
|
|
#[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 dry_run_output_is_copy_pasteable_shell() {
|
|
let dry = sandbox(&["--dry-run"])
|
|
.args(["--", "bash", "-c", "echo $HOME"])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
|
|
let dry_cmd = String::from_utf8_lossy(&dry.stdout).trim().to_string();
|
|
let args = shlex::split(&dry_cmd).expect("dry-run output is not valid shell");
|
|
assert_eq!(args[0], "bwrap");
|
|
assert_eq!(args[args.len() - 1], "echo $HOME");
|
|
assert_eq!(args[args.len() - 2], "-c");
|
|
}
|
|
|
|
#[test]
|
|
fn empty_home_rejected() {
|
|
let output = sandbox(&[])
|
|
.env("HOME", "")
|
|
.args(["--", "true"])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
|
|
assert!(
|
|
!output.status.success(),
|
|
"expected failure with empty HOME, but got success"
|
|
);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
stderr.to_lowercase().contains("home"),
|
|
"expected error mentioning HOME, got: {stderr}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_missing_file_errors() {
|
|
let output = sandbox_withconfig(&["--config", "/nonexistent/config.toml"])
|
|
.args(["--", "true"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
stderr.contains("/nonexistent/config.toml"),
|
|
"expected config path in error, got: {stderr}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_invalid_toml_errors() {
|
|
let cfg = ConfigFile::new("not valid {{{{ toml");
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg])
|
|
.args(["--", "true"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
stderr.contains("cannot parse"),
|
|
"expected parse error, got: {stderr}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_unknown_key_errors() {
|
|
let cfg = ConfigFile::new("hardened = true\nbogus = \"nope\"\n");
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg])
|
|
.args(["--", "true"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
stderr.contains("unknown config key"),
|
|
"expected unknown key error, got: {stderr}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn bwrap_arg_setenv_passes_through() {
|
|
let output = sandbox(&["--bwrap-arg", "--setenv MYVAR hello"])
|
|
.args(["--", "bash", "-c", "echo $MYVAR"])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "hello",
|
|
"expected --bwrap-arg to pass --setenv through to bwrap, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_entrypoint_appends_passthrough_args() {
|
|
let cfg = ConfigFile::new(
|
|
r#"
|
|
[profiles.test]
|
|
entrypoint = ["bash", "-c"]
|
|
"#,
|
|
);
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
|
|
.args(["--", "echo entrypoint-works"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "entrypoint-works",
|
|
"expected passthrough args appended to entrypoint, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_entrypoint_falls_back_to_command_defaults() {
|
|
let cfg = ConfigFile::new(
|
|
r#"
|
|
[profiles.test]
|
|
entrypoint = ["bash", "-c"]
|
|
command = ["echo default-args"]
|
|
"#,
|
|
);
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "default-args",
|
|
"expected command defaults when no passthrough args, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_entrypoint_alone_without_command_or_passthrough() {
|
|
let cfg = ConfigFile::new(
|
|
r#"
|
|
[profiles.test]
|
|
entrypoint = ["bash", "-c", "echo entrypoint-only"]
|
|
"#,
|
|
);
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "entrypoint-only",
|
|
"expected entrypoint to run on its own, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn cli_entrypoint_appends_passthrough_args() {
|
|
let output = sandbox(&["--entrypoint", "bash"])
|
|
.args(["--", "-c", "echo cli-entrypoint-works"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "cli-entrypoint-works",
|
|
"expected --entrypoint to receive trailing args, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn cli_entrypoint_overrides_config_entrypoint() {
|
|
let cfg = ConfigFile::new(
|
|
r#"
|
|
entrypoint = ["/bin/false"]
|
|
"#,
|
|
);
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg, "--entrypoint", "bash"])
|
|
.args(["--", "-c", "echo override-works"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "override-works",
|
|
"expected CLI --entrypoint to override config entrypoint, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_command_alone_without_passthrough() {
|
|
let cfg = ConfigFile::new(
|
|
r#"
|
|
[profiles.test]
|
|
command = ["bash", "-c", "echo command-only"]
|
|
"#,
|
|
);
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "command-only",
|
|
"expected config command to run on its own, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn config_command_replaced_by_passthrough() {
|
|
let cfg = ConfigFile::new(
|
|
r#"
|
|
[profiles.test]
|
|
command = ["bash", "-c", "echo should-not-see-this"]
|
|
"#,
|
|
);
|
|
|
|
let output = sandbox_withconfig(&["--config", &cfg, "--profile", "test"])
|
|
.args(["--", "bash", "-c", "echo replaced"])
|
|
.output()
|
|
.expect("failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, "replaced",
|
|
"expected passthrough to replace config command, got: {stdout}"
|
|
);
|
|
}
|