diff --git a/crates/bashkit/tests/integration/threat_model_tests.rs b/crates/bashkit/tests/integration/threat_model_tests.rs index f27fd0e00..2169e6e5c 100644 --- a/crates/bashkit/tests/integration/threat_model_tests.rs +++ b/crates/bashkit/tests/integration/threat_model_tests.rs @@ -91,11 +91,12 @@ mod resource_exhaustion { }) } - /// Runs a script in the built CLI under `run_command_bounded`. + /// Runs a script in the built CLI under `run_command_bounded`, with + /// trailing `$0`/ARG0 words after the `-c` script. /// The launcher applies the fail-closed CPU/stack caps, reports the /// effective values as the first stderr line, then `exec`s the CLI so /// exit codes and diagnostics stay the real producer's own. - fn run_cli_bounded(script: &str, limit: Duration) -> BoundedRun { + fn run_cli_argv_bounded(script: &str, extra_args: &[&str], limit: Duration) -> BoundedRun { let launcher = format!( "{BOUNDED_CLI_LIMITS}; echo \"harness-limits: stack=$(ulimit -s) cpu=$(ulimit -t)\" >&2; exec \"$@\"" ); @@ -103,6 +104,7 @@ mod resource_exhaustion { cmd.args(["-c", &launcher, "_"]) .arg(bashkit_cli_path()) .args(["-c", script]) + .args(extra_args) .stdin(Stdio::null()) .stdout(Stdio::piped()) .stderr(Stdio::piped()); @@ -116,6 +118,12 @@ mod resource_exhaustion { run } + /// Runs a script in the built CLI under `run_command_bounded`, with + /// no trailing words after the `-c` script. + fn run_cli_bounded(script: &str, limit: Duration) -> BoundedRun { + run_cli_argv_bounded(script, &[], limit) + } + /// Runs an already-built command with one shared wall deadline for /// child exit, pipe drain, and reaping: /// - wall clock: past `limit` the child is killed; if it had already @@ -218,60 +226,6 @@ mod resource_exhaustion { } } - /// Runs argv (a `-c` script plus trailing `$0`/ARG0 words) in a child - /// CLI process under the same bounds contract as [`run_cli_bounded`]: - /// wall-clock watchdog, 8 KiB output cap, real exit code preserved. - fn run_cli_argv_bounded(argv: &[&str], limit: Duration) -> BoundedRun { - use std::io::Read; - let mut child = Command::new(bashkit_cli_path()); - child - .args(argv) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - let mut child = child.spawn().expect("spawn bounded bashkit CLI"); - let deadline = Instant::now() + limit; - loop { - match child.try_wait().expect("poll bounded CLI") { - Some(status) => { - let mut stdout = String::new(); - let mut stderr = String::new(); - child - .stdout - .take() - .unwrap() - .read_to_string(&mut stdout) - .unwrap(); - child - .stderr - .take() - .unwrap() - .read_to_string(&mut stderr) - .unwrap(); - return BoundedRun { - exit_code: status.code(), - stdout: stdout.chars().take(8192).collect(), - stderr: stderr.chars().take(8192).collect(), - timed_out: false, - }; - } - None => { - if Instant::now() >= deadline { - child.kill().ok(); - child.wait().ok(); - return BoundedRun { - exit_code: None, - stdout: String::new(), - stderr: String::new(), - timed_out: true, - }; - } - std::thread::sleep(Duration::from_millis(5)); - } - } - } - } - /// TM-DOS-136: scaled multiline token x long ARG0 stays bounded in a /// child. The exact finding shape: `for x "` plus N `a`+newline lines /// plus the closing quote (the parser expects `do`), invoked with a long @@ -289,7 +243,7 @@ mod resource_exhaustion { } script.push('"'); let arg0 = "B".repeat(8192); - let run = run_cli_argv_bounded(&["-c", &script, &arg0], Duration::from_secs(20)); + let run = run_cli_argv_bounded(&script, &[&arg0], Duration::from_secs(20)); assert!( !run.timed_out, "token_lines={token_lines}: child hit the 20s watchdog"