Contributing¶
This page is generated from the repository root CONTRIBUTING.md so the
published site and the repository stay in sync.
Contributing to paranoid-passwd¶
This is a guide for human contributors. Agent-facing protocols (the LLM clean-room checklist,
zero-exception rules, hallucination patterns) live in AGENTS.md and
CLAUDE.md — read those too if you are working on generation, crypto, or audit
math.
1. Dev Environment Setup¶
Start with the Makefile; it is the operator interface for this repo and the source of truth for every command below.
make configure
make configure (equivalently ./configure) runs scripts/configure_local_toolchain.sh and
writes .config/paranoid-local.mk (consumed by Make) and .config/paranoid-local.env (for
manual shell use). It detects the host platform, Cargo/Rustup, Docker, Xvfb/ImageMagick GUI
capture tools, Android SDK/NDK paths and NDK clang/ar/ranlib, adb, emulator, Maestro,
wasm-pack, and the installed Rust Android/WASM targets.
If you need the Android and WASM GUI targets installed, use:
make bootstrap-local
This installs the aarch64-linux-android and wasm32-unknown-unknown Rust targets with Rustup,
then reruns make configure.
To see what your machine was detected as:
make show-config
This prints .config/paranoid-local.summary, which tells you whether Docker, Android, and WASM
toolchains are ready before you rely on the targets that need them (test-gui-android-check,
test-gui-wasm-check, *-emulate targets).
Offline, vendored builds — and why¶
Every Cargo invocation in this repo runs --locked --frozen --offline against a vendored
dependency tree in vendor/, wired up by .cargo/config.toml:
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
--locked refuses to build if Cargo.lock would need to change. --frozen refuses to touch the
network or update the lockfile at all. --offline refuses network access outright. Together they
mean a build either reproduces exactly what’s committed or fails loudly — there is no path where
a dependency gets silently substituted or upgraded mid-build. This matters specifically because
this project treats its dependency tree (OpenSSL bindings, Argon2, statistical libraries) as part
of its security posture, not an implementation detail. Keep this invariant: do not add Cargo
commands that omit --locked --frozen --offline, and do not add dependencies without vendoring
them (cargo vendor) and updating vendor/.
2. Verification¶
make ci
make ci is the local equivalent of the repository’s CI gate. It runs, in order:
cargo fmt --checkcargo clippy --workspace --all-targets --locked --frozen --offline -- -D warningsbash scripts/cargo_test.sh --workspace --locked --frozen --offline(the full workspace test suite)make test-ops-mtls-transport(bash scripts/cargo_test.sh -p paranoid-ops --locked --frozen --offline --features mtls-transport)make test-cli-contract(builds the CLI, runstests/test_cli.shagainst it)make test-tui-e2e(builds the CLI, runstests/test_tui_e2e.py— a real PTY-driven TUI harness)the platform GUI e2e target, when the host is Linux (
test-gui-e2e) — skipped on other hostsmake test-gui-host-check(compile-check the host Slint GUI surface)make test-vault-e2e(builds the CLI, runstests/test_vault_cli.sh)make test-platform-signing-boundary(tests/test_platform_signing_verify.sh)make verify-assurance(hallucination checks, supply-chain checks, AI review inventory, security assurance gate — see below)python3 -m tox -e docs,docs-linkcheck(build the Sphinx docs site and check outbound links)
Run this before opening a PR. It is what CI itself runs.
Narrower per-crate commands¶
While iterating, you rarely need the full make ci gate. Use the crate-scoped Cargo commands
directly:
cargo build --workspace --locked --frozen --offline
cargo test -p paranoid-core --locked --frozen --offline
cargo test -p paranoid-cli --locked --frozen --offline
cargo check -p paranoid-gui --locked --frozen --offline
cargo fmt --check
cargo clippy --workspace --all-targets --locked --frozen --offline -- -D warnings
make quality for release candidates¶
make quality
This is the release-candidate gate, stricter than make ci. It runs, in order:
verify-deepwithPARANOID_STRICT_EXTERNAL_TOOLS=1 PARANOID_RUN_LOCAL_SCANNERS=1(missing optional scanners become fatal instead of just reported)the full
citargettest-gui-targets(host, Android, and WASM GUI compile checks)the platform-appropriate GUI visual-regression target —
test-gui-visual-regression-emulatethrough the builder image on macOS,test-gui-visual-regressionnatively on Linux
make verify-deep itself runs cargo run -p xtask --locked --frozen --offline -- verify-deep,
the Rust-native deep-check gate (Rust toolchain policy, locked offline Cargo metadata, workspace
license/source policy, ShellCheck on repo-owned shell scripts, Python syntax checks, tracked-file
secret scanning, and local security-scanner visibility).
There is also make quality-emulate, which runs the same release-candidate posture inside the
Wolfi builder image instead of the host — use it to reproduce what the builder-driven CI path
sees, including scanner tools that may not be installed locally. See
Testing for the full breakdown of what each quality gate covers.
3. Where Code Belongs¶
The workspace is seven crates plus an xtask dev-tooling crate. Each has one job:
Crate |
Owns |
|---|---|
Password generation, rejection sampling, OpenSSL-backed RNG/SHA-256, statistical audit math (chi-squared, serial correlation), pattern detection, compliance-framework checks |
|
The typed operation boundary for automation-facing generator/vault workflows — request/response envelopes, policy context |
|
Redacted structured audit events, JSONL sink health, federal-ready evidence |
|
Vault seal state machine and non-secret seal-provider posture |
|
Encrypted local vault storage, keyslots, item CRUD, backups, transfer packages, recovery posture |
|
The scriptable CLI and default TUI, consuming the crates above |
|
The Slint-native desktop GUI, consuming the same typed results |
Security-sensitive logic (RNG, hashing, KDF, audit math, rejection sampling) belongs in
paranoid-core only — never in the CLI, TUI, GUI, or docs tooling. See
CLAUDE.md for the full zero-exception list; the ones most relevant to code
placement:
Keep security-sensitive logic in
crates/paranoid-core.Do not reintroduce browser, WASM, or webview runtime surfaces as a secret-handling path.
Keep the rejection sampling boundary at
((256 / charset_len) * charset_len) - 1: this is the highest acceptable random byte value for the charset. Bytes greater than this value must be rejected and re-drawn to avoid modulo bias.Keep chi-squared pass logic at
p > 0.01and degrees of freedom atN - 1.Do not add
unsafeRust without explicit repository disposition and assurance-script coverage (scripts/hallucination_check.shscans for handwrittenunsafe; only Slint-generated code and exact audited platform ABI export attributes are exempt).Keep Cargo builds locked, frozen, offline, and backed by
vendor/.
If you are touching generation, crypto, KDF, or statistical audit code, read the LLM clean-room
checklist in AGENTS.md first — it lists exact hallucination patterns (off-by-one
rejection sampling, inverted p-value logic) this codebase has been burned by before.
4. Test Layers¶
Layer |
What it proves |
Command |
|---|---|---|
Unit ( |
Generation correctness, audit math known-answers, ops/audit/seal policy, vault CRUD and keyslot logic, TUI reducer behavior, GUI component bindings |
|
CLI contract |
The generator CLI’s documented flags and output against the real debug binary |
|
Vault CLI e2e |
Headless vault CRUD, filtering, |
|
TUI PTY e2e |
Real terminal keystrokes driving the generator wizard and vault TUI through the actual binary |
|
GUI checks |
Host compile-check, Android/WASM compile-checks, and a real GUI-binary workflow harness under Xvfb with a captured screenshot |
|
Platform signing boundary |
Release platform-signing verifier contract |
|
Assurance gate |
Hallucination checks, supply-chain checks, AI review inventory, security assurance protocol wiring |
|
make ci runs unit, the paranoid-ops mTLS transport integration tests, CLI contract, TUI PTY e2e,
the platform-appropriate GUI e2e, the GUI host check, vault e2e, platform signing boundary, and
the assurance gate, plus the docs build. make quality adds the full test-gui-targets matrix (host + Android + WASM) and GUI visual
regression. See docs/reference/testing.md for the complete,
current breakdown of what every test file and Make target covers.
5. Extension Points as They Exist Today¶
These are the compile-time Rust surfaces you extend today. There is no data-driven or plugin-style registry yet — a registry is planned future work, not a promise this document is making. Extending any of these means editing Rust source in the owning crate, not registering a config file or external plugin.
Compliance frameworks —
FrameworkId(an enum) and theFRAMEWORKSconst array incrates/paranoid-core/src/lib.rs. EachComplianceFrameworkentry is a static struct literal (min_length,min_entropy_bits,require_mixed_case,require_digits,require_symbols). Adding a framework means adding an enum variant, aFrameworkId::parse/as_strarm, and aComplianceFrameworkentry inFRAMEWORKS— all in the same commit, sinceframework_by_idassumes the array is exhaustive over the enum (.expect("framework ids are static and exhaustive")).Charset presets —
resolve_charsetincrates/paranoid-core/src/lib.rs. Named presets (alnum,alnum-symbols,hex,full) arematcharms returning a built string; anything else falls through tovalidate_charsetas a literal charset. Adding a preset means adding amatcharm.Seal provider kinds —
VaultSealProviderKindincrates/paranoid-seal/src/lib.rs(PasswordRecovery,MnemonicRecovery,DeviceBound,CertificateWrapped,ExternalAutoUnseal). This enum drives seal posture reporting and theis_operator_recovery/is_certificate_unseal/is_auto_unsealclassification helpers that ops/audit policy checks against.Keyslot kinds —
VaultKeyslotKindincrates/paranoid-vault/src/lib.rs(PasswordRecovery,MnemonicRecovery,DeviceBound,CertificateWrapped). This is the persisted, serialized keyslot kind stored inVaultHeader.keyslots; it must stay aligned withVaultSealProviderKindinparanoid-sealsince seal posture is derived from configured keyslots.
Adding a variant to any of these enums touches every exhaustive match over it — the compiler
will find them, but expect changes to ripple through CLI argument parsing, TUI/GUI rendering, and
serialization (several of these enums have #[serde(rename_all = "snake_case")] and, in
VaultKeyslotKind, backward-compat #[serde(alias = ...)] entries for previously persisted
vault headers). Treat any new variant as a persisted-format change if it can appear in
VaultHeader.
6. PR Conventions¶
Use Conventional Commits (
feat:,fix:,chore:,docs:,refactor:,perf:,test:,ci:,build:) for every commit message. This repo runsrelease-please(seerelease-please-config.json) off the commit history — the prefix is what drivesCHANGELOG.mdand version bumps, so get it right.PRs are squash-merged. Write commit messages during development for readability; the PR title and squash-merge message are what actually lands on
mainand feeds the changelog, so make sure it accurately reflects the whole PR content, not just the last commit.Docs and tests move with the code that changes them in the same PR — do not defer doc updates to a follow-up. If you add or change a Make target, test file, or crate responsibility, update the corresponding section of
docs/reference/testing.mdand this file if relevant.Run
make cilocally before opening a PR; it is the same gate CI runs.