From d195a64f78dde746207efb0b5ae814a8c63391f4 Mon Sep 17 00:00:00 2001 From: Albert Hui Date: Sun, 2 Aug 2026 02:41:27 +0800 Subject: [PATCH 1/6] ci: adopt the fleet reusable CI workflow Replaces this repo's hand-maintained ci.yml with a call to the shared workflow_call workflow. Repo-specific jobs stay here alongside the call. The fleet carried 91 copies of ci.yml in 89 distinct normalized variants across 49 feature profiles. The per-repo copies left four gaps this closes: - Secret scan: 48 of 91 repos had none. - SHA pinning: 10 of 91 were fully pinned; 81 carried a floating tag. - permissions: 0 of 91 declared a block. - Coverage: 6 implementations with 3 incompatible semantics. The shared coverage gate is per-line and honours cov:unreachable, because that is the only semantics that preserves defence in depth. An aggregate floor has no per-line hook, so it cannot honour an exemption and never names the rotting lines; a naive DA:n,0 grep has no exemption at all, so the only way to green is to delete the guard. Both pressure the author toward removing exactly the code that keeps a parser safe on hostile input. The callee does not exist yet -- creating the repo that hosts it is not yet authorized -- so the `ci` check will fail to resolve until it lands. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 149 +++++---------------------------------- 1 file changed, 17 insertions(+), 132 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66902d6..6828db4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,142 +6,27 @@ on: pull_request: branches: [main] -env: - CARGO_TERM_COLOR: always - RUSTFLAGS: -D warnings +permissions: + contents: read jobs: - fmt: - name: Format - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - run: cargo fmt --check - - clippy: - name: Clippy - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@stable - with: - components: clippy - - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 # v2.7.8 - - run: cargo clippy --workspace --all-targets -- -D warnings - - test: - name: Test (${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 # v2.7.8 - - run: cargo test --workspace --all-features - - msrv: - name: MSRV (1.81) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@1.81 - - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 # v2.7.8 - - run: cargo build --workspace - - coverage: - name: Coverage (100% lines) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@stable - with: - components: llvm-tools-preview - - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 # v2.7.8 - - uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 - with: - tool: cargo-llvm-cov - # Each executable source line must be hit at least once. - # - # Exception — panic-free defence in depth: a line carrying a - # `// cov:unreachable` marker is unreachable under a dominating invariant, - # kept deliberately to stay panic-free if that invariant is ever broken by - # a future change. Such lines cannot be exercised by any test and are - # exempt. The gate fails on any OTHER zero-hit line. - - name: Generate lcov - run: cargo llvm-cov --workspace --all-features --lcov --output-path lcov.info - - name: Enforce line coverage (unreachable defensive arms must carry // cov:unreachable) - shell: bash - run: | - fail=0 - while IFS= read -r line; do - if [[ "$line" == SF:* ]]; then - f="${line#SF:}" - elif [[ "$line" =~ ^DA:([0-9]+),0$ ]]; then - n="${BASH_REMATCH[1]}" - src="$(sed -n "${n}p" "$f")" - if [[ "$src" == *cov:unreachable* ]]; then - echo "exempt (// cov:unreachable): $f:$n" - else - echo "::error::Uncovered line $f:$n:$src" - fail=1 - fi - fi - done < lcov.info - if [[ "$fail" -ne 0 ]]; then exit 1; fi - echo "All executable lines covered, or annotated // cov:unreachable." - - deny: - name: cargo-deny - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1 - with: - command: check - - vet: - name: Cargo Vet (supply-chain) - runs-on: ubuntu-latest - # Complements `deny` (known-bad advisories/licenses) with the supply-chain- - # injection layer: every dependency version must be human-source-reviewed or - # covered by an imported aggregate audit set (Google/Mozilla/Bytecode-Alliance/ - # Embark). Config in supply-chain/{config,audits,imports}.toml. - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@stable - - name: Install cargo-vet - uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 - with: - tool: cargo-vet - - name: Fetch dependencies - run: cargo fetch - - name: Check supply chain - run: cargo vet --locked - - gitleaks: - name: gitleaks - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - name: gitleaks (license-free binary) - run: | - VER=8.21.2 - curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${VER}/gitleaks_${VER}_linux_x64.tar.gz" | tar -xz gitleaks - CFG=""; [ -f .gitleaks.toml ] && CFG="--config .gitleaks.toml" - ./gitleaks detect --source . --redact --no-banner $CFG - + # fmt · clippy · test (3 OS) · MSRV · cargo-deny · cargo-vet · secret scan · + # fuzz build-check · per-line coverage gate. + # + # Every default fits this repo, so there is nothing to override: MSRV is + # derived from rust-version (1.81), coverage is already the per-line gate at + # --workspace --all-features, and core/fuzz is discovered automatically. + ci: + uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@c30b7708f0e5900d40c0435eac02a15d0f72df75 + + # Repo-specific, so it stays here rather than moving into the shared workflow. docs: name: Docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 # v2.7.8 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master + with: + toolchain: stable + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --workspace From 313908521f884e15a582cedd4216d74a033a92d0 Mon Sep 17 00:00:00 2001 From: Albert Hui Date: Sun, 2 Aug 2026 02:48:12 +0800 Subject: [PATCH 2/6] ci: repin the reusable workflow to the corrected fleet-config commit The previous pin predates the rust-cache provenance correction, so a reviewer following the SHA would read the wrong figures (the finding is 56 repos / 87 files / 292 occurrences, not "~36 repos"). Workflow bytes are unchanged; only the README differs between the two commits. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6828db4..0ad5510 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: # derived from rust-version (1.81), coverage is already the per-line gate at # --workspace --all-features, and core/fuzz is discovered automatically. ci: - uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@c30b7708f0e5900d40c0435eac02a15d0f72df75 + uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@5bfd1026c31e82b6c0b192a091c82dc1a7e7ee39 # Repo-specific, so it stays here rather than moving into the shared workflow. docs: From 8cbeee63cdbd76c2aec82713753176b4ecaf8d57 Mon Sep 17 00:00:00 2001 From: Albert Hui Date: Sun, 2 Aug 2026 02:55:00 +0800 Subject: [PATCH 3/6] ci: pin action versions to the fleet's current, and repin fleet-config Reverts actions/checkout v7.0.1 -> v4.2.2 and rust-cache v2.9.1 -> the genuine v2.7.8 in this repo's own jobs, matching the shared workflow. Every action now pins exactly what the fleet runs today, so adopting the reusable workflow changes one variable -- where CI is defined -- and not two. Repins fleet-config to the commit that fixes the cargo-deny argument order (--config belongs to the `check` subcommand; the previous form would have failed at runtime) and corrects the permissions figure to 22 of 92 repos. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ad5510..5f14753 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,16 +17,16 @@ jobs: # derived from rust-version (1.81), coverage is already the per-line gate at # --workspace --all-features, and core/fuzz is discovered automatically. ci: - uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@5bfd1026c31e82b6c0b192a091c82dc1a7e7ee39 + uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@29389c094b9d2e95493d5f8857dd51d5407559a0 # Repo-specific, so it stays here rather than moving into the shared workflow. docs: name: Docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master with: toolchain: stable - - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --workspace From 36ec082d0865638446197cb382615c5675030e3e Mon Sep 17 00:00:00 2001 From: Albert Hui Date: Sun, 2 Aug 2026 02:56:27 +0800 Subject: [PATCH 4/6] ci: repin fleet-config to the fully-pinned commit The previous fleet-config commit still had one checkout on v7.0.1 -- the deny job's `Fetch shared deny.toml` step, whose `uses:` is indented under a `- name:` key and so escaped a whole-file replace. All 25 action refs in the callee are now pinned and each SHA re-verified against its commented tag. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f14753..8abb62f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: # derived from rust-version (1.81), coverage is already the per-line gate at # --workspace --all-features, and core/fuzz is discovered automatically. ci: - uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@29389c094b9d2e95493d5f8857dd51d5407559a0 + uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@29f8011615059de76d9ad1a41ade1c6f9b70162c # Repo-specific, so it stays here rather than moving into the shared workflow. docs: From d6a6f3fcece4c1f0c672cae24051df99b8061c15 Mon Sep 17 00:00:00 2001 From: Albert Hui Date: Sun, 2 Aug 2026 15:29:47 +0800 Subject: [PATCH 5/6] fix(ci): point the caller at fleet-ci, not fleet-config, and repin The caller stub referenced SecurityRonin/fleet-config/.github/workflows/rust-ci.yml, but the reusable workflow lives in SecurityRonin/fleet-ci. fleet-config holds the shared deny.toml and the legal templates and has no workflows directory, so the reference could never have resolved. Also repins from 29f8011 to f49dff5, which carries the fix for a defect the workflow had inherited from the repos it consolidates: a bare "cargo fetch" re-resolves and rewrites Cargo.lock in the runner, so the "cargo vet --locked" on the following line validated a lock CI had just generated for itself rather than the committed bytes. 80 of 81 fleet repos share that shape. Consolidating the workflow as previously pinned would have propagated it to all 91 repos in a single shared file everyone assumes was reviewed. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8abb62f..ca0308b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: # derived from rust-version (1.81), coverage is already the per-line gate at # --workspace --all-features, and core/fuzz is discovered automatically. ci: - uses: SecurityRonin/fleet-config/.github/workflows/rust-ci.yml@29f8011615059de76d9ad1a41ade1c6f9b70162c + uses: SecurityRonin/fleet-ci/.github/workflows/rust-ci.yml@f49dff5ddb19b17f69926210abb70f78c14c29e2 # Repo-specific, so it stays here rather than moving into the shared workflow. docs: From e33ff20ee0663d9b243788ce7f6a85f9dfa77c07 Mon Sep 17 00:00:00 2001 From: Albert Hui Date: Tue, 4 Aug 2026 14:20:32 -0700 Subject: [PATCH 6/6] ci: repin fleet-ci to pick up the path-deps and rustdoc gates The pin was f49dff5, which predates both jobs this adoption needs. * `path-deps` (543abee) refuses a path dependency that resolves outside the repository. Three fleet repos hit that this week and it cost roughly 28 red checks, each reporting an error naming a workspace member rather than the dependency that escaped. * `docs` (6b55022) is the rustdoc gate. This repo's ci.yml runs `RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --workspace`, and adoption replaces ci.yml wholesale, so without that job the gate would simply disappear -- clippy does not read doc comments and the test job does not build docs. Checked what else adoption would drop, since replacing a whole ci.yml is where gates go missing quietly. The four executing fuzz jobs are safe: they live in fuzz.yml, which this PR does not touch, and fleet-ci's own fuzz job is a build check by design ("the long run belongs in fuzz.yml"). That distinction matters here -- `Fuzz unlock` is the job that found the three denial-of-service bugs fixed in this repo this week, and swapping it for a compile check would have meant none of them were ever found. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca0308b..e286b52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: # derived from rust-version (1.81), coverage is already the per-line gate at # --workspace --all-features, and core/fuzz is discovered automatically. ci: - uses: SecurityRonin/fleet-ci/.github/workflows/rust-ci.yml@f49dff5ddb19b17f69926210abb70f78c14c29e2 + uses: SecurityRonin/fleet-ci/.github/workflows/rust-ci.yml@6b5502293ffb656c7ded8998c5acc704b5cee431 # Repo-specific, so it stays here rather than moving into the shared workflow. docs: