//! Removing a tree whose files are owned by subordinate ids, through the `__sandbox-rm` helper. //! The tests skip when the host can't provide subuid mode or `unshare --map-auto`. use std::fs; use std::path::Path; use std::process::{Command, Stdio}; use forge_runner::sandbox::idmap::{IdMap, UsernsMode, remove_tree}; #[test] fn remove_tree_deletes_files_owned_by_subordinate_ids() { let map = match IdMap::resolve(UsernsMode::Subuid) { Ok(map) => map, Err(e) => { eprintln!("skipping: {e}"); return; } }; let dir = tempfile::tempdir().expect("tempdir"); let job = dir.path().join("job"); fs::create_dir_all(job.join("sub")).expect("create job dir"); let file = job.join("sub/f"); fs::write(&file, b"x").expect("write file"); // Give the file to container uid 1000, which is a subordinate id on the host. let chown = Command::new("unshare") .args(["--map-auto", "--map-root-user", "chown", "1000:1000"]) .arg(&file) .stdout(Stdio::null()) .stderr(Stdio::null()) .status(); if !chown.is_ok_and(|s| s.success()) { eprintln!("skipping: unshare --map-auto cannot chown"); return; } let exe = Path::new(env!("CARGO_BIN_EXE_forge-runner")); remove_tree(&map, &job, exe).expect("remove_tree"); assert!(!job.exists(), "{} should be gone", job.display()); } #[test] fn remove_tree_treats_a_missing_path_as_done() { let dir = tempfile::tempdir().expect("tempdir"); let missing = dir.path().join("missing"); let exe = Path::new(env!("CARGO_BIN_EXE_forge-runner")); remove_tree(&IdMap::single(), &missing, exe).expect("single mode"); let map = IdMap { uid: 1000, gid: 1000, sub_uid: Some((524288, 65536)), sub_gid: Some((524288, 65536)), }; remove_tree(&map, &missing, exe).expect("subuid mode"); }