From c0c2e3f6076e864f43299632ac12af53c326d7b2 Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Fri, 3 Jul 2026 13:23:54 -0700 Subject: [PATCH 1/2] ci: add cargo-audit supply-chain scanning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add RustSec advisory scanning to catch dependency CVEs, flagged independently by 4 of 5 security reviews. - New CI job `cargo-audit` in .github/workflows/ci.yml runs `cargo audit --deny unmaintained --deny unsound` (vulnerabilities are denied by default), so any un-ignored advisory fails CI. - `just audit` mirrors the CI command for local use; folded into `just check`. - .cargo/audit.toml holds the ignore policy. Every entry carries an inline justification; nothing is blanket-ignored. Yanked crates are informational-only (no advisory ID to ignore by; the dangerous ones resurface as vuln/unmaintained/unsound, which are denied). Fix 5 of the 7 live advisories by bumping patched transitive deps in Cargo.lock (anyhow, memmap2, quinn-proto, rand, rustls-webpki/rustls). The 2 remaining (quick-xml DoS) are unfixable via cargo update — gated by wayland-scanner's ^0.39 pin — and non-exploitable (build-time proc macro parsing trusted local protocol XML), so they are ignored with a documented reason plus core2/paste unmaintained (transitive AVIF encode and build-time proc macro, never in the auth path). Co-Authored-By: Claude Fable 5 --- .cargo/audit.toml | 56 ++++++++++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 25 ++++++++++++++++++ CONTRIBUTING.md | 15 ++++++++++- Cargo.lock | 42 +++++++++++++++--------------- justfile | 10 +++++-- 5 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 .cargo/audit.toml diff --git a/.cargo/audit.toml b/.cargo/audit.toml new file mode 100644 index 0000000..d0852f4 --- /dev/null +++ b/.cargo/audit.toml @@ -0,0 +1,56 @@ +# cargo-audit configuration — supply-chain CVE scanning policy. +# +# cargo-audit auto-reads this file from `.cargo/audit.toml`. Run it locally +# with `just audit`, which uses the exact same flags as the CI `cargo-audit` +# job so local and CI results match. +# +# Failure policy (set via CLI flags in `just audit` and CI, NOT here, because +# cargo-audit's `[output]` config table requires a complete field set): +# +# cargo audit --deny unmaintained --deny unsound +# +# That fails the build on any vulnerability (always denied by default), any +# unmaintained advisory, or any unsound advisory that is NOT explicitly listed +# in `[advisories] ignore` below. A new advisory of these kinds fails CI until +# it is either fixed (bump the offending dependency) or triaged into the ignore +# list with a justification. This is what keeps the policy from being +# "warnings-only". +# +# Yanked crates are reported as informational warnings only, not build +# failures: a plain yanked crate carries no RustSec advisory ID, so it cannot +# be individually justified/ignored here (ignores are keyed by advisory ID). +# Anything genuinely dangerous about a yanked crate surfaces as a separate +# vulnerability / unmaintained / unsound advisory, which IS denied. Currently +# yanked (informational only): core2 0.4.0 (also covered by RUSTSEC-2026-0105 +# below) and uds_windows 1.2.0 (Windows-only zbus transport, `cfg(windows)`, +# never compiled on facelock's Linux targets). +# +# Every ignore entry MUST carry an inline justification. Do not blanket-ignore. +# When a fix ships (a dependency bump that drops the advisory), delete the +# ignore rather than leaving it to rot. + +[advisories] +ignore = [ + # quick-xml 0.39.x — quadratic parse time / unbounded namespace allocation + # DoS. Fixed in >=0.41.0, but our only path to quick-xml is the build-time + # proc-macro `wayland-scanner` (v0.31.10 pins quick-xml ^0.39, so + # `cargo update` cannot lift it). wayland-scanner parses the trusted Wayland + # protocol XML shipped inside the wayland-* crates at compile time; it never + # sees attacker-controlled runtime input, and no quick-xml code runs in the + # auth path or any shipped binary. Revisit when smithay-client-toolkit / + # wayland-scanner ship a release built on quick-xml >=0.41. + "RUSTSEC-2026-0194", + "RUSTSEC-2026-0195", + + # core2 0.4.0 — unmaintained (all versions yanked). Transitive via + # image -> ravif -> rav1e -> bitstream-io, i.e. the AVIF *encoder*. facelock + # only decodes camera frames; the AVIF encode path is never exercised at + # runtime. No maintained successor is wired up upstream. Revisit when + # image / rav1e drop the core2 dependency. + "RUSTSEC-2026-0105", + + # paste 1.0.15 — unmaintained proc-macro (build-time only). Transitive via + # rav1e. Runs only at compile time and ships no runtime code; rav1e has not + # migrated to a maintained replacement yet. Revisit when rav1e drops paste. + "RUSTSEC-2024-0436", +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30de1b8..dff3bb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,31 @@ jobs: target/release/libpam_facelock.so retention-days: 1 + cargo-audit: + name: Supply-chain Audit (cargo-audit) + runs-on: ubuntu-latest + container: archlinux:base-devel + steps: + - name: Install system dependencies + run: | + pacman -Syu --noconfirm \ + git \ + rust + + - uses: actions/checkout@v6 + + - name: Cache cargo registry and cargo-audit build + uses: Swatinem/rust-cache@v2 + + - name: Install cargo-audit + run: cargo install cargo-audit --locked + + # Ignore policy (with justifications) lives in .cargo/audit.toml. + # Deny policy matches `just audit`: fail on any vulnerability (default), + # unmaintained, or unsound advisory that is not explicitly ignored. + - name: Run cargo audit + run: cargo audit --deny unmaintained --deny unsound + tpm-tests: name: TPM Tests (swtpm) runs-on: ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba425f6..b80dd47 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,6 +47,19 @@ The PAM module (`pam-facelock`) must stay lightweight: **libc, toml, serde, zbus Each crate has a defined dependency boundary. See `AGENTS.md` for the full table. +### Supply-chain auditing + +```bash +just audit # cargo audit --deny unmaintained --deny unsound +``` + +`just audit` scans the full `Cargo.lock` for RustSec advisories and mirrors the +CI `cargo-audit` job. It fails on any vulnerability, unmaintained, or unsound +advisory that is not explicitly ignored. The ignore list, with a justification +per entry, lives in `.cargo/audit.toml`; add a new entry (with a reason) only +when an advisory is genuinely non-exploitable here and cannot yet be fixed by a +dependency bump. Requires `cargo install cargo-audit --locked`. + ## Testing ### Tier 1: Unit tests (no hardware) @@ -88,7 +101,7 @@ Only after tiers 3--4 pass. Always keep a root shell open. Start with `sudo` onl ### All checks at once ```bash -just check # runs test + clippy + fmt +just check # runs test + clippy + fmt + audit ``` ## Security considerations diff --git a/Cargo.lock b/Cargo.lock index ccd9127..4ad8d84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arbitrary" @@ -1062,7 +1062,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2217,9 +2217,9 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ "libc", ] @@ -2686,9 +2686,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.39.2" +version = "0.39.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" dependencies = [ "memchr", ] @@ -2715,15 +2715,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" dependencies = [ "aws-lc-rs", "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash 2.1.2", "rustls", @@ -2772,9 +2772,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core 0.9.5", @@ -2852,7 +2852,7 @@ dependencies = [ "num-traits", "paste", "profiling", - "rand 0.9.2", + "rand 0.9.4", "rand_chacha", "simd_helpers", "thiserror", @@ -3059,14 +3059,14 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "aws-lc-rs", "once_cell", @@ -3116,7 +3116,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3127,9 +3127,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "aws-lc-rs", "ring", @@ -3520,7 +3520,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4315,7 +4315,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/justfile b/justfile index 40ca5cf..d2b61d5 100644 --- a/justfile +++ b/justfile @@ -30,8 +30,14 @@ fmt-check: fmt: cargo fmt --all -# Run all checks (test + lint + format) -check: test lint fmt-check +# Scan the dependency tree for RustSec advisories (mirrors the CI cargo-audit job). +# Ignore policy lives in .cargo/audit.toml; deny policy is set here so CI matches. +# Requires cargo-audit: cargo install cargo-audit --locked +audit: + cargo audit --deny unmaintained --deny unsound + +# Run all checks (test + lint + format + audit) +check: test lint fmt-check audit # Build the PAM test container image (uses host-built release binaries) _build-test-container: build-release From b730a70025c052ea10a797b51ec99349c6759aaa Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Sat, 4 Jul 2026 14:02:31 -0700 Subject: [PATCH 2/2] ci: scope RUSTFLAGS=-Dwarnings away from cargo-audit job The workflow-level RUSTFLAGS=-Dwarnings was inherited by cargo-audit, which compiles cargo install cargo-audit --locked against third-party crates we don't control. A future warning in cargo-audit's own dependency tree would fail this job for reasons unrelated to the audit. Override RUSTFLAGS to empty at the job level so strict warnings only gate our own workspace builds (build-and-test, tpm-tests, clippy). --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dff3bb3..b6cd61a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,12 @@ jobs: name: Supply-chain Audit (cargo-audit) runs-on: ubuntu-latest container: archlinux:base-devel + # Override the workflow-level -Dwarnings: this job compiles cargo-audit's + # own third-party dependency tree, which we don't control. A future + # warning upstream shouldn't fail this job for reasons unrelated to the + # audit itself. The real build/test/clippy jobs above keep -Dwarnings. + env: + RUSTFLAGS: "" steps: - name: Install system dependencies run: |