Files
shadow/CONTRIBUTING.md
Pierre Warnier 3e6dab9b18 docs: update all URLs from shadow-utils-rs to uutils org
Repo transferred to uutils/shadow-rs. Update all references:
- README.md: CI badge, license badge, clone URL
- Cargo.toml: repository, homepage
- CONTRIBUTING.md: clone URL
- SECURITY.md: advisory URL
- shadow-rs.spec: source URL
- CLAUDE.md: PR review API URLs, kanban board
2026-04-22 15:31:42 +02:00

143 lines
4.9 KiB
Markdown

<!-- spell-checker:ignore reimplementing setuid subuid subgid gshadow -->
# 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:
- [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md)
- [SECURITY.md](./SECURITY.md) for vulnerability reporting
> [!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](https://github.com/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](https://pubs.opengroup.org/onlinepubs/9799919799/) | Open standard | Behavioral spec |
| Man pages (man7.org) | Documentation | Command options, file formats |
| [FreeBSD src](https://cgit.freebsd.org/src/) | BSD-2-Clause | Implementation patterns |
| [OpenBSD src](https://cvsweb.openbsd.org/src/) | ISC | Implementation patterns |
| [musl libc](https://musl.libc.org/) | MIT | pwd/grp/shadow C API |
| [sudo-rs](https://github.com/trifectatechfoundation/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
```shell
git clone https://github.com/uutils/shadow-rs
cd shadow-rs
docker compose build
./hooks/install.sh # install pre-commit and pre-push hooks
```
### Building and Testing
```shell
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
```shell
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`
Denied at the workspace level (`unsafe_code = "deny"`). Only two FFI boundary
modules are exempted: `shadow_core::pam` (PAM C library) and `shadow_core::crypt`
(POSIX crypt(3)). Every `unsafe` block must have a `// SAFETY:` comment.
### `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](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.**