From 3c1ed622b5b4cc90e84fbc9027d2ab5a39f10192 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 05:29:34 +0000 Subject: [PATCH 1/4] chore(deps): update rust docker tag to v1.99 --- docker/Dockerfile.alpine | 2 +- docker/Dockerfile.debian | 2 +- docker/Dockerfile.e2e | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index f09933c..92b2789 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -8,7 +8,7 @@ # No SELinux. Busybox's tools may differ from the upstream shadow-utils. # Pinned: see the note in Dockerfile.debian. -FROM rust:1.98-alpine3.23 +FROM rust:1.99-alpine3.23 RUN apk add --no-cache \ musl-dev \ diff --git a/docker/Dockerfile.debian b/docker/Dockerfile.debian index ec8d934..3a7870b 100644 --- a/docker/Dockerfile.debian +++ b/docker/Dockerfile.debian @@ -8,7 +8,7 @@ # Pinned: an unpinned tag lands a new toolchain on main with no PR signal, # and clippy gains lints between releases. Renovate proposes the bump. -FROM rust:1.98-trixie +FROM rust:1.99-trixie RUN apt-get update && apt-get install -y --no-install-recommends \ libpam0g-dev \ diff --git a/docker/Dockerfile.e2e b/docker/Dockerfile.e2e index 497f9c0..440f744 100644 --- a/docker/Dockerfile.e2e +++ b/docker/Dockerfile.e2e @@ -10,7 +10,7 @@ # ── Stage 1: build shadow-rs ──────────────────────────────────────── # Pinned: see the note in Dockerfile.debian. -FROM rust:1.98-trixie AS builder +FROM rust:1.99-trixie AS builder RUN apt-get update && apt-get install -y --no-install-recommends \ libpam0g-dev \ From 8fb9f6871de7cab9da55ec07d011a0f30db79a00 Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Mon, 5 Oct 2026 10:42:46 +0200 Subject: [PATCH 2/4] docs: the test matrix table follows the Rust image bump Renovate bumps the three Dockerfiles; the table in PLATFORM-SUPPORT.md names the same images and was still at 1.98. --- docs/PLATFORM-SUPPORT.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/PLATFORM-SUPPORT.md b/docs/PLATFORM-SUPPORT.md index 41d309d..af6fd01 100644 --- a/docs/PLATFORM-SUPPORT.md +++ b/docs/PLATFORM-SUPPORT.md @@ -47,8 +47,8 @@ CI runs the full suite on three images: | Image | Base | libc | PAM | SELinux | |---|---|---|---|---| -| `debian` | `rust:1.98-trixie` | glibc | Linux-PAM | headers | -| `alpine` | `rust:1.98-alpine3.23` | musl (dynamic) | Linux-PAM | none | +| `debian` | `rust:1.99-trixie` | glibc | Linux-PAM | headers | +| `alpine` | `rust:1.99-alpine3.23` | musl (dynamic) | Linux-PAM | none | | `fedora` | `fedora:44` | glibc | Linux-PAM | enforcing | The base images are pinned. An unpinned tag lands a new toolchain on `main` From fe49d10b65a963d3d5a1cda2cefa9c82bfd2d560 Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Mon, 5 Oct 2026 10:48:02 +0200 Subject: [PATCH 3/4] tests: show the value when asserting that something is empty Rust 1.99's clippy adds assert_is_empty: a bare assert!(x.is_empty()) says only that the check failed, not what x held. Twenty-two test assertions across the workspace were of that form; each now carries the value in its message, which is what the lint is after and reads better than its own suggestion of comparing against `[] as [T; 0]`. Test code only. The CI clippy job runs on the runner's toolchain, which has not reached 1.99 yet, so the pull request was green while `make check` in the rebuilt image was not. --- src/shadow-core/src/group.rs | 4 ++-- src/shadow-core/src/gshadow.rs | 10 +++++----- src/shadow-core/src/os_error.rs | 2 +- src/shadow-core/src/passwd.rs | 2 +- src/shadow-core/src/shadow.rs | 2 +- src/shadow-core/src/subid.rs | 2 +- src/uu/chgpasswd/src/chgpasswd.rs | 2 +- src/uu/chsh/src/chsh.rs | 4 ++-- src/uu/gpasswd/src/gpasswd.rs | 8 ++++++-- src/uu/login/src/login.rs | 2 +- src/uu/newusers/src/newusers.rs | 6 +++--- src/uu/pwconv/src/pwconv.rs | 2 +- tests/by-util/test_expiry.rs | 6 +++++- 13 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/shadow-core/src/group.rs b/src/shadow-core/src/group.rs index 78c588a..5418645 100644 --- a/src/shadow-core/src/group.rs +++ b/src/shadow-core/src/group.rs @@ -146,7 +146,7 @@ mod tests { assert_eq!(entry.name, "root"); assert_eq!(entry.passwd, "x"); assert_eq!(entry.gid, 0); - assert!(entry.members.is_empty()); + assert!(entry.members.is_empty(), "{:?}", entry.members); } #[test] @@ -225,7 +225,7 @@ mod tests { let path = dir.path().join("group"); std::fs::write(&path, "").unwrap(); let entries = read_group_file(&path).unwrap(); - assert!(entries.is_empty()); + assert!(entries.is_empty(), "{entries:?}"); } use proptest::prelude::*; diff --git a/src/shadow-core/src/gshadow.rs b/src/shadow-core/src/gshadow.rs index a50c4c9..4905715 100644 --- a/src/shadow-core/src/gshadow.rs +++ b/src/shadow-core/src/gshadow.rs @@ -155,8 +155,8 @@ mod tests { let entry: GshadowEntry = "root:*::".parse().unwrap(); assert_eq!(entry.name, "root"); assert_eq!(entry.passwd, "*"); - assert!(entry.admins.is_empty()); - assert!(entry.members.is_empty()); + assert!(entry.admins.is_empty(), "{:?}", entry.admins); + assert!(entry.members.is_empty(), "{:?}", entry.members); } #[test] @@ -172,13 +172,13 @@ mod tests { fn test_parse_admins_only() { let entry: GshadowEntry = "wheel:!:root:".parse().unwrap(); assert_eq!(entry.admins, vec!["root"]); - assert!(entry.members.is_empty()); + assert!(entry.members.is_empty(), "{:?}", entry.members); } #[test] fn test_parse_members_only() { let entry: GshadowEntry = "docker:!::deploy,ci".parse().unwrap(); - assert!(entry.admins.is_empty()); + assert!(entry.admins.is_empty(), "{:?}", entry.admins); assert_eq!(entry.members, vec!["deploy", "ci"]); } @@ -239,7 +239,7 @@ mod tests { let path = dir.path().join("gshadow"); std::fs::write(&path, "").unwrap(); let entries = read_gshadow_file(&path).unwrap(); - assert!(entries.is_empty()); + assert!(entries.is_empty(), "{entries:?}"); } #[test] diff --git a/src/shadow-core/src/os_error.rs b/src/shadow-core/src/os_error.rs index 17e290c..11b6da3 100644 --- a/src/shadow-core/src/os_error.rs +++ b/src/shadow-core/src/os_error.rs @@ -34,7 +34,7 @@ mod tests { // Non-empty, and the bare OS text — not Rust's "... (os error 13)" // rendering (the regression that suffix-stripping prevents). We assert // the shape, not the exact wording, since libc may localize it. - assert!(!msg.is_empty()); + assert!(!msg.is_empty(), "{msg:?}"); assert!(!msg.contains("(os error"), "got: {msg:?}"); } } diff --git a/src/shadow-core/src/passwd.rs b/src/shadow-core/src/passwd.rs index 62c1b20..1332a3b 100644 --- a/src/shadow-core/src/passwd.rs +++ b/src/shadow-core/src/passwd.rs @@ -359,7 +359,7 @@ mod tests { let path = dir.path().join("passwd"); std::fs::write(&path, "").unwrap(); let entries = read_passwd_file(&path).unwrap(); - assert!(entries.is_empty()); + assert!(entries.is_empty(), "{entries:?}"); } // ------------------------------------------------------------------- diff --git a/src/shadow-core/src/shadow.rs b/src/shadow-core/src/shadow.rs index a3b5dfe..e8a5996 100644 --- a/src/shadow-core/src/shadow.rs +++ b/src/shadow-core/src/shadow.rs @@ -565,7 +565,7 @@ mod tests { let path = dir.path().join("shadow"); std::fs::write(&path, "").unwrap(); let entries = read_shadow_file(&path).unwrap(); - assert!(entries.is_empty()); + assert!(entries.is_empty(), "{entries:?}"); } // ------------------------------------------------------------------- diff --git a/src/shadow-core/src/subid.rs b/src/shadow-core/src/subid.rs index 3a4cf09..12b6a3b 100644 --- a/src/shadow-core/src/subid.rs +++ b/src/shadow-core/src/subid.rs @@ -203,7 +203,7 @@ mod tests { let path = dir.path().join("subuid"); std::fs::write(&path, "").unwrap(); let entries = read_subid_file(&path).unwrap(); - assert!(entries.is_empty()); + assert!(entries.is_empty(), "{entries:?}"); } #[test] diff --git a/src/uu/chgpasswd/src/chgpasswd.rs b/src/uu/chgpasswd/src/chgpasswd.rs index fbce623..2194059 100644 --- a/src/uu/chgpasswd/src/chgpasswd.rs +++ b/src/uu/chgpasswd/src/chgpasswd.rs @@ -604,7 +604,7 @@ mod tests { assert_eq!(entries[0].passwd, "$6$new"); // The new line inherits the membership /etc/group already records. assert_eq!(entries[0].members, members); - assert!(entries[0].admins.is_empty()); + assert!(entries[0].admins.is_empty(), "{:?}", entries[0].admins); } // ----------------------------------------------------------------------- diff --git a/src/uu/chsh/src/chsh.rs b/src/uu/chsh/src/chsh.rs index f1b25bd..6e41429 100644 --- a/src/uu/chsh/src/chsh.rs +++ b/src/uu/chsh/src/chsh.rs @@ -428,7 +428,7 @@ mod tests { let dir = tempfile::tempdir().expect("tempdir"); let path = dir.path().join("nonexistent"); let shells = read_shells(&path).expect("read_shells"); - assert!(shells.is_empty()); + assert!(shells.is_empty(), "{shells:?}"); } #[test] @@ -437,7 +437,7 @@ mod tests { let path = dir.path().join("shells"); std::fs::write(&path, "").expect("write"); let shells = read_shells(&path).expect("read_shells"); - assert!(shells.is_empty()); + assert!(shells.is_empty(), "{shells:?}"); } // ----------------------------------------------------------------------- diff --git a/src/uu/gpasswd/src/gpasswd.rs b/src/uu/gpasswd/src/gpasswd.rs index da9a8f2..36c7de1 100644 --- a/src/uu/gpasswd/src/gpasswd.rs +++ b/src/uu/gpasswd/src/gpasswd.rs @@ -689,8 +689,12 @@ mod tests { parse_user_list("a, b ,c"), vec!["a".to_string(), "b".to_string(), "c".to_string()] ); - assert!(parse_user_list("").is_empty()); - assert!(parse_user_list(",,").is_empty()); + assert!(parse_user_list("").is_empty(), "{:?}", parse_user_list("")); + assert!( + parse_user_list(",,").is_empty(), + "{:?}", + parse_user_list(",,") + ); } #[test] diff --git a/src/uu/login/src/login.rs b/src/uu/login/src/login.rs index bfd7a6a..8934549 100644 --- a/src/uu/login/src/login.rs +++ b/src/uu/login/src/login.rs @@ -852,7 +852,7 @@ mod tests { assert_eq!(c.tty_perm, 0o600); assert_eq!(c.tty_group, "tty"); assert!(c.default_home); - assert!(c.motd_files.is_empty()); + assert!(c.motd_files.is_empty(), "{:?}", c.motd_files); let c = Config::from_defs(&defs( "LOGIN_RETRIES 5\nLOGIN_TIMEOUT 0\nTTYPERM 0620\nDEFAULT_HOME no\nMOTD_FILE /etc/motd:/run/motd\nLOGIN_PLAIN_PROMPT yes\nFAIL_DELAY 4\n", diff --git a/src/uu/newusers/src/newusers.rs b/src/uu/newusers/src/newusers.rs index ce85c19..00876ed 100644 --- a/src/uu/newusers/src/newusers.rs +++ b/src/uu/newusers/src/newusers.rs @@ -625,9 +625,9 @@ mod tests { fn test_all_optional_fields_may_be_empty() { let line = parse_line("alice:pw:::::", 1).expect("parses"); assert_eq!(line.name, "alice"); - assert!(line.uid.is_empty()); - assert!(line.gid.is_empty()); - assert!(line.home.is_empty()); + assert!(line.uid.is_empty(), "{:?}", line.uid); + assert!(line.gid.is_empty(), "{:?}", line.gid); + assert!(line.home.is_empty(), "{:?}", line.home); } fn line(spec: &str) -> Line { diff --git a/src/uu/pwconv/src/pwconv.rs b/src/uu/pwconv/src/pwconv.rs index 3663658..5ecb150 100644 --- a/src/uu/pwconv/src/pwconv.rs +++ b/src/uu/pwconv/src/pwconv.rs @@ -598,7 +598,7 @@ mod tests { reconcile_gshadow(&mut gr, &mut gs); assert_eq!(gr[0].passwd, "x"); assert_eq!(gs[0].passwd, "$6$t$t"); - assert!(gs[0].admins.is_empty()); + assert!(gs[0].admins.is_empty(), "{:?}", gs[0].admins); assert_eq!(gs[0].members, vec!["alice".to_string(), "bob".to_string()]); } diff --git a/tests/by-util/test_expiry.rs b/tests/by-util/test_expiry.rs index 9b6b894..4b6ccd9 100644 --- a/tests/by-util/test_expiry.rs +++ b/tests/by-util/test_expiry.rs @@ -105,7 +105,11 @@ fn test_locked_is_silent() { let dir = prefix("root:!$6$x$y:0:0:1:7:::"); let out = expiry(&dir, &["-c"]); out.assert_code(0); - assert!(out.stdout.is_empty()); + assert!( + out.stdout.is_empty(), + "{}", + String::from_utf8_lossy(&out.stdout) + ); } /// No shadow line for the caller: no policy to enforce. From bae540e0001653810d595bc38515dfbfca5ca7f8 Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Mon, 5 Oct 2026 10:50:20 +0200 Subject: [PATCH 4/4] tests: the expiry output is already a string --- tests/by-util/test_expiry.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/by-util/test_expiry.rs b/tests/by-util/test_expiry.rs index 4b6ccd9..33a8772 100644 --- a/tests/by-util/test_expiry.rs +++ b/tests/by-util/test_expiry.rs @@ -105,11 +105,7 @@ fn test_locked_is_silent() { let dir = prefix("root:!$6$x$y:0:0:1:7:::"); let out = expiry(&dir, &["-c"]); out.assert_code(0); - assert!( - out.stdout.is_empty(), - "{}", - String::from_utf8_lossy(&out.stdout) - ); + assert!(out.stdout.is_empty(), "{:?}", out.stdout); } /// No shadow line for the caller: no policy to enforce.