146 Commits

Author SHA1 Message Date
Pierre Warnier 04427511e1 docker: install cargo-deny as a pinned prebuilt binary (#175)
The dev images built cargo-deny from source via `cargo install cargo-deny`.
That compiled cargo-deny on every image build (multi-minute) and surfaced
cargo-deny's own `profile.dev.package.{insta,similar}` warnings, which look
like our config but are not.

Install the pinned (0.19.8), checksum-verified prebuilt binary instead. The
static musl build runs on glibc too, so all three images share one asset.
Result: no source compile, no spurious warnings, and a reproducible,
sha256-verified install (vs the previous unpinned `cargo install`). Each
build self-checks with `cargo-deny --version`.

Version/checksum are ARGs so they can be bumped (and tracked by Renovate).
2026-06-10 15:06:33 +02:00
Pierre Warnier 8e9324652b ci: polish the image-build retry loop (#174)
Address review feedback on #173:
- Don't sleep after the final build attempt (no retry follows it).
- Forward the workflow-wide CARGO_NET_RETRY into the container with a
  bare '-e CARGO_NET_RETRY' instead of re-hardcoding the value, keeping
  a single source of truth.
2026-06-10 12:45:14 +02:00
Pierre Warnier 4ce4184e38 ci: make the Docker test matrix resilient to registry flakes (#172) (#173)
The Test (debian/alpine/fedora) matrix failed four times in a row on
2026-06-10, each on a transient network error (Docker Hub base-image
pull i/o timeout; crates.io download broken pipe) unrelated to the code.

- fail-fast: false so one distro's flake no longer cancels the others.
- Retry 'docker compose build <target>' (the Docker Hub pull) with backoff.
- Pass CARGO_NET_RETRY into the container and set it for runner-native
  jobs so cargo retries crate downloads; real test failures still fail
  fast (no step-level retry around the test run).

No new third-party actions — a shell retry loop keeps the supply-chain
surface unchanged.

Closes #172.
2026-06-10 12:42:33 +02:00
Sylvestre Ledru 27daa7b7fe Merge pull request #170 from oech3/patch-1
README.md: strip -rs from project name
2026-06-10 10:20:19 +02:00
oech3 4274bac2d1 README.md: strip -rs from project name 2026-06-09 18:28:51 +09:00
Pierre Warnier d31c689b3f cli: identify shadow-rs as part of uutils (#161) (#162)
* cli: identify shadow-rs as part of uutils in --help and --version

Per #161, every tool now reports `(uutils shadow-rs) <ver>` in its
--version output and links to the project in --help via a shared
shadow_core::cli module.

While auditing the same uu_app() blocks for residual similarity to
GNU shadow-utils man-page phrasing, the medium-confidence findings
from a clean-room similarity check were also rewritten: 118 clap
.help() and .about() strings across all 14 tools now use phrasing
derived from the in-tree behavior of each flag, not from upstream
documentation.

Output strings that scripts grep for (chage -l column headings,
pwck/grpck diagnostic lines) were left intentionally untouched, since
drop-in compatibility is part of the project's contract.

- shadow-core: new cli module with VERSION and AFTER_HELP constants
- 14 tools: wire .version() and .after_help() in every uu_app()
- 14 tools: rewrite 118 flag-help and .about() strings
- shadow-rs multicall: handle --help/--version/-h/-V with project ID
- fmt + clippy + tests pass on debian, alpine, fedora (574 passed, 0 failed)

Closes #161

* docs: record clean-room audit results (2026-05-04)

Adds an evidence document for the clean-room similarity audit that
prompted the flag-help rewrite in the previous commit. Headline:
0 verbatim matches in 486 user-facing strings.

The audit protocol is reproducible and described in the doc, including
the schema-constrained output and post-run command-log scan that ensure
no upstream string crosses back into the workspace.

* cli: correct help/version text flagged in review

- multicall --version/--help now use the shared (uutils shadow-rs)
  identifier instead of (uutils), matching the tool crates; clarify the
  symlink invocation line in the help banner.
- --root help for the SysRoot tools (userdel, useradd, usermod, groupadd,
  groupdel, groupmod, pwck, grpck) no longer claims a chroot(2): these
  only resolve system files under a path prefix. Reword to match, and
  rename the metavar CHROOT_DIR -> ROOT_DIR.
- userdel --force: documented as accepted-for-compatibility (no effect)
  rather than promising behavior the code does not implement.
- groupadd -K: scope the help to the GID-range keys actually honored.
- passwd --repository: note only the local files backend is supported.
- passwd --stdin: reads password input generally (auth may consume the
  current password too), not just the new password.
- chpasswd -m: state that MD5 is rejected, not supported.
- usermod --append: restore the note that -a is only effective with -G.
- clean-room audit doc: cite CONTRIBUTING.md (the in-tree policy) instead
  of the gitignored CLAUDE.md.
2026-06-08 13:34:08 +02:00
Pierre Warnier ed578748e9 chore: gitignore AI review artifacts under docs/ (#169) 2026-06-08 13:34:05 +02:00
Daniel Hofstetter a1c06e39da ci: add .pre-commit-config.yaml (#164)
* ci: add .pre-commit-config.yaml

* Make debian/rules executable
2026-06-08 12:59:57 +02:00
Pierre Warnier 19af7be38d ci: commit Cargo.lock so cargo audit can run (#167) (#168)
The Security audit workflow runs `cargo audit --file ./Cargo.lock`, but
Cargo.lock was gitignored, so the file was absent in CI and every run
failed with "Couldn't load ./Cargo.lock" — including the daily scheduled
run on main. No advisory scan was ever performed.

Commit the lockfile and drop it from .gitignore. shadow-rs ships binaries
(the setuid-root tools), and committing the lockfile is the convention for
binary crates: it gives reproducible builds and a stable input for the
audit. The fuzz crate's lockfile stays ignored as throwaway tooling.

Closes #167.
2026-06-08 12:59:48 +02:00
oech3 21ac3d4437 shadow-core: use getrandom from rustix (#165)
to replace unsafe libc::getrandom

Co-authored-by: oech3 <>
2026-05-24 14:09:12 +02:00
renovate[bot] a47b357bc5 chore(deps): update debian docker tag to trixie-20260518 2026-05-20 09:01:23 +02:00
Pierre Warnier b24d19ab49 Merge pull request #156 from oech3/unreach
validate.rs: remove unreachable!()
2026-04-23 11:54:38 +02:00
Pierre Warnier befcac05fc Merge pull request #158 from uutils/fix/157-mkdir-mode
useradd, skel: set mkdir mode atomically to close world-writable window (#157)
2026-04-23 09:40:07 +02:00
Pierre Warnier 8b08f73000 useradd, skel: set mkdir mode atomically to close world-writable window (#157)
std::fs::create_dir(path) calls mkdir(path, 0o777) and the actual mode
is 0o777 & ~umask. With an attacker-controlled umask (inherited across
setuid since the kernel does not reset it), the directory exists with
permissive bits between mkdir and the subsequent set_permissions call.

Fix uses DirBuilder::mode(...).create(...) so the mode is set in the
syscall itself, wrapped in UmaskGuard::zero() to neutralize umask
interference. Same pattern applied to skel.rs for subdirectory and
file copies (file copies switch from fs::copy to OpenOptions::mode +
io::copy for the same reason).

Regression test asserts a process running with umask 0 still produces
a 0o700 home directory.

Reported by @collinfunk in uutils/coreutils#11828.
Fixes #157.
2026-04-23 09:31:26 +02:00
oech3 d50a3b65c0 validate.rs: Fix comment
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-23 16:08:30 +09:00
Pierre Warnier d341138086 changelog: add post-0.2.0 unreleased entries 2026-04-22 19:21:02 +02:00
Pierre Warnier 7c6cf221bc process: use rustix::param::linux_execfn instead of unsafe getauxval 2026-04-22 19:09:33 +02:00
oech3 224ddcb4b1 validate.rs: remove unreachable!() 2026-04-23 01:58:41 +09:00
Pierre Warnier 4ecf63ec1f security: AT_EXECFN validation + audit.yml (#154, #155)
#154: Reject setuid multicall invocations where argv[0] doesn't match
AT_EXECFN from the ELF auxiliary vector. Prevents an attacker from
spoofing argv[0] to route the multicall binary to a different tool
in setuid context. Only enforced when euid != uid.

#155: Add daily cargo-audit workflow matching uutils/coreutils pattern.
Also triggers on Cargo.toml/Cargo.lock changes.

Fixes #154. Fixes #155.
2026-04-22 18:13:36 +02:00
Pierre Warnier 86af8fc45b chore: align all versions to 0.2.0 2026-04-22 17:41:16 +02:00
Pierre Warnier 95f8f2d917 readme: fix license badge HTTP → HTTPS 2026-04-22 17:37:07 +02:00
Pierre Warnier 7703f28173 chore: remove generated file 2026-04-22 17:32:49 +02:00
Pierre Warnier 93eb852924 release: v0.2.0 — uutils adoption
First release under the uutils organization.

Highlights:
- Repo transferred to uutils/shadow-rs
- uucore upgraded to 0.8
- nix crate fully replaced by rustix
- Default install now uses standalone per-tool binaries with
  least-privilege setuid layout
- println!/eprintln! replaced with non-panicking writes
- Unwind tables suppressed in release builds
- NSS-backed user lookup via getpwuid_r
- 35+ security findings addressed across 6 review rounds
v0.2.0
2026-04-22 16:53:01 +02:00
Pierre Warnier 88f87a17d6 changelog: add uucore 0.8 upgrade, nix→rustix migration, org transfer 2026-04-22 16:36:09 +02:00
Pierre Warnier c4fcb7387d Merge pull request #150 from uutils/renovate/uucore-0.x
chore(deps): update rust crate uucore to 0.8
2026-04-22 16:35:38 +02:00