Skip to content

Commit d27b91f

Browse files
committed
test: cover sudo install paths
Signed-off-by: Codex (GPT 5) <codex@openai.com>
1 parent cc0c1d2 commit d27b91f

1 file changed

Lines changed: 108 additions & 0 deletions

File tree

src/lib.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,70 @@ mod tests {
12461246
assert!(install_payload(&src, &dest).is_err());
12471247
}
12481248

1249+
#[test]
1250+
#[serial]
1251+
#[cfg(unix)]
1252+
fn install_payload_retries_with_sudo_on_permission_denied() {
1253+
let (_sudo_dir, _path_guard) = setup_fake_sudo();
1254+
let temp = tempfile::tempdir().expect("temp dir");
1255+
let src = temp.path().join("src");
1256+
let dest = temp.path().join("dest");
1257+
fs::write(&src, b"hello").expect("write");
1258+
fs::write(&dest, b"old").expect("write dest");
1259+
1260+
{
1261+
use std::os::unix::fs::PermissionsExt;
1262+
let mut perms = fs::metadata(&dest).expect("stat").permissions();
1263+
perms.set_mode(0o444);
1264+
fs::set_permissions(&dest, perms).expect("chmod");
1265+
}
1266+
1267+
install_payload(&src, &dest).expect("install payload");
1268+
assert_eq!(fs::read(&dest).expect("read"), b"hello");
1269+
}
1270+
1271+
#[test]
1272+
#[serial]
1273+
#[cfg(unix)]
1274+
fn install_with_sudo_uses_fake_sudo() {
1275+
let (_sudo_dir, _path_guard) = setup_fake_sudo();
1276+
let temp = tempfile::tempdir().expect("temp dir");
1277+
let src = temp.path().join("src");
1278+
let dest = temp.path().join("dest");
1279+
fs::write(&src, b"hello").expect("write");
1280+
1281+
install_with_sudo(&src, &dest).expect("install with sudo");
1282+
assert_eq!(fs::read(&dest).expect("read"), b"hello");
1283+
}
1284+
1285+
#[test]
1286+
#[serial]
1287+
#[cfg(unix)]
1288+
fn ensure_install_dir_uses_sudo_on_permission_denied() {
1289+
let (_sudo_dir, _path_guard) = setup_fake_sudo();
1290+
let temp = tempfile::tempdir().expect("temp dir");
1291+
let protected = temp.path().join("protected");
1292+
fs::create_dir_all(&protected).expect("mkdir");
1293+
1294+
{
1295+
use std::os::unix::fs::PermissionsExt;
1296+
let mut perms = fs::metadata(&protected).expect("stat").permissions();
1297+
perms.set_mode(0o500);
1298+
fs::set_permissions(&protected, perms).expect("chmod");
1299+
}
1300+
1301+
let install_dir = protected.join("bin");
1302+
ensure_install_dir(&install_dir).expect("ensure install dir");
1303+
assert!(install_dir.exists());
1304+
1305+
{
1306+
use std::os::unix::fs::PermissionsExt;
1307+
let mut perms = fs::metadata(&protected).expect("stat").permissions();
1308+
perms.set_mode(0o700);
1309+
fs::set_permissions(&protected, perms).expect("chmod");
1310+
}
1311+
}
1312+
12491313
#[test]
12501314
fn is_permission_denied_detects_nested_error() {
12511315
let err = anyhow::Error::new(io::Error::new(io::ErrorKind::PermissionDenied, "nope"));
@@ -1767,6 +1831,50 @@ mod tests {
17671831
}
17681832
}
17691833

1834+
#[cfg(unix)]
1835+
fn setup_fake_sudo() -> (tempfile::TempDir, EnvGuard) {
1836+
use std::os::unix::fs::PermissionsExt;
1837+
1838+
let dir = tempfile::tempdir().expect("temp dir");
1839+
let sudo_path = dir.path().join("sudo");
1840+
let script = r#"#!/bin/sh
1841+
set -e
1842+
cmd="$1"
1843+
shift
1844+
1845+
case "$cmd" in
1846+
mv)
1847+
exec /bin/mv "$@"
1848+
;;
1849+
mkdir)
1850+
last=""
1851+
for arg in "$@"; do
1852+
last="$arg"
1853+
done
1854+
if [ -n "$last" ]; then
1855+
parent=$(dirname "$last")
1856+
chmod u+w "$parent" 2>/dev/null || true
1857+
fi
1858+
exec /bin/mkdir "$@"
1859+
;;
1860+
*)
1861+
echo "unexpected sudo command: $cmd" >&2
1862+
exit 1
1863+
;;
1864+
esac
1865+
"#;
1866+
1867+
fs::write(&sudo_path, script).expect("write fake sudo");
1868+
let mut perms = fs::metadata(&sudo_path).expect("stat").permissions();
1869+
perms.set_mode(0o755);
1870+
fs::set_permissions(&sudo_path, perms).expect("chmod");
1871+
1872+
let existing = env::var("PATH").unwrap_or_default();
1873+
let path = format!("{}:{}", dir.path().display(), existing);
1874+
let guard = EnvGuard::set("PATH", path);
1875+
(dir, guard)
1876+
}
1877+
17701878
struct TestServer {
17711879
base: String,
17721880
handle: Option<thread::JoinHandle<()>>,

0 commit comments

Comments
 (0)