Repository navigation
ci: audit the dependency trees of the tooling the reusables install - #150
Merged
Merged
Conversation
The containment half of Glyndor/apt#121 landed earlier: a job that installs third-party tooling holds no secrets, enforced by workflow-lint. This is the auditing half. Nothing looked inside those trees, and a version pinned before an advisory is published stays pinned after it. The method was proven by hand on 2026-08-24 and is what this automates. `cargo install --locked` builds the tree in the tool's OWN bundled Cargo.lock, which ships inside the .crate — not this repository's lockfile. So the audit downloads the .crate, extracts that lockfile, and runs cargo audit against it. That is the tree the runner actually builds. Seven tools, with their versions read from the workflow files rather than hardcoded, sharing pin-watch's approach so a bump in one place cannot leave this auditing a version nobody installs. Yanked crates get their own section. cargo audit reports them as warnings, not vulnerabilities, and they matter here for a specific reason: `cargo install --locked` performs no resolution, so it installs a yanked crate without complaint. The maintainer's "do not use this version" reaches nobody today. It never exits non-zero because an advisory exists. A third party's disclosure timing must not block every pull request in the organisation, so a finding opens an issue and the run stays green. It does exit non-zero when the script itself failed — an unreadable pin, a download that did not return, output it could not parse — which was exercised by breaking a pin name deliberately. Verified against the real advisory database with only `gh` stubbed. The three hand measurements reproduce: RUSTSEC-2026-0185 in cargo-audit's own tree, RUSTSEC-2026-0009 in cargo-cyclonedx's, and xml-rs 0.8.19 yanked. It found five more the hand sweep missed, because that covered three tools and this covers seven. The job installs tooling, so it holds no secrets — the tooling-isolation rule applied to the job that enforces the other half of the same issue. Refs Glyndor/apt#121 Signed-off-by: Jaro-c <75870284+Jaro-c@users.noreply.github.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.
Closes the auditing half of Glyndor/apt#121. The containment half landed earlier — a job that installs third-party tooling holds no secrets, enforced by
workflow-lint'stooling-isolation. This is the part that looks inside the trees.The method, already proven by hand
cargo install --lockedbuilds the tree in the tool's own bundledCargo.lock, which ships inside the.crateon crates.io — not this repository's lockfile. So the audit downloads the.crate, extracts that lockfile, and runscargo audit --fileagainst it. That is the tree the runner actually builds.Seven tools, versions read from the workflow files rather than hardcoded, sharing
pin-watch.py's approach so a bump in one place cannot leave this auditing a version nobody installs.What it finds today
cargo-auditcargo-llvm-covcargo-cyclonedxcargo-fuzzcargo-semver-checkscargo-aboutcargo-denyThe three hand measurements from 2026-08-24 reproduce exactly —
RUSTSEC-2026-0185(quinn-proto, CVSS 7.5) in cargo-audit's own tree,RUSTSEC-2026-0009(time) in cargo-cyclonedx's, andxml-rs0.8.19 yanked. It found five more the hand sweep missed, because that covered three tools and this covers seven.cargo-aboutreporting zero is the pin bump from earlier today working: 0.9.1 carriedRUSTSEC-2026-0204, and 0.9.2 does not.Three decisions that make or break it
It never exits non-zero because an advisory exists. A third party's disclosure timing must not block every pull request in the organisation. A finding opens an issue; the run stays green. It does exit non-zero when the script itself failed — an unreadable pin, a download that did not return, unparseable output. Exercised by breaking a pin name on purpose:
exit=1.Yanked crates get their own section.
cargo auditreports them as warnings rather than vulnerabilities, and they matter here for a specific reason measured today:cargo install --lockedperforms no resolution, so it installs a yanked crate without complaint. The maintainer's "do not use this version" reaches nobody.The job installs tooling, so it holds no secrets — the
tooling-isolationrule applied to the job that enforces the other half of the same issue. Running that check against this repository with the new workflow in place passes.A limitation of the rule this exposed, worth stating
tooling-isolationchecks forsecrets.<NAME>references. It does not look atpermissions:. This new job carriesissues: writeandGH_TOKEN: ${{ github.token }}— which the check passes, correctly by its own definition, but that is not zero credential. A build script in the audited tree could open an issue. Low impact:contents: readmeans it cannot push, and it cannot reach any secret.The gap worth naming is broader than this job: a workflow with
permissions: contents: writeand a tooling install would pass the check today while being genuinely dangerous. That is a real hole in a rule I wrote this morning, and it is better recorded than left for someone to discover by trusting the check further than it goes. Not fixed here — widening it needs thought about which permissions are disqualifying and would flag legitimate jobs.Verification
actionlintclean,ruff checkandruff format --checkclean. Run for real against the live RustSec database with onlyghstubbed, so crates.io and the advisory data were genuine. Deduplication exercised: with the issue already open it declines to create a second.