From 05a92bcb21e40dd1e56df2c55fde83e8c0f84a82 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Nov 2026 13:52:19 +0000 Subject: [PATCH] Skip permission-denial unit tests under root Four socket-patch-core unit tests make a directory read-only and assert that a write or removal fails. Root ignores permission bits, so under uid 0 (dev containers, cloud agent sandboxes, root CI images) the operation succeeds and the tests fail on a clean checkout: patch::copy_tree::relax_loop_must_not_traverse_symlinked_root patch::redirect::vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry vendor::pypi_poetry::wire_write_failure_maps_error_and_leaves_lock_untouched vendor::pypi_requirements::wire_failure_rolls_back_already_written_files Give them the same geteuid() == 0 early return that the pnpm_lock, bun_lock and composer_lock permission tests already use. GitHub-hosted and Depot runners are non-root, so CI still runs every assertion. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_011f9aeSKziH186vNriv2dbS --- crates/socket-patch-core/src/patch/copy_tree.rs | 3 +++ crates/socket-patch-core/src/patch/redirect/vlt_heal.rs | 3 +++ crates/socket-patch-core/src/vendor/pypi_poetry.rs | 3 +++ crates/socket-patch-core/src/vendor/pypi_requirements.rs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/crates/socket-patch-core/src/patch/copy_tree.rs b/crates/socket-patch-core/src/patch/copy_tree.rs index f49c1df16..1ff6224cc 100644 --- a/crates/socket-patch-core/src/patch/copy_tree.rs +++ b/crates/socket-patch-core/src/patch/copy_tree.rs @@ -655,6 +655,9 @@ mod tests { #[cfg(unix)] #[tokio::test] async fn relax_loop_must_not_traverse_symlinked_root() { + if unsafe { libc::geteuid() } == 0 { + return; // root bypasses permission bits; nothing to test + } let base = tempfile::tempdir().unwrap(); // External target tree with restrictive perms. let target = base.path().join("target"); diff --git a/crates/socket-patch-core/src/patch/redirect/vlt_heal.rs b/crates/socket-patch-core/src/patch/redirect/vlt_heal.rs index 67f5ee023..eddc3c260 100644 --- a/crates/socket-patch-core/src/patch/redirect/vlt_heal.rs +++ b/crates/socket-patch-core/src/patch/redirect/vlt_heal.rs @@ -527,6 +527,9 @@ mod tests { #[tokio::test] async fn an_unremovable_hidden_lock_keeps_every_store_entry() { use std::os::unix::fs::PermissionsExt as _; + if unsafe { libc::geteuid() } == 0 { + return; // root bypasses permission bits; nothing to test + } let tmp = tempfile::tempdir().unwrap(); store(tmp.path(), ID, PRISTINE); hidden(tmp.path(), Some("sha512-UPSTREAM")); diff --git a/crates/socket-patch-core/src/vendor/pypi_poetry.rs b/crates/socket-patch-core/src/vendor/pypi_poetry.rs index 3ac21c6a6..3becf9bdb 100644 --- a/crates/socket-patch-core/src/vendor/pypi_poetry.rs +++ b/crates/socket-patch-core/src/vendor/pypi_poetry.rs @@ -1503,6 +1503,9 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 #[tokio::test] async fn wire_write_failure_maps_error_and_leaves_lock_untouched() { use std::os::unix::fs::PermissionsExt; + if unsafe { libc::geteuid() } == 0 { + return; // root bypasses permission bits; nothing to test + } let tmp = write_project(LOCK21_DIRECT_REGISTRY, PYPROJECT_DIRECT).await; let p = load_poetry_project(tmp.path()).await.unwrap(); diff --git a/crates/socket-patch-core/src/vendor/pypi_requirements.rs b/crates/socket-patch-core/src/vendor/pypi_requirements.rs index 02db10802..8a071598c 100644 --- a/crates/socket-patch-core/src/vendor/pypi_requirements.rs +++ b/crates/socket-patch-core/src/vendor/pypi_requirements.rs @@ -3153,6 +3153,9 @@ mod tests { #[tokio::test] async fn wire_failure_rolls_back_already_written_files() { use std::os::unix::fs::PermissionsExt as _; + if unsafe { libc::geteuid() } == 0 { + return; // root bypasses permission bits; nothing to test + } let original_root = "six==1.16.0\n-r deps/pinned.txt\n"; let tmp = write_root(original_root).await; tokio::fs::create_dir_all(tmp.path().join("deps"))