Repository navigation
fix(supply-chain): census every version pin and run stale-repos by digest - #873
Conversation
…gest Add a census, kept as a CI test, that lists every version pin in workflows, action metadata and Go modules. It fails when a pin is mutable, neither tracked by Dependabot nor listed with a refresh path in .github/version-pins.json, or when a listed entry no longer matches. github/stale-repos is a Docker action whose metadata runs the floating stale_repos:v9 tag while the step holds the App token. Call the v9.1.1 image by digest instead. Part of #627 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Every digest on any line, every *_IMAGE assignment and docker run/pull/create arguments (joined across continued lines) are now examined, and each result branch of an image expression must be digest-pinned or empty. A Dependabot "*" matches one path segment, and entries that ignore everything or open no pull requests count as untracked. Workflow templates are scanned and go.mod discovery fails closed. Lists the todo-to-issue image and the template checkout pin the wider scan found. Part of #627 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devantler
left a comment
There was a problem hiding this comment.
🤖 Generated by the Agentic Engineer (interactive Claude Code session)
Self-review (fallback — CodeRabbit, Codex and Cursor Bugbot unavailable)
Reviewed commit: e48e610
- CodeRabbit: rate-limited across the organization since 2026-11-03T09:04Z (coordinator lane-health reading). No review requested.
- Codex: requested at the first head. It answered "You have reached your Codex usage limits for code reviews" at 2026-11-04T19:23:04Z.
- Cursor Bugbot: hit its usage limit at 2026-11-04T00:29Z, with no delivery evidence since. Not requested.
An independent reviewer agent reviewed this PR at d3fd9026ccc2c4aa254ff312b97eebaae372a7a1: correctness and security first, then this repository's review guidelines. It ran the PR's tests and mutation fixtures in a detached worktree. I fixed or documented every finding, then re-reviewed the delta to e48e6107708a5358933f3a2b4a4024c430181f0a myself:
- P1, fixed: the census now examines every image digest on any line, every
*_IMAGEassignment, anddocker run/pull/createarguments, joined across continued lines. The wider scan found the unlistedtodo-to-issue-actionimage, which is now listed with its refresh path. New controls: env image,docker run, continueddocker run, unlisted env digest. - P1, fixed: in an image expression, each result branch (a literal after
${{,&&or||) must be digest-pinned or empty. Comparison operands do not count. New control: a mutable||branch. - nit, fixed: a Dependabot
*matches one path segment (new nested-action control). Entries that ignore*or setopen-pull-requests-limit: 0count as untracked (new control).workflow-templates/is scanned (new control; its checkout pin is listed).go.moddiscovery fails closed. - nit, documented in
actions/CONTRIBUTING.md: shell variables are resolved only through*_IMAGE, a tool version needs a dotted number, and a quoted#ends the scanned text. - Confirmed: the
docker://stale-repos step behaves the same as the action. Both tags resolve to the pinned index digest.
Verdict: no P0/P1 findings
Tried as a user at
🤖 Generated with Claude Code |
Code coverage overviewLanguages: Go, C# Go / code-coverage/test
C# / code-coverage/dotnet
Go / code-coverage/go
ℹ️ Calculations represent line coverage. Results may change as calculations are updated. Updated |
Status: held as a draft until CI finishes at 🤖 Generated with Claude Code |
Why
#627 asks that every version the catalogue runs be both immutable and kept current. Only the gomod tracking part (#840, delivered in #841) has landed. Two gaps remain:
github/stale-reposis SHA-pinned, yet it runs a floating image while it holds the organization App token. It is a Docker action whose metadata saysimage: docker://ghcr.io/github-community-projects/stale_repos:v9, so the SHA pin froze nothing.What
.github/scripts/version-pin-census.shlists every version pin in workflow files, action metadata and Go modules, one row each:tracked,manifestorviolation. A pin is tracked in two cases. It can be a full-SHA action with a# v<version>comment, in a directory that Dependabot's github-actions entry covers. Or it can be a module with external requirements, in agomodentry that does not ignore*. Requirements replaced by a local path are not versions. Any other pin must be listed in the new.github/version-pins.jsonwith its refresh path. That means images, tool versions inrun:/with:/env:(including block-scalar lists such asdotnet-version: |), branch-tracked actions and frozen fixtures. The census fails in four cases: a mutable pin (an action ref that is not a full SHA, or an image without a digest), a pin that is neither tracked nor listed, a manifest entry that no longer matches anything, and unreadable input (exit 2). It does not use the network.setup-homebrew's branch commit, and the two deliberately frozen govulncheck fixtures, each with a reason. The census found two pins the issue did not list: the .NET SDK list inrun-dotnet-testsand ci.yaml'sdotnet-versionblocks.docker://ghcr.io/github-community-projects/stale_repos:v9.1.1@sha256:b259f6c3…. That is the image thev9andv9.1.1tags both resolve to today. The action declares no inputs, arguments or entrypoint, and the step passes everything throughenv:, so the container gets the same environment and workspace.test-version-pin-census.shis wired into thelint-ci-coverage-parityjob.actions/CONTRIBUTING.mddocuments the rule.Acceptance criteria of #627
stale-reposfixed here. One remaining: the productionvalidate-go-project.yamllint job runsoxsecurity/megalinter/flavors/go@9949bad0, whose metadata uses the tagmegalinter-go:v10.1.0, whileGITHUB_TOKENhasissues/pull-requests: write. Fixing that trades Dependabot tracking of MegaLinter for a digest, or takes the token off the step, so it is left for a separate change.So this PR is Part of #627, not a fix for it.
Validation
bash .github/tests/test-version-pin-census.shpasses. It runs the census on this repository (431 tracked, 42 listed, 0 violations) and 22 controls on an isolated fixture tree. They cover: tag ref, SHA without version comment, uncovered directory, nested directory under a one-level*,open-pull-requests-limit: 0, workflow template,docker://tag, service tag, expression image, mutable expression branch,*_IMAGEenv tag, unlisted env digest,docker runliteral, continueddocker run, unlistedgo install …@v,*_VERSIONenv, block-scalar version, untracked module, unlisted frozen module, stale entry, malformed manifest and missing dependabot.yml. Each control asserts its specific row.main's tree with an empty manifest (32 violations, RED) and passes here.test-test-script-wiring.shpasses. zizmor has no findings on the stale-repos workflow.🤖 Generated with Claude Code
Review follow-up (second commit): an independent review pass found two fail-opens. Images outside
image:/container:/docker://were never examined, which hid the unlistedtodo-to-issue-actionimage. And a mutable branch inside an image expression went unseen. Both are fixed and each has controls. The scan also now coversworkflow-templates/and Dependabot's one-segment*. The manifest lists the two pins the wider scan found.