From 86eb48de44c6d544f68c98a74f29768870800459 Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Fri, 3 Apr 2026 14:44:59 +0200 Subject: [PATCH 1/4] meta: align Cargo.toml metadata with uutils conventions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix root package edition (2021 → workspace 2024) - Use workspace inheritance for license, authors, repository, rust-version - Fix keywords: "coreutils" → "shadow-utils", add "uutils" - Add homepage, keywords, categories to workspace.package - Add workspace metadata inheritance to all 15 crate Cargo.toml files - Normalize tool descriptions to "tool ~ (shadow-rs) verb phrase" format - Add feat_common_core feature alias (groups all 14 tools) - Fix pre-existing clippy and fmt issues from edition 2024 alignment --- Cargo.toml | 16 +++++++++++----- src/bin/completions.rs | 2 +- src/shadow-core/Cargo.toml | 6 +++++- src/uu/chage/Cargo.toml | 6 +++++- src/uu/chfn/Cargo.toml | 6 +++++- src/uu/chpasswd/Cargo.toml | 6 +++++- src/uu/chsh/Cargo.toml | 6 +++++- src/uu/groupadd/Cargo.toml | 6 +++++- src/uu/groupdel/Cargo.toml | 6 +++++- src/uu/groupmod/Cargo.toml | 6 +++++- src/uu/grpck/Cargo.toml | 6 +++++- src/uu/newgrp/Cargo.toml | 6 +++++- src/uu/passwd/Cargo.toml | 6 +++++- src/uu/pwck/Cargo.toml | 6 +++++- src/uu/useradd/Cargo.toml | 6 +++++- src/uu/userdel/Cargo.toml | 6 +++++- src/uu/usermod/Cargo.toml | 6 +++++- tests/by-util/test_passwd.rs | 18 +++++++++--------- 18 files changed, 96 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad21932..ec965e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,13 +3,15 @@ [package] name = "shadow-rs" version = "0.0.1" -edition = "2021" -license = "MIT" +edition.workspace = true +rust-version.workspace = true +license.workspace = true +authors.workspace = true +repository.workspace = true description = "Memory-safe Rust reimplementation of Linux shadow-utils" -repository = "https://github.com/shadow-utils-rs/shadow-rs" readme = "README.md" -keywords = ["coreutils", "shadow", "passwd", "useradd", "linux"] -categories = ["command-line-utilities", "os::unix-apis"] +keywords = ["shadow-utils", "uutils", "shadow", "passwd", "linux"] +categories = ["command-line-utilities"] [workspace] members = [ @@ -37,6 +39,9 @@ rust-version = "1.94.0" license = "MIT" authors = ["shadow-rs contributors"] repository = "https://github.com/shadow-utils-rs/shadow-rs" +homepage = "https://github.com/shadow-utils-rs/shadow-rs" +keywords = ["shadow-utils", "uutils", "shadow", "passwd", "linux"] +categories = ["command-line-utilities"] [workspace.dependencies] # Internal crates @@ -109,6 +114,7 @@ feat_phase1 = ["feat_passwd", "feat_pwck"] feat_phase2 = ["feat_useradd", "feat_userdel", "feat_usermod", "feat_chpasswd", "feat_chage"] feat_phase3 = ["feat_groupadd", "feat_groupdel", "feat_groupmod", "feat_grpck", "feat_chfn", "feat_chsh", "feat_newgrp"] feat_common = ["feat_phase1", "feat_phase2"] +feat_common_core = ["feat_phase1", "feat_phase2", "feat_phase3"] # PAM authentication (requires libpam-dev) pam = ["passwd/pam"] diff --git a/src/bin/completions.rs b/src/bin/completions.rs index 3761993..7d35924 100644 --- a/src/bin/completions.rs +++ b/src/bin/completions.rs @@ -16,8 +16,8 @@ //! Supported shells: bash, zsh, fish, elvish, powershell use clap::{Arg, ArgAction, Command}; -use clap_complete::generate; use clap_complete::Shell; +use clap_complete::generate; use std::io; fn get_tool_app(name: &str) -> Option { diff --git a/src/shadow-core/Cargo.toml b/src/shadow-core/Cargo.toml index a8c2e75..d577069 100644 --- a/src/shadow-core/Cargo.toml +++ b/src/shadow-core/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "Core library for shadow-rs: parsers, atomic file ops, locking, PAM integration" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "shadow-core ~ (shadow-rs) parsers, atomic file ops, locking, PAM" [lib] path = "src/lib.rs" diff --git a/src/uu/chage/Cargo.toml b/src/uu/chage/Cargo.toml index 64484cb..180169b 100644 --- a/src/uu/chage/Cargo.toml +++ b/src/uu/chage/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "chage command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "chage ~ (shadow-rs) change user password aging" [lib] path = "src/chage.rs" diff --git a/src/uu/chfn/Cargo.toml b/src/uu/chfn/Cargo.toml index caa126d..93d8ffd 100644 --- a/src/uu/chfn/Cargo.toml +++ b/src/uu/chfn/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "chfn command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "chfn ~ (shadow-rs) change user finger information" [lib] path = "src/chfn.rs" diff --git a/src/uu/chpasswd/Cargo.toml b/src/uu/chpasswd/Cargo.toml index 15a0821..7dad5a3 100644 --- a/src/uu/chpasswd/Cargo.toml +++ b/src/uu/chpasswd/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "chpasswd command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "chpasswd ~ (shadow-rs) update passwords in batch" [lib] path = "src/chpasswd.rs" diff --git a/src/uu/chsh/Cargo.toml b/src/uu/chsh/Cargo.toml index b003d27..9532d2f 100644 --- a/src/uu/chsh/Cargo.toml +++ b/src/uu/chsh/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "chsh command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "chsh ~ (shadow-rs) change user login shell" [lib] path = "src/chsh.rs" diff --git a/src/uu/groupadd/Cargo.toml b/src/uu/groupadd/Cargo.toml index 3a1ba4b..c87f409 100644 --- a/src/uu/groupadd/Cargo.toml +++ b/src/uu/groupadd/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "groupadd command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "groupadd ~ (shadow-rs) create a new group" [lib] path = "src/groupadd.rs" diff --git a/src/uu/groupdel/Cargo.toml b/src/uu/groupdel/Cargo.toml index 8a9a238..3312cef 100644 --- a/src/uu/groupdel/Cargo.toml +++ b/src/uu/groupdel/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "groupdel command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "groupdel ~ (shadow-rs) delete a group" [lib] path = "src/groupdel.rs" diff --git a/src/uu/groupmod/Cargo.toml b/src/uu/groupmod/Cargo.toml index 2f04c03..79079c8 100644 --- a/src/uu/groupmod/Cargo.toml +++ b/src/uu/groupmod/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "groupmod command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "groupmod ~ (shadow-rs) modify a group" [lib] path = "src/groupmod.rs" diff --git a/src/uu/grpck/Cargo.toml b/src/uu/grpck/Cargo.toml index 7bd78cc..5aeaf33 100644 --- a/src/uu/grpck/Cargo.toml +++ b/src/uu/grpck/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "grpck command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "grpck ~ (shadow-rs) verify integrity of group files" [lib] path = "src/grpck.rs" diff --git a/src/uu/newgrp/Cargo.toml b/src/uu/newgrp/Cargo.toml index 5ae6715..5d4828e 100644 --- a/src/uu/newgrp/Cargo.toml +++ b/src/uu/newgrp/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "newgrp command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "newgrp ~ (shadow-rs) change effective group ID" [lib] path = "src/newgrp.rs" diff --git a/src/uu/passwd/Cargo.toml b/src/uu/passwd/Cargo.toml index 1a393ca..116c145 100644 --- a/src/uu/passwd/Cargo.toml +++ b/src/uu/passwd/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "passwd command — change user password (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "passwd ~ (shadow-rs) change user password" [lib] path = "src/passwd.rs" diff --git a/src/uu/pwck/Cargo.toml b/src/uu/pwck/Cargo.toml index 16f499b..bd08e5a 100644 --- a/src/uu/pwck/Cargo.toml +++ b/src/uu/pwck/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "pwck command — verify integrity of password files (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "pwck ~ (shadow-rs) verify integrity of password files" [lib] path = "src/pwck.rs" diff --git a/src/uu/useradd/Cargo.toml b/src/uu/useradd/Cargo.toml index 50585a1..568d30a 100644 --- a/src/uu/useradd/Cargo.toml +++ b/src/uu/useradd/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "useradd command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "useradd ~ (shadow-rs) create a new user" [lib] path = "src/useradd.rs" diff --git a/src/uu/userdel/Cargo.toml b/src/uu/userdel/Cargo.toml index 30179a5..fe50486 100644 --- a/src/uu/userdel/Cargo.toml +++ b/src/uu/userdel/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "userdel command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "userdel ~ (shadow-rs) delete a user account" [lib] path = "src/userdel.rs" diff --git a/src/uu/usermod/Cargo.toml b/src/uu/usermod/Cargo.toml index e1df2f9..bca6c06 100644 --- a/src/uu/usermod/Cargo.toml +++ b/src/uu/usermod/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true -description = "usermod command (shadow-rs)" +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +rust-version.workspace = true +description = "usermod ~ (shadow-rs) modify a user account" [lib] path = "src/usermod.rs" diff --git a/tests/by-util/test_passwd.rs b/tests/by-util/test_passwd.rs index e7583ca..8238367 100644 --- a/tests/by-util/test_passwd.rs +++ b/tests/by-util/test_passwd.rs @@ -428,15 +428,15 @@ fn test_gnu_compat_status_output() { // Verify our format matches by parsing a shadow entry and formatting it let shadow_path = std::path::Path::new("/etc/shadow"); - if let Ok(entries) = shadow_core::shadow::read_shadow_file(shadow_path) { - if let Some(entry) = entries.iter().find(|e| e.name == "root") { - let our_status = entry.status_char(); - assert_eq!( - our_status, gnu_fields[1], - "status char mismatch: ours={our_status}, GNU={}", - gnu_fields[1] - ); - } + if let Ok(entries) = shadow_core::shadow::read_shadow_file(shadow_path) + && let Some(entry) = entries.iter().find(|e| e.name == "root") + { + let our_status = entry.status_char(); + assert_eq!( + our_status, gnu_fields[1], + "status char mismatch: ours={our_status}, GNU={}", + gnu_fields[1] + ); } } From 95d2b2478af49b55e3e94c73a7904bc83077050f Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Fri, 3 Apr 2026 14:45:17 +0200 Subject: [PATCH 2/4] docs: add CI/MSRV badges, fix stale reference - Add CI and MSRV badges to README - Remove "(when created)" from CODE_OF_CONDUCT.md reference in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- README.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9263ae3..660b6e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ everything you need to know. Before you start, also check: -- [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) (when created) +- [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) - [SECURITY.md](./SECURITY.md) for vulnerability reporting > [!WARNING] diff --git a/README.md b/README.md index 1f5d257..824d492 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ # shadow-rs [![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/shadow-utils-rs/shadow-rs/blob/main/LICENSE) +[![CI](https://github.com/shadow-utils-rs/shadow-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/shadow-utils-rs/shadow-rs/actions/workflows/ci.yml) +[![MSRV](https://img.shields.io/badge/MSRV-1.94.0-blue)](https://github.com/shadow-utils-rs/shadow-rs) From 5a457b8781791b071ca52eeadde147133f1fe516 Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Fri, 3 Apr 2026 14:45:43 +0200 Subject: [PATCH 3/4] ci: add Docker multi-distro tests, renovate, rust-toolchain - Add Docker test matrix (debian/alpine/fedora) to GitHub Actions CI - Add renovate.json for automated dependency updates - Add rust-toolchain.toml for contributor convenience --- .github/workflows/ci.yml | 10 ++++++++++ renovate.json | 5 +++++ rust-toolchain.toml | 3 +++ 3 files changed, 18 insertions(+) create mode 100644 renovate.json create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a9692e..c585a01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,3 +58,13 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: EmbarkStudios/cargo-deny-action@v2 + + test-docker: + name: Test (${{ matrix.target }}) + runs-on: ubuntu-latest + strategy: + matrix: + target: [debian, alpine, fedora] + steps: + - uses: actions/checkout@v4 + - run: docker compose run --rm ${{ matrix.target }} cargo test --workspace diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..b42c4fb --- /dev/null +++ b/renovate.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "config:recommended" + ] +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..73cb934 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "stable" +components = ["rustfmt", "clippy"] From fdb6d46a05d8cb27dbe7bf99f0b4c18127eba19f Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Fri, 3 Apr 2026 15:01:26 +0200 Subject: [PATCH 4/4] review: address 2 Copilot review comments - Add homepage.workspace to root package (missing vs subcrates) - Gate Docker test-docker job to push only (seccomp:unconfined and SYS_ADMIN are unsafe for untrusted PR contexts) --- .github/workflows/ci.yml | 1 + Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c585a01..95fd3fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,6 +61,7 @@ jobs: test-docker: name: Test (${{ matrix.target }}) + if: github.event_name == 'push' runs-on: ubuntu-latest strategy: matrix: diff --git a/Cargo.toml b/Cargo.toml index ec965e6..9cd0b68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ rust-version.workspace = true license.workspace = true authors.workspace = true repository.workspace = true +homepage.workspace = true description = "Memory-safe Rust reimplementation of Linux shadow-utils" readme = "README.md" keywords = ["shadow-utils", "uutils", "shadow", "passwd", "linux"]