Files
shadow/CONTRIBUTING.md
T
Pierre Warnier 3ed6188aea tests: add proptest, edge cases, fuzz targets, integration tests, docs
Fixes #11 — tests/by-util/test_passwd.rs: 15 integration tests
  following uutils convention (status format, exit codes, lock/unlock
  cycle, aging, lifecycle, quiet mode, error cases).

Fixes #12 — fuzz targets for all parsers:
  fuzz_passwd_parse, fuzz_shadow_parse, fuzz_login_defs_parse,
  fuzz_validate_username. All must not panic on any input.

Fixes #15 — proptest round-trip tests for PasswdEntry, ShadowEntry:
  generate random valid entries, serialize, parse back, compare.

Fixes #16 — parser edge case tests:
  wrong field counts, empty files, roundtrip via file I/O, negative
  values, boundary values, unicode rejection, null bytes, mixed
  whitespace, duplicate keys, key-only lines.

Also: CONTRIBUTING.md, SECURITY.md created. README.md and CLAUDE.md
updated to reflect uucore integration and current project state.

142 tests passing on Debian/Alpine/Fedora, zero clippy warnings.
2026-03-23 14:11:19 +01:00

4.9 KiB

Contributing to shadow-rs

Thanks for wanting to contribute to shadow-rs! This document explains everything you need to know.

Before you start, also check:

Warning

shadow-rs is original code and cannot contain any code from GNU shadow-utils or other GPL-licensed implementations. This means that we cannot accept any changes based on the shadow-maint/shadow source code (GPL-2.0+). To make sure that cannot happen, you must not read or link to the GNU source code. This includes paraphrasing or translating their logic, and feeding it into an LLM for translation.

Safe Reference Sources

When implementing a tool, reference ONLY these sources:

Source License Use
POSIX specification Open standard Behavioral spec
Man pages (man7.org) Documentation Command options, file formats
FreeBSD src BSD-2-Clause Implementation patterns
OpenBSD src ISC Implementation patterns
musl libc MIT pwd/grp/shadow C API
sudo-rs Apache-2.0 / MIT PAM, privilege-dropping

Process: Read the POSIX spec and man page for behavioral requirements, then write an original implementation. Never search for or view the C source.

Getting Started

Requirements

  • Docker and Docker Compose (all builds/tests run in containers)
  • Git

Setup

git clone https://github.com/shadow-utils-rs/shadow-rs
cd shadow-rs
docker compose build
./hooks/install.sh  # install pre-commit and pre-push hooks

Building and Testing

docker compose run --rm debian cargo build          # build
docker compose run --rm debian cargo test --workspace  # test on Debian
docker compose run --rm alpine cargo test --workspace  # test on Alpine (musl)
docker compose run --rm fedora cargo test --workspace  # test on Fedora (SELinux)

Linting

docker compose run --rm debian cargo clippy --workspace --all-targets -- -D warnings
docker compose run --rm debian cargo fmt --all --check

Design Goals

  • Drop-in replacement: same flags, same exit codes, same output format as GNU shadow-utils. Differences with GNU are treated as bugs.
  • uutils compatible: tools use uucore (UResult<()>, #[uucore::main], show_error!) so they can be merged into the uutils ecosystem.
  • Memory safe: no .unwrap(), no panic!, no std::process::exit in library code.
  • Well-tested: unit tests, proptest, integration tests, fuzz targets.

Our Rust Style

Don't panic!

Never use .unwrap() or panic!. Use unreachable! only with a justifying comment. Return errors via UResult<()>.

Don't exit

Utilities must be embeddable. Return UResult<()> from uumain. The uucore::bin!() macro handles process::exit in the generated main().

unsafe

Only for FFI (nix crate for syscalls, PAM crate for PAM). Every unsafe block must have a // SAFETY: comment explaining why it's sound.

str, OsStr & Path

Use OsStr and Path for filesystem paths. Only convert to String/str when you know the data is always valid UTF-8 (usernames, for example).

Comments

Comments explain why, not what. If you need to describe what code does, improve the naming instead.

Commits

  • Small, atomic commits — one logical change per commit
  • Tool-prefixed messages: passwd: fix buffer handling
  • Test commits: tests/passwd: add aging test
  • Do not move code in the same commit as a behavior change

Pull Requests

  • One issue per PR, reference it: Fixes #N
  • Title prefixed with tool name, under 70 characters
  • Branch naming: fix/N-short-description or feat/N-short-description
  • CI must pass (clippy, fmt, tests on all 3 distros)
  • Keep PRs small and self-contained

AI-Assisted Development

AI tools (Copilot, Claude, etc.) are allowed and treated like any other development tool.

  • All code must be understood, reviewed, and tested by human contributors
  • Clean-room rule is absolute — never feed GPL source into an LLM
  • Reference only: POSIX specs, man pages, BSD-licensed implementations
  • If a PR is substantially AI-generated, note it (transparency, not a blocker)
  • Quality is the gate — contributions are judged on correctness and test coverage, not authorship method

Licensing

shadow-rs is distributed under the terms of the MIT License.

Acceptable dependency licenses: MIT, Apache-2.0, ISC, BSD-2-Clause, BSD-3-Clause, CC0-1.0, Unicode-3.0, Zlib, MPL-2.0.

No GPL or LGPL dependencies, ever.