ci: adopt the fleet reusable CI workflow - #5
Draft
h4x0r wants to merge 5 commits into
Draft
Conversation
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pilot 3 of 3 — workspace with fuzz (
ntfs-core+ntfs-forensic, rootfuzz/). 172 lines become 44.This one surfaces a real finding. The workflow being replaced runs
cargo llvm-cov --libwith no features; the fleet default is--workspace --all-features. Running the shared gate locally at the fleetdefault surfaces 37 uncovered lines in
core/src/vfs.rs— thevfsfeatureadapter, which the narrower scope never measured at all. The old job is named
"Coverage (100% lines)" and its number was true for what it measured, and silent
about a whole feature-gated module.
Those 37 lines are left visible on purpose. The two honest ways to clear them are
to test the vfs adapter, or to declare the exclusion explicitly with
coverage-ignore-regex: 'core/src/vfs\.rs'— which is at least reviewable.Narrowing scope back to
--libwould hide the gap again. Scope is part of thecoverage semantics, not a detail.
Why
The fleet carries 91 copies of
ci.ymlin 89 distinct normalized variantsacross 49 feature profiles. Where a shared mechanism exists the fleet
converges completely —
release-plz.ymlhas 87 copies in 2 variants, andrust-toolchain.tomlis uniform at 1.96.0 across all 90. CI drifted becausenothing held it together.
Four gaps the single workflow closes:
permissions:blockcontents: read, workflow-wideThe pins are sound; one provenance label is fiction
9bdad043e88c75890e36ad3bbc8d27f0090dd609appears in 56 fleet repos, across 87workflow files, 292 times — 276 commented
# v2.7.8, 16 commented# v2. It isa real
Swatinem/rust-cachecommit dated 2024-05-03 (fix: usage of deprecated version of node, PR #197), but it matches no release tag: v2.7.3 →23bce251a8cd2ffc3c1075eaa2367cf899916d84, v2.7.5 →82a92a6e8fbeee089604da2575dc567ae9ddeaab, v2.7.7 →f0deed1e0edfc6a9be95417288c0e1099b1eeec3, v2.7.8 →9d47c6ad4b02e050fd481d890b2ea34778fd09d6, v2.8.0 →98c8021b550208e191a6a3145459bfc9fb29c4c0.This is a traceability defect, not a vulnerability. A SHA is immutable, so the
security control is doing its job — the pinned bytes cannot change under anyone.
What fails is provenance: 56 repos run untagged mid-tree code while the comment
beside it asserts a release, so an audit answering "are we on released
versions?" from those comments gets a wrong answer, and Renovate's
digest-pinning may not map SHA→version cleanly either.
orchestration/issenandparser/browser-forensicpin both SHAs in differentworkflows, so they are internally inconsistent about which
rust-cachethey run.Every SHA in the shared workflow was resolved with
gh api repos/<owner>/<repo>/commits/<tag> --jq .sha;rust-cacheisc19371144df3bb44fab255c43d04cbc2ab54d1c4, genuinely v2.9.1.The coverage gate, and why these semantics
The fleet's gate existed in three forms that disagree about what "100%" asserts:
cov:unreachable-aware (36 repos) — walks everyDA:<n>,0record, reads the source line, exempts annotated ones, names what failed.
--fail-under-lines N(10 repos, N ∈ {85, 89, 90, 92, 95,96, 97}).
grep -qE '^DA:[0-9]+,0$'— strict 100%, no exemption at all.The shared workflow implements (1). It is what the fleet constitution already
requires, and it is the only form that preserves defence in depth: under a floor,
an unreachable guard is indistinguishable from an untested one; under the naive
grep, the only way to go green is to delete the guard. Both pressure the author
toward removing exactly the code that keeps a parser safe on hostile input. A
floor also hides which lines rot — at 85%, 15% of the crate can decay silently,
and every floor in the fleet carried a "ratchet it up later" comment that had
never been ratcheted.
Repos not yet at per-line coverage set
coverage-gate: floor, which renders inthe checks UI as
Coverage (FLOOR N% — migration debt, not the fleet gate)andemits a warning. The debt stays visible instead of looking like a passing gate.
Design points worth reviewing
rust-versionacross workspace members from
cargo metadata. Restating it in CI is how arepo ends up verifying 1.85 while promising 1.81 downstream. Verified against
browser-forensic, whose members declare both 1.80 and 1.85 — it derives 1.80.If no member declares one, the job fails loudly rather than guessing a floor it
would then claim to have verified.
fuzzcontaining aCargo.toml, at any depth. 79 fleet repos have a fuzz crate but only 70 keepit at
fuzz/; the other 9 usecore/fuzz,forensic/fuzz, orcrates/<member>/fuzz. A root-only check would skip those silently, and afuzz job that passes because it found nothing is worse than none at all.
Discovery was run against all 92 repos: exact match, zero mismatches.
.gitleaks.tomlis honoured — 60 repos ship one, allowlistingforensic fixtures that look like credentials.
docs(34 repos) andgeiger(19) are the obvious next consolidationcandidates, but they do not block adoption.
Validation
Python compiles.
(covered / uncovered / annotated exemption / bare marker / delimiter artifact /
unreadable source) — correct exit code and classification in each.
cargo llvm-covoutput (ntfs-forensic: 34files, 12,906
DArecords, 97 zero-hit). That caught a genuine bug my ownfixture had missed: the marker regex was anchored to
//and so dropped thetrailing block-comment form back into the failure set. Fixed and re-verified.
end, because the callee does not exist.
Action pins are behaviour-neutral
Every action is pinned to exactly what the fleet runs today, so this changes
one variable — where CI is defined — not two:
actions/checkout11bd71901bbe5b1630ceea73d27597364c9af683Swatinem/rust-cache9d47c6ad4b02e050fd481d890b2ea34778fd09d6taiki-e/install-action59012be0884e296ca2da49b530610e72c49039adAn earlier revision pinned
checkoutat v7.0.1 andrust-cacheat v2.9.1. Bothwere reverted — a version bump hidden inside a 91-repo consolidation is
unreviewable, and when CI breaks nobody can tell whether the migration or the
upgrade caused it.
rust-cacheis now the genuine v2.7.8, the version 56repos already believe they run, so this fixes the provenance label without
changing behaviour. Upgrades become a separate reviewable PR against one file.
cargo denyargument order--configbelongs to thechecksubcommand;--all-features,--excludeand
--targetare global options that precede it. Both forms were runagainst cargo-deny 0.19.0:
The workflow emits
cargo deny [globals] check --config <shared> all. Adeny-argsinput carries the three genuinely per-repo settings a shared configcannot hold:
--all-features(4 repos — kept out of the shared file because atfleet scope it pulls optional GPL-2.0/GPL-3.0 crates like
lzo1xandnoallocinto the graph),
--excludefor*-fuzzmembers (10 repos), and--target(winevt-forensic only, which per
cargo deny --help"overrides the top-leveltargets = []configuration value").