From c28dd0b376b52e4a10d86a20e5b8850de85f787b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 18:41:14 +0000 Subject: [PATCH 01/11] fix(test): skip fs_errors test when running as root Root (uid=0) bypasses Unix discretionary access controls, so removing read permissions with chmod has no effect. This causes the fs_errors test to fail because read_dir() succeeds instead of returning Permission denied. Skip the test with an explanatory message when euid is 0. https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- Cargo.lock | 1 + Cargo.toml | 1 + tests/cli_errors.rs | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 33c9c1e8..fa28fb2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -643,6 +643,7 @@ dependencies = [ "fmt-iter", "into-sorted", "itertools 0.14.0", + "libc", "maplit", "normalize-path", "pipe-trait", diff --git a/Cargo.toml b/Cargo.toml index f364dd97..cd8e44ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,6 +86,7 @@ zero-copy-pads = "0.2.0" [dev-dependencies] build-fs-tree = "0.8.1" command-extra = "1.0.0" +libc = "0.2" maplit = "1.0.2" normalize-path = "0.2.1" pretty_assertions = "1.4.1" diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index c33f0d9a..3cf9bb1d 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -108,6 +108,11 @@ fn max_depth_0() { #[cfg(unix)] #[test] fn fs_errors() { + if unsafe { libc::geteuid() } == 0 { + eprintln!("SKIPPED: fs_errors test cannot work as root (permission checks are bypassed)"); + return; + } + let workspace = SampleWorkspace::default(); fs_permission(workspace.join("empty-dir"), "-r", false); fs_permission(workspace.join("nested").join("0"), "-r", false); From bc281813138d3cbd30f730eb5940c29c3ad3e9de Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 20:26:56 +0000 Subject: [PATCH 02/11] refactor(test): probe permissions instead of checking euid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the `unsafe { libc::geteuid() }` check with a direct probe: after chmod -r, try read_dir and skip if it still succeeds. This removes the `unsafe` block and the `libc` dev-dependency while being more semantically correct — it tests the actual condition we care about rather than a proxy. https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- Cargo.lock | 1 - Cargo.toml | 1 - tests/cli_errors.rs | 11 ++++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa28fb2e..33c9c1e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -643,7 +643,6 @@ dependencies = [ "fmt-iter", "into-sorted", "itertools 0.14.0", - "libc", "maplit", "normalize-path", "pipe-trait", diff --git a/Cargo.toml b/Cargo.toml index cd8e44ea..f364dd97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,6 @@ zero-copy-pads = "0.2.0" [dev-dependencies] build-fs-tree = "0.8.1" command-extra = "1.0.0" -libc = "0.2" maplit = "1.0.2" normalize-path = "0.2.1" pretty_assertions = "1.4.1" diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index 3cf9bb1d..810b5c3a 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -108,15 +108,16 @@ fn max_depth_0() { #[cfg(unix)] #[test] fn fs_errors() { - if unsafe { libc::geteuid() } == 0 { - eprintln!("SKIPPED: fs_errors test cannot work as root (permission checks are bypassed)"); - return; - } - let workspace = SampleWorkspace::default(); fs_permission(workspace.join("empty-dir"), "-r", false); fs_permission(workspace.join("nested").join("0"), "-r", false); + if std::fs::read_dir(workspace.join("empty-dir")).is_ok() { + fs_permission(&workspace, "+rwx", true); + eprintln!("SKIPPED: permission removal had no effect (likely running as root)"); + return; + } + let Output { status, stdout, From 94aaf333909e8a18cd91a8ae5965017f6528d592 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 20:32:40 +0000 Subject: [PATCH 03/11] Revert "refactor(test): probe permissions instead of checking euid" This reverts commit bb8e8cc3d4e356a5f8bf693b54ccea70bdbc62a2. --- Cargo.lock | 1 + Cargo.toml | 1 + tests/cli_errors.rs | 11 +++++------ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33c9c1e8..fa28fb2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -643,6 +643,7 @@ dependencies = [ "fmt-iter", "into-sorted", "itertools 0.14.0", + "libc", "maplit", "normalize-path", "pipe-trait", diff --git a/Cargo.toml b/Cargo.toml index f364dd97..cd8e44ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,6 +86,7 @@ zero-copy-pads = "0.2.0" [dev-dependencies] build-fs-tree = "0.8.1" command-extra = "1.0.0" +libc = "0.2" maplit = "1.0.2" normalize-path = "0.2.1" pretty_assertions = "1.4.1" diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index 810b5c3a..3cf9bb1d 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -108,16 +108,15 @@ fn max_depth_0() { #[cfg(unix)] #[test] fn fs_errors() { + if unsafe { libc::geteuid() } == 0 { + eprintln!("SKIPPED: fs_errors test cannot work as root (permission checks are bypassed)"); + return; + } + let workspace = SampleWorkspace::default(); fs_permission(workspace.join("empty-dir"), "-r", false); fs_permission(workspace.join("nested").join("0"), "-r", false); - if std::fs::read_dir(workspace.join("empty-dir")).is_ok() { - fs_permission(&workspace, "+rwx", true); - eprintln!("SKIPPED: permission removal had no effect (likely running as root)"); - return; - } - let Output { status, stdout, From 858afc648b9dde0698a1e45135ad56f868c9ba26 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 20:44:46 +0000 Subject: [PATCH 04/11] fix(test): fail loudly on root with cfg escape hatch for fs_errors Instead of silently skipping, panic with an actionable error message when running as root. The test can be excluded entirely via `RUSTFLAGS='--cfg pdu_test_skip_fs_errors'` for environments like Claude Code Web where root is unavoidable. https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- tests/cli_errors.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index 3cf9bb1d..5201269b 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -106,11 +106,15 @@ fn max_depth_0() { } #[cfg(unix)] +#[cfg(not(pdu_test_skip_fs_errors))] #[test] fn fs_errors() { if unsafe { libc::geteuid() } == 0 { - eprintln!("SKIPPED: fs_errors test cannot work as root (permission checks are bypassed)"); - return; + panic!( + "{}\n{}", + "error: Attempt to run this test on root environment was detected. Such an environment would affect the accuracy of this test.", + "hint: Either run this test on non-root environment or set `RUSTFLAGS='--cfg pdu_test_skip_fs_errors'` to skip this error.", + ); } let workspace = SampleWorkspace::default(); From 434845460e09170a22fba8bad9e977fc21722a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kh=E1=BA=A3i?= Date: Mon, 23 Mar 2026 03:57:02 +0700 Subject: [PATCH 05/11] docs: improve error message Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/cli_errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index 5201269b..826c8671 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -112,8 +112,8 @@ fn fs_errors() { if unsafe { libc::geteuid() } == 0 { panic!( "{}\n{}", - "error: Attempt to run this test on root environment was detected. Such an environment would affect the accuracy of this test.", - "hint: Either run this test on non-root environment or set `RUSTFLAGS='--cfg pdu_test_skip_fs_errors'` to skip this error.", + "error: This test must not be run as root because running with elevated privileges would affect its accuracy.", + "hint: Either run this test as a non-root user or set `RUSTFLAGS='--cfg pdu_test_skip_fs_errors'` to skip this test.", ); } From 6b56aaf3c343a565a14b494bec8c70076827b69d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 21:04:09 +0000 Subject: [PATCH 06/11] fix(test): allow unexpected_cfgs for pdu_test_skip_fs_errors Suppress the -D unexpected-cfgs error by adding #[allow(unexpected_cfgs)] before the custom cfg gate. https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- tests/cli_errors.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index 826c8671..be2142ea 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -106,6 +106,7 @@ fn max_depth_0() { } #[cfg(unix)] +#[allow(unexpected_cfgs)] #[cfg(not(pdu_test_skip_fs_errors))] #[test] fn fs_errors() { From 934f1f976af3a278b3e95d9dc992b708037d2206 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 21:51:46 +0000 Subject: [PATCH 07/11] fix(test): register pdu_test_skip_fs_errors in check-cfg The #[allow(unexpected_cfgs)] approach doesn't override -D warnings used in CI release builds. Register the custom cfg in Cargo.toml's [lints.rust] section instead, which properly declares it as a known cfg to the compiler. https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- Cargo.toml | 3 +++ tests/cli_errors.rs | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cd8e44ea..ae39db4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,9 @@ terminal_size = "0.4.3" text-block-macros = "0.2.0" zero-copy-pads = "0.2.0" +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(pdu_test_skip_fs_errors)'] } + [dev-dependencies] build-fs-tree = "0.8.1" command-extra = "1.0.0" diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index be2142ea..826c8671 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -106,7 +106,6 @@ fn max_depth_0() { } #[cfg(unix)] -#[allow(unexpected_cfgs)] #[cfg(not(pdu_test_skip_fs_errors))] #[test] fn fs_errors() { From 0de44612c997abcd1f68c104941000746d1a1abd Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 21:54:57 +0000 Subject: [PATCH 08/11] style(cargo): move [lints.rust] section after [dev-dependencies] https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ae39db4b..4b48a1e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,9 +83,6 @@ terminal_size = "0.4.3" text-block-macros = "0.2.0" zero-copy-pads = "0.2.0" -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(pdu_test_skip_fs_errors)'] } - [dev-dependencies] build-fs-tree = "0.8.1" command-extra = "1.0.0" @@ -94,3 +91,6 @@ maplit = "1.0.2" normalize-path = "0.2.1" pretty_assertions = "1.4.1" rand = "0.10.0" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(pdu_test_skip_fs_errors)'] } From 0cad540fa9fe6916eac84b19696f3b9fae24c893 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 22:06:58 +0000 Subject: [PATCH 09/11] fix(test): gate fs_errors imports and helper with pdu_test_skip_fs_errors Gate the Unix-specific imports and fs_permission helper with cfg(all(unix, not(pdu_test_skip_fs_errors))) so they don't produce dead code warnings when the test is skipped. https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- tests/cli_errors.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index 826c8671..a1e3af9c 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -9,9 +9,9 @@ use pretty_assertions::assert_eq; use std::process::{Command, Output, Stdio}; use text_block_macros::text_block; -#[cfg(unix)] +#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] use maplit::btreeset; -#[cfg(unix)] +#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] use parallel_disk_usage::{ bytes_format::BytesFormat, data_tree::DataTree, @@ -22,7 +22,7 @@ use parallel_disk_usage::{ reporter::{ErrorOnlyReporter, ErrorReport}, visualizer::{BarAlignment, ColumnWidthDistribution, Direction, Visualizer}, }; -#[cfg(unix)] +#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] use std::{collections::BTreeSet, path::Path}; fn stdio(command: Command) -> Command { @@ -32,7 +32,7 @@ fn stdio(command: Command) -> Command { .with_stderr(Stdio::piped()) } -#[cfg(unix)] +#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] fn fs_permission(path: impl AsRef, permission: &'static str, recursive: bool) { let Output { status, stderr, .. } = Command::new("chmod") .pipe(|cmd| if recursive { cmd.with_arg("-R") } else { cmd }) From 95ecb638aac912de46f2a1fede09e4e482e1b1e0 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 22:11:11 +0000 Subject: [PATCH 10/11] style(test): use separate cfg attributes instead of cfg(all(...)) https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- tests/cli_errors.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/cli_errors.rs b/tests/cli_errors.rs index a1e3af9c..b726676a 100644 --- a/tests/cli_errors.rs +++ b/tests/cli_errors.rs @@ -9,9 +9,11 @@ use pretty_assertions::assert_eq; use std::process::{Command, Output, Stdio}; use text_block_macros::text_block; -#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] +#[cfg(unix)] +#[cfg(not(pdu_test_skip_fs_errors))] use maplit::btreeset; -#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] +#[cfg(unix)] +#[cfg(not(pdu_test_skip_fs_errors))] use parallel_disk_usage::{ bytes_format::BytesFormat, data_tree::DataTree, @@ -22,7 +24,8 @@ use parallel_disk_usage::{ reporter::{ErrorOnlyReporter, ErrorReport}, visualizer::{BarAlignment, ColumnWidthDistribution, Direction, Visualizer}, }; -#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] +#[cfg(unix)] +#[cfg(not(pdu_test_skip_fs_errors))] use std::{collections::BTreeSet, path::Path}; fn stdio(command: Command) -> Command { @@ -32,7 +35,8 @@ fn stdio(command: Command) -> Command { .with_stderr(Stdio::piped()) } -#[cfg(all(unix, not(pdu_test_skip_fs_errors)))] +#[cfg(unix)] +#[cfg(not(pdu_test_skip_fs_errors))] fn fs_permission(path: impl AsRef, permission: &'static str, recursive: bool) { let Output { status, stderr, .. } = Command::new("chmod") .pipe(|cmd| if recursive { cmd.with_arg("-R") } else { cmd }) From d7b1878eaf7b55eedfab8602368b82318cf857d0 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 22:23:29 +0000 Subject: [PATCH 11/11] fix(cargo): pin libc to exact patch version for consistency https://claude.ai/code/session_01Ki7wbrgQXWs2GXf8h2hybQ --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4b48a1e8..7ba21ff4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,7 @@ zero-copy-pads = "0.2.0" [dev-dependencies] build-fs-tree = "0.8.1" command-extra = "1.0.0" -libc = "0.2" +libc = "0.2.182" maplit = "1.0.2" normalize-path = "0.2.1" pretty_assertions = "1.4.1"