From f1abb0d2ef620eb7ea68350d4cde6d34fbed3bd8 Mon Sep 17 00:00:00 2001 From: Jacob Hagstedt Date: Mon, 19 Oct 2026 19:36:04 +0200 Subject: [PATCH] Server gate: cargo audit The server gate becomes cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo audit && cargo test (CLAUDE.md, server/README.md). The pre-commit hook runs cargo audit --no-fetch only when server/Cargo.lock or a server Cargo.toml is staged, and skips with a message when cargo-audit or the advisory database is missing. First run: 0 advisories, 0 warnings over 319 crates; no audit.toml needed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B --- CLAUDE.md | 4 ++-- server/README.md | 13 ++++++++++++- tools/git-hooks/pre-commit | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 200a461..4eeb461 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -94,14 +94,14 @@ Everything builds **locally on this MacBook**. No hosted CI, no remote build ser ../tools/gradle-serial.sh check # THE Android gate: build, unit tests, lint, architecture rules, screenshot tests ../tools/gradle-serial.sh installDebug # install the debug app on the attached phone # Server gate, from server/: -cargo fmt --check && cargo clippy -- -D warnings && cargo test # THE server gate +cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo audit && cargo test # THE server gate # Either directory: tools/install-git-hooks.sh # once per checkout tools/clean-builds.sh [--dry-run] # delete Gradle build output in every checkout and worktree (disk) python3 tools/dependency-report/latest.py # version drift of android/gradle/libs.versions.toml ``` -* **`tools/gradle-serial.sh check` (Android) and `cargo fmt --check && cargo clippy -- -D warnings && cargo test` (server) are the only gates.** Every check a plan asks for must be reachable from one of them (the OpenAPI match test and the test-vector tests included). Report gates with the real result lines (BUILD line, actionable tasks, test counts from fresh XML only). Never report a check as passing that you did not run in this session. +* **`tools/gradle-serial.sh check` (Android) and `cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo audit && cargo test` (server) are the only gates.** Every check a plan asks for must be reachable from one of them (the OpenAPI match test and the test-vector tests included). Report gates with the real result lines (BUILD line, actionable tasks, test counts from fresh XML only). Never report a check as passing that you did not run in this session. * **One Gradle build at a time.** Parallel builds exhaust memory. Always `tools/gradle-serial.sh`; it waits on a lock in `/tmp` and then runs `android/gradlew` of your worktree. * **Disk.** Three agents plus the main checkout can fill a disk. `~/.gradle/init.d/cache-retention.gradle.kts` (user-level, outside the repo) keeps `~/.gradle/caches` at 7 days with cleanup on every build; Gradle 9 accepts build-cache retention only there. Run `tools/clean-builds.sh` after removing a worktree or when free space is under about 5 GB. Deleting `~/.gradle/caches/build-cache-1` and old `~/.gradle/caches/` folders is allowed; the next build is a slow full one. An agent that hits "no space left on device" loses only uncommitted work: free space and resume it, do not respawn. * **Version drift:** run the dependency report at the start of every plan. A library more than one stable minor behind gets a line in the plan's report; a toolchain component more than one line behind triggers an upgrade plan first. diff --git a/server/README.md b/server/README.md index e18fc92..3005595 100644 --- a/server/README.md +++ b/server/README.md @@ -120,7 +120,18 @@ the wire contract makes `tests/openapi_contract.rs` fail against `contracts/open ## Tests and the gate -From `server/`: `cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test`. +From `server/`: `cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo audit && cargo test`. + +`cargo audit` (cargo-audit 0.22.2, `cargo install cargo-audit --locked`) checks `Cargo.lock` against the RustSec +advisory database. It needs the network: each run fetches the database into `~/.cargo/advisory-db` (and the +crates.io index). Run the gate online at least once per machine so the database exists; offline, +`cargo audit --no-fetch` uses the copy already there. A fix is a semver-compatible bump +(`cargo update -p `); an advisory without a fix goes in `server/.cargo/audit.toml` under +`[advisories] ignore` with a dated comment and is an owner decision. + +The pre-commit hook (`tools/git-hooks/pre-commit`) runs `cargo audit --no-fetch` only when `server/Cargo.lock` or a +`Cargo.toml` under `server/` is staged, so ordinary commits stay fast. When `cargo-audit` is not installed or the +database was never fetched it prints a message and skips the check; it never fails a commit for a missing tool. * `crates/kvitt-domain/tests/vectors.rs`: every case of every file in `contracts/test-vectors/` (the two Kotlin-only analytics files are parsed and skipped). diff --git a/tools/git-hooks/pre-commit b/tools/git-hooks/pre-commit index a1e4b47..d355b09 100755 --- a/tools/git-hooks/pre-commit +++ b/tools/git-hooks/pre-commit @@ -31,3 +31,20 @@ if [ -f "$top/server/Cargo.toml" ] && [ -d "$top/server/crates/kvitt-domain" ] & exit 1 } fi + +# Server: cargo audit, only when a dependency changed (server/Cargo.lock or a Cargo.toml staged), so ordinary +# commits stay fast. Offline (--no-fetch: the advisory database in ~/.cargo/advisory-db as last fetched by the gate). +# A missing cargo-audit or a database never fetched skips the check with a message; it never fails the commit. +if [ -f "$top/server/Cargo.lock" ] && git -C "$top" diff --cached --name-only -- 'server/Cargo.lock' 'server/Cargo.toml' \ + 'server/**/Cargo.toml' | grep -q .; then + if ! command -v cargo-audit >/dev/null 2>&1; then + echo "pre-commit: cargo-audit is not installed; skipping the dependency audit (cargo install cargo-audit --locked)." >&2 + elif [ ! -d "${CARGO_HOME:-$HOME/.cargo}/advisory-db" ]; then + echo "pre-commit: no advisory database yet; skipping the dependency audit (run cargo audit once from server/)." >&2 + else + (cd "$top/server" && cargo audit --no-fetch --quiet) || { + echo "pre-commit: cargo audit found advisories in server/Cargo.lock (see above). Fix them, or see server/README.md." >&2 + exit 1 + } + fi +fi