M5a plan: task 16, the gate passes on macOS; the review's tasks become 17 to 20
The work moved to titan (macOS), where the gate failed for reasons older than M5a: sockets under macOS's long TMPDIR pass its 104-byte limit, gatewayd reads /proc/self for its uid, and /tmp is /private/tmp. Task 16 sets TMPDIR=/tmp for every process Cargo runs (.cargo/config.toml [env]), has gatewayd take its uid from the owner of a pipe it makes (no dependency, no unsafe), and hands over a toolkit shell.rs that compares resolved paths. On a scratch tree the gate passes on titan and on talos with 936 tests, and a wrong uid fails 7 gatewayd tests. Tasks 16 to 19 are renumbered 17 to 20. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
//! `toolkit shell`, run as `brokerd` runs it, with the host's `/bin/sh`. Do not edit.
|
||||
|
||||
mod support;
|
||||
|
||||
use proto::tools::ShellArgs;
|
||||
use support::{TempDir, json, toolkit};
|
||||
use toolkit::shell::MAX_OUTPUT;
|
||||
|
||||
fn sh(command: &str, cwd: Option<&str>) -> support::Ran {
|
||||
let args = ShellArgs {
|
||||
command: command.to_string(),
|
||||
cwd: cwd.map(str::to_string),
|
||||
};
|
||||
toolkit(&["shell"], &json(&args))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_and_errors_come_back_in_order_then_the_exit_status() {
|
||||
let ran = sh("echo one; echo two >&2; echo three", None);
|
||||
assert_eq!(ran.code, 0);
|
||||
assert_eq!(ran.stdout, "one\ntwo\nthree\n\n[exit 0]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_failing_command_is_still_a_result_with_its_status() {
|
||||
let ran = sh("echo nope; exit 3", None);
|
||||
assert_eq!((ran.code, ran.stdout.as_str()), (0, "nope\n\n[exit 3]"));
|
||||
let ran = sh("true", None);
|
||||
assert_eq!(ran.stdout, "\n[exit 0]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_command_killed_by_a_signal_says_so() {
|
||||
let ran = sh("kill -9 $$", None);
|
||||
assert_eq!(
|
||||
(ran.code, ran.stdout.as_str()),
|
||||
(0, "\n[killed by signal 9]")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_command_runs_in_cwd_or_in_tmp() {
|
||||
let dir = TempDir::new("cwd");
|
||||
let here = dir.path().to_str().unwrap();
|
||||
// `pwd` prints the path with symbolic links resolved: on macOS, /tmp is /private/tmp.
|
||||
let real = |path: &str| std::fs::canonicalize(path).unwrap().display().to_string();
|
||||
let ran = sh("pwd", Some(here));
|
||||
assert_eq!(ran.stdout, format!("{}\n\n[exit 0]", real(here)));
|
||||
let ran = sh("pwd", None);
|
||||
assert_eq!(ran.stdout, format!("{}\n\n[exit 0]", real("/tmp")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_missing_cwd_is_exit_1() {
|
||||
let ran = sh("pwd", Some("/no/such/dir"));
|
||||
assert_eq!(
|
||||
(ran.code, ran.stdout.as_str()),
|
||||
(1, "shell: /no/such/dir: no such directory")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn standard_input_is_empty() {
|
||||
let ran = sh("cat; echo done", None);
|
||||
assert_eq!(ran.stdout, "done\n\n[exit 0]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_past_the_limit_is_dropped_and_the_command_still_finishes() {
|
||||
let ran = sh(
|
||||
&format!(
|
||||
"head -c {} /dev/zero | tr '\\0' a; echo; echo end >&2; exit 4",
|
||||
MAX_OUTPUT + 5000
|
||||
),
|
||||
None,
|
||||
);
|
||||
assert_eq!(ran.code, 0);
|
||||
let expected_tail = format!("\n[output after {MAX_OUTPUT} bytes dropped]\n[exit 4]");
|
||||
assert!(
|
||||
ran.stdout.ends_with(&expected_tail),
|
||||
"{}",
|
||||
&ran.stdout[ran.stdout.len() - 80..]
|
||||
);
|
||||
assert_eq!(ran.stdout.len(), MAX_OUTPUT + expected_tail.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_that_is_not_utf8_is_replaced_not_refused() {
|
||||
let ran = sh("printf 'a\\377b'", None);
|
||||
assert_eq!(ran.stdout, "a\u{fffd}b\n[exit 0]");
|
||||
}
|
||||
Reference in New Issue
Block a user