diff --git a/rust/crates/runtime/tests/probe_unshare.rs b/rust/crates/runtime/tests/probe_unshare.rs new file mode 100644 index 00000000..d4328207 --- /dev/null +++ b/rust/crates/runtime/tests/probe_unshare.rs @@ -0,0 +1,50 @@ +//! Scratch probe: dump GitHub runner unshare semantics (temporary, PR will be closed). +#![cfg(target_os = "linux")] + +use std::process::Command; + +fn run(args: &[&str]) -> (i32, String, String) { + let out = Command::new("unshare").args(args).output(); + match out { + Ok(o) => ( + o.status.code().unwrap_or(-1), + String::from_utf8_lossy(&o.stdout).trim().to_string(), + String::from_utf8_lossy(&o.stderr).trim().to_string(), + ), + Err(e) => (-1, String::new(), format!("spawn error: {e}")), + } +} + +#[test] +fn dump_unshare_semantics() { + let uid = unsafe { libc::getuid() }; + let mut report = String::new(); + report.push_str(&format!("uid={uid} euid={}\n", unsafe { libc::geteuid() })); + for f in ["/etc/subuid", "/etc/subgid"] { + report.push_str(&format!("--- {f} ---\n")); + if let Ok(s) = std::fs::read_to_string(f) { + report.push_str(&s); + } else { + report.push_str("(unreadable)\n"); + } + } + for k in ["/proc/sys/kernel/unprivileged_userns_clone", "/proc/sys/kernel/apparmor_restrict_unprivileged_userns"] { + report.push_str(&format!("{k} = {}\n", std::fs::read_to_string(k).unwrap_or_else(|_| "(n/a)".into()))); + } + for (name, args) in [ + ("plain", &["--user", "--map-root-user", "true"][..]), + ("auto", &["--user", "--map-root-user", "--map-auto", "true"][..]), + ( + "plain-full", + &["--user", "--map-root-user", "--mount", "--ipc", "--pid", "--uts", "--fork", "sh", "-lc", "echo alpha"][..], + ), + ( + "auto-full", + &["--user", "--map-root-user", "--map-auto", "--mount", "--ipc", "--pid", "--uts", "--fork", "sh", "-lc", "echo alpha"][..], + ), + ] { + let (rc, so, se) = run(args); + report.push_str(&format!("[{name}] rc={rc} stdout={so:?} stderr={se:?}\n")); + } + panic!("PROBE REPORT:\n{report}"); +}