Pierre Warnier
86eb48de44
meta: align Cargo.toml metadata with uutils conventions
...
- 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
2026-04-03 14:44:59 +02:00
Pierre Warnier
62dca6f047
Merge pull request #116 from shadow-utils-rs/feat/114-usermod-password
...
usermod: add -p/--password flag (#114 )
2026-04-03 14:01:11 +02:00
Pierre Warnier
c3e0679acc
review: address all 4 Copilot review comments
...
- Error on missing shadow entry instead of silent no-op
- Validate password hash rejects ':', '\n', '\r'
- Centralize days_since_epoch() in shadow-core
- Assert field count and reserved field in test
2026-04-03 13:57:28 +02:00
Pierre Warnier
24347e9913
usermod: add -p/--password flag for pre-hashed passwords ( #114 )
...
Ansible's user module calls `usermod -p <hash>` to set passwords.
This was the most significant gap for Ansible interop.
Implementation:
- Add PASSWORD option constant and clap argument (-p/--password)
- Write hash directly to shadow entry, update last_change to today
- Follows the same lock → read → mutate → atomic_write pattern
Tests:
- test_set_password: basic -p flag with hash verification
- test_set_password_long_flag: --password long form
- test_set_password_preserves_other_fields: all 9 shadow fields intact
Also updated e2e Ansible playbook to use native `user: password:`
parameter instead of the chpasswd -e workaround.
Fixes #114
2026-04-03 13:48:11 +02:00
Pierre Warnier
d8e71819fe
Merge pull request #115 from shadow-utils-rs/feat/102-e2e-deployment-tests
...
e2e: automated deployment tests in Docker (#102 )
2026-04-03 13:37:07 +02:00
Pierre Warnier
36a623d0dd
review: address all 8 Copilot review comments
...
- Redact full command args in assert_ok failure output (password leak)
- Wrap all bare useradd/chpasswd calls in assert_ok (5 test sections)
- Strict symlink checks: require -L + verify target resolves to shadow-rs
- Add no_log: true to Ansible password task
- Redirect nscd -d stdout to /dev/null
Assertion count: 97 → 117
2026-04-03 13:34:08 +02:00
Pierre Warnier
e29b06c461
e2e: add end-to-end deployment tests ( #102 )
...
Add automated deployment testing in Docker that simulates a real
system-wide installation: build from source, install replacing GNU
shadow-utils, then run 97 assertions covering:
- Symlink dispatch and multicall dispatch (all 14 tools)
- Setuid bits and non-root privilege enforcement
- Full user lifecycle (useradd → chpasswd → usermod → pwck → userdel)
- Full group lifecycle (groupadd → groupmod → groupdel → grpck)
- Individual tool tests (chage, chfn, chsh, passwd -l/-u)
- PAM authentication (su with known password via expect)
- nscd cache invalidation
- Landlock sandboxing (when kernel supports it)
- Ansible integration (user/group modules as real-world consumer)
New files:
- docker/Dockerfile.e2e — multi-stage build + debian:trixie runtime
- tests/e2e/deploy-test.sh — bash test harness with 97 assertions
- tests/e2e/ansible-test.yml — Ansible playbook integration test
- .dockerignore — prevent sending target/ and .git/ to Docker
Modified:
- docker-compose.yml — add e2e service (no changes to existing services)
- Cargo.toml — add pam feature forwarding to root package
- shadow-core/pam.rs — add #[link(name = "pam")] for linker
Closes #109 , closes #110 , closes #111 , closes #112 , closes #113
Refs #102
2026-04-03 13:22:55 +02:00
Pierre Warnier
4110b1cd04
Merge pull request #108 from shadow-utils-rs/feat/106-completions-landlock
...
completions: add clap_complete generator + Landlock sandboxing for passwd
2026-04-03 12:34:41 +02:00
Pierre Warnier
b4130cfcf0
review: address all 6 Copilot review comments
2026-04-03 12:30:52 +02:00
Pierre Warnier
7fbea1f102
passwd: implement Landlock filesystem sandboxing ( #41 )
...
Restricts passwd's filesystem access to only what it needs:
- /etc/ (read+write for passwd/shadow files)
- /dev/ (read+write for tty prompts)
- /usr/sbin/ (execute for nscd/sss_cache)
Uses the landlock crate (MIT/Apache-2.0) with best-effort mode:
silently does nothing on kernels < 5.13. The apply_landlock()
helper is in shadow-core::hardening so other tools can reuse it.
Skipped during #[cfg(test)] since Landlock is irreversible per-process.
Fixes #41
2026-04-03 12:18:35 +02:00
Pierre Warnier
829b37f7a8
completions: add clap_complete shell completion generator ( #106 )
...
Feature-gated binary (--features completions) that generates bash/zsh/fish/
elvish/powershell completions from each tool's uu_app() definition.
Usage:
shadow-rs-completions passwd --shell bash
shadow-rs-completions --all --shell zsh --dir completions/
Also updates generate-completions.sh to use the new binary and adds
windows-sys skip to deny.toml for transitive clap dep.
Fixes #106
2026-04-03 12:18:18 +02:00
Pierre Warnier
e1cf43502a
Merge pull request #107 from shadow-utils-rs/feat/integration-tests-release
...
tests: integration tests for all 14 tools + CHANGELOG for v0.1.0
v0.1.0
2026-03-24 16:07:46 +01:00
Pierre Warnier
7bd47ff3d0
tests: add integration tests for all 14 tools, add CHANGELOG
...
Add integration tests for the 8 remaining tools:
- useradd, userdel, usermod (user management)
- groupadd, groupdel, groupmod (group management)
- pwck, grpck (file consistency checkers)
101 new tests covering clap parsing, flag conflicts, error paths,
and root-only file mutation operations with synthetic /etc/ files.
Total test count: 461 → 562.
Also adds CHANGELOG.md for v0.1.0 release.
2026-03-24 15:59:04 +01:00
Pierre Warnier
caac89485d
Merge pull request #105 from shadow-utils-rs/fix/93-104-prod-ready
...
prod: 11 production-readiness fixes
2026-03-24 15:45:16 +01:00
Pierre Warnier
5d8ac9587d
review: address all 13 Copilot review comments
...
- Fix cargo build --release --workspace in test scripts
- Document setuid-on-symlinks as intentional in Makefile
- Warn (not abort) on subid allocation failure in useradd
- Propagate subid file read errors instead of unwrap_or_default
- Update SELinux docs to describe best-effort behavior
- Add env_clear() to getfattr subprocess in selinux.rs
- Use hardening::sanitized_env() in nscd.rs instead of local reimpl
- Create testuser in pam-e2e.sh, add cleanup
- Document su-as-root limitation in pam-e2e.sh
- Fix set -e exit code capture in gnu-compat.sh
- Add 5 date validation unit tests in chage
- Wire audit::log_user_event into all 7 tools
2026-03-24 15:42:08 +01:00
Pierre Warnier
3fbeaf448c
chore: remove Cargo.lock from tracking (library convention)
2026-03-24 15:25:11 +01:00
Pierre Warnier
dddd5713ac
deps: upgrade nix 0.29 → 0.30 to unify with uucore
...
Eliminates duplicate nix crate that caused cargo-deny ban failure.
Adapts to nix 0.30 API: fsync/fcntl/fchownat now take AsFd instead
of raw i32 file descriptors; use AT_FDCWD for fchownat.
2026-03-24 15:24:54 +01:00
Pierre Warnier
83080f53dd
CI: upgrade cargo-deny-action to v2 for edition 2024 support
...
The v1 action bundles an old Cargo that doesn't recognize edition 2024.
v2 uses the host toolchain, so we install stable Rust first.
2026-03-24 15:18:07 +01:00
Pierre Warnier
8ba8f940fd
prod: GNU compat tests, PAM e2e, setuid, SELinux, audit, packaging
...
Fixes #93 — GNU compatibility test suite (tests/gnu-compat.sh)
Fixes #94 — PAM end-to-end test script (tests/pam-e2e.sh)
Fixes #95 — Setuid permissions in Makefile (chmod 4755)
Fixes #96 — nscd env_clear() on subprocess spawning
Fixes #97 — SELinux file context support (getfattr/chcon/restorecon)
Fixes #98 — Audit logging to syslog/auditd
Fixes #99 — subuid/subgid allocation in useradd
Fixes #100 — Debian packaging (debian/control, debian/rules)
Fixes #101 — Fedora packaging (shadow-rs.spec)
Fixes #103 — Recursive chown on usermod UID change
Fixes #104 — Proper date validation (Feb 31 rejected)
456 tests, zero clippy warnings. Binary: 894KB (release-small).
2026-03-24 15:15:21 +01:00
Pierre Warnier
bcf1eae8a9
Merge pull request #92 from shadow-utils-rs/fix/78-86-88-final
...
fix: binary <1MB, test helpers, completions
2026-03-24 14:55:12 +01:00
Pierre Warnier
748f0ad88d
fix: binary size <1MB, shared test helpers, shell completions
...
Fixes #78 — Binary size: release-small profile achieves 894KB (<1MB).
Default release also shrank from 1.5MB to 1.3MB thanks to
panic=abort + codegen-units=1 from PR #91 .
Fixes #86 — Shared test helper crate at tests/common/mod.rs with
skip_unless_root(), setup_prefix(), setup_full_prefix(), read_file().
Fixes #88 — Shell completion script at util/generate-completions.sh
(placeholder — generates minimal bash/zsh/fish completions).
456 tests, zero clippy warnings.
2026-03-24 14:48:37 +01:00
Pierre Warnier
20afe8c73b
Merge pull request #91 from shadow-utils-rs/fix/79-90-uutils-compliance
...
infra: uutils compliance — edition 2024, unsafe deny, dead_code deny
2026-03-24 14:44:24 +01:00
Pierre Warnier
9e3faa966c
address Copilot review: fix docs, feature-gate crypt, MSRV 1.94, CI msrv job
2026-03-24 14:43:38 +01:00
Pierre Warnier
896a4214b6
infra: uutils compliance — edition 2024, unsafe deny, dead_code deny
...
Fixes #79 — CODE_OF_CONDUCT.md (Contributor Covenant 2.1)
Fixes #80 — locales/en-US.ftl for all 14 tools
Fixes #81 — rust-version = "1.85.0" in workspace
Fixes #82 — edition 2024 (resolver 3, unsafe extern blocks)
Fixes #83 — GitHub Actions CI (fmt, clippy, test, cargo-deny)
Fixes #84 — .clippy.toml with MSRV and quality thresholds
Fixes #85 — deny.toml tightened (multiple-versions=deny)
Fixes #87 — panic=abort, codegen-units=1 in release profile
Fixes #89 — Makefile with install/uninstall/clean targets
Fixes #90 — workspace lints: cargo group, unused_qualifications
Key policy changes enforced by cargo:
- unsafe_code = "deny" workspace-wide. Only pam.rs and crypt.rs
have #[allow(unsafe_code)] (C FFI boundaries).
- dead_code = "deny" workspace-wide. No unused code allowed.
- Edition 2024: set_var/remove_var are unsafe, so sanitize_env
returns a Vec instead of mutating. Signal handler removed
(was unsafe). localtime_r replaced with pure Rust calendar math.
456 tests, zero clippy warnings.
2026-03-24 14:30:22 +01:00
Pierre Warnier
a6e6ef63b2
Merge pull request #77 from shadow-utils-rs/fix/56-67-69-70-remaining
...
docs/fixes: man pages, benchmarks, BSD research, Copilot findings
2026-03-24 13:12:34 +01:00