* 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.
6.1 KiB
Clean-room compliance audit — 2026-05-04
This document records the results of an automated clean-room audit run
against src/uu/**/*.rs and src/shadow-core/**/*.rs. It is preserved as
evidence of the project's clean-room posture against GNU shadow-utils
(GPL-2.0+).
Why an audit at all
The project's clean-room policy (CONTRIBUTING.md) forbids reading
shadow-maint/shadow source.
That guarantees no commit ever derives from upstream — but it cannot, by
itself, prove the absence of accidental similarity in user-facing strings
(error messages, clap flag-help, --help text). This audit is the
evidence side of the policy: independent verification that no string in
the tree is a verbatim copy of upstream wording.
Protocol
The audit was performed by an LLM with the shadow-maint/shadow source
code in its training corpus, run from a clean-room driver outside the
repository's working tree. The protocol guarantees no upstream content
crosses back into the repository:
- Output schema — the LLM's response was constrained to a strict
JSON Schema admitting only
{file, line, verdict, confidence, category}per finding plus a length-cappednotesfield. The schema literally has no field where a GNU-shadow string could land. - Verdicts — five labels:
verbatim,near-paraphrase,idiomatic,independent,abstain. Confidence in{high, medium, low}. - Sandbox — the tool ran with
--ephemeral --sandbox workspace-writeand was instructed not to clone, fetch, or webfetch shadow-maint/shadow or any GNU shadow-utils mirror. - Output channel — only the schema-validated JSON message was
captured. The progress log was scanned for
shadow-maint,github.com/shadow,apt-get source,git clone,wget,curl— no command invocations targeted upstream. - Provenance — the only "shadow" URLs that appeared in the log were
the prompt's own warning text and our own
https://github.com/uutils/shadow-rsconstant.
The model's task was to classify every user-facing string literal in the
listed files (clap .help/.about/.long_about/.override_usage/.after_help,
uucore::show_error!, eprintln!/println!, writeln!(io::stderr/stdout),
panic!/unreachable!) without ever quoting upstream. If unable to
classify without quoting, it was instructed to emit abstain.
Results
| Verdict | Count | Share |
|---|---|---|
| verbatim | 0 | 0.0% |
| near-paraphrase | 134 | 27.6% |
| idiomatic | 218 | 44.9% |
| independent | 62 | 12.8% |
| abstain | 72 | 14.8% |
| total examined | 486 |
Headline: 0 verbatim matches.
Triage of the 134 near-paraphrases
-
16 high-confidence all fall under the behavioral-compatibility carve-out — output strings that scripts grep for and where the project explicitly commits to drop-in compat with GNU shadow (
CONTRIBUTING.mdDesign Goals: "Drop-in replacement: same flags, same exit codes, same output format as GNU shadow-utils"). Distribution:chage -laging-info column headings —src/uu/chage/src/chage.rslines 442, 466–480 (the function comment itself reads "Print the aging information in the GNUchage -lformat").pwckdiagnostic output —src/uu/pwck/src/pwck.rslines 385, 478, 504, 510, 519.grpckdiagnostic output —src/uu/grpck/src/grpck.rslines 209, 251, 261.
Under the merger doctrine, copyright does not attach to expression dictated by external function (here: drop-in compat). These were retained as-is — divergence would be a regression, not a fix.
-
118 medium-confidence were clap flag-help and
.about(...)strings across all 14 tools. The model could not commit to "high" because flag-help wording is close to upstreammanpages and verifying that would require quoting. All 118 were rewritten in this pass to remove residual GNU-shadow-style phrasing, working only from our own source (the existing flag name, the actual behavior in the code).
Triage of the 72 abstains
The model declined to classify these — typically because they are
domain-specific format strings that overlap with similar implementations
generally, and the model was unwilling to commit either way without
quoting. They live mostly in src/shadow-core/src/{validate,crypt,error}.rs
and the show_error! paths of the user tools. None of them is a
verbatim risk; all use composable phrasing typical of error-handling
idiom.
Methodology integrity checks
- The schema-validated output passed Draft-2020-12 JSON-Schema validation with zero errors.
- All 30 file paths referenced in findings exist in the working tree.
- Every line number is within the bounds of the file it references — no hallucinated locations.
- The audit was run with
model_reasoning_effort=highto avoid shallow-model false negatives.
Bottom line
| Question | Answer |
|---|---|
| Verbatim copies of GNU shadow strings in tree? | 0 in 486 strings examined |
| Real paraphrase-rewrite surface? | 118 strings, all rewritten in this commit |
| Compatibility carve-out strings? | 16 retained intentionally |
| GPL strings leaked through audit? | None (schema-constrained, log-verified) |
The project's clean-room posture is intact. The 118 rewritten strings remove the only material residual-similarity surface that did not fall under the drop-in-compat carve-out.
Re-running this audit
The audit is reproducible. The protocol parameters are:
- Strict JSON Schema for the LLM's response (no field can carry upstream content).
- Sandbox/ephemeral mode; explicit prompt forbidding clone/fetch/webfetch of shadow-maint or any GNU shadow source package.
- Post-run scan of the tool's command log for upstream URLs / source-fetch commands.
- Schema-validate the final output before consuming it.
Future audits should be filed as docs/CLEAN-ROOM-AUDIT-YYYY-MM-DD.md.