Repository navigation
Make every version the catalogue runs both immutable and tracked by update automation #627
Description
🤖 Generated by the Agentic Engineer (interactive Claude Code session)
Evidence
Measured on main at 945434b on 2026-10-17:
- Go modules. There are 15
go.modfiles.dependabot.ymllists only two (.github/tests/govulncheck-allowlistandgovulncheck-generics), and both entries ignore every dependency. No Go module in the catalogue therefore receives version updates. Among the untracked modules with dependencies are two shipped actions:validate-shell-pipelinesusesmvdan.cc/sh/v3 v3.14.1, the shell parser that decides pass or fail in consumer CI, andvalidate-namingusesgo.yaml.in/yaml/v3 v3.0.5. The PostgreSQL test fixture (pgx/v5 v5.10.0) and the credentials test module are also untracked. - Hard-coded tool versions that no automation reads:
semantic-release@25.0.3, golangci-lintv2.14.0(three places),deadcode@v0.50.0,gocover-cobertura@v1.5.0,node-version: 22,GODOT_VERSION: 4.7.1, and the cosign installer's implicit default (nocosign-releaseinput is set). The upstream review found security fixes already missed in semantic-release and Go; that bump is Take the semantic-release 25.0.9 and Go 1.26.9 security fixes on the shared release and validation paths #625. - Images. The PostgreSQL fixture image is pinned by digest in
validate-go-project.yamland its read-only projection, and no ecosystem independabot.ymlcovers it. - Pins that do not freeze what runs.
github/stale-reposis SHA-pinned, but runs a floating:v9container image while holding an organization App token.Homebrew/actions/setup-homebrewtracks amaincommit because upstream publishes no releases; it is now behind upstreammain.
Audience and problem
Every consumer inherits these versions. A pin nobody updates is safe only until its next upstream fix, and nothing here notices that moment. A SHA pin around a floating image gives the appearance of immutability without the substance.
Hypothesis
If every pinned version is either tracked by update automation or listed in one reviewed refresh manifest, upstream fixes reach consumers through the normal review path. The existing refresh-gh-digests updater is the model for the manifest. Changes would arrive within the 7-day cooldown, not when someone happens to look.
Direction
- Add one
gomodupdate entry covering every module with dependencies, as a single weekly group with the existing cooldown. Keep the two vulnerability fixtures deliberately frozen and say why in a comment. - Move each hard-coded tool version to a place an updater can read: a Dependabot-readable file, or a version manifest with a reviewed updater like
refresh-gh-digests.yaml. - First verify whether Dependabot reads a workflow
services:image. If it does not, cover the PostgreSQL image through the same manifest. - Pin
stale-repos' image by digest, by calling the image directly or replacing the action. Record whysetup-homebrewtracksmain, and give it a refresh path. - Keep the added update volume small. Bursts of update pull requests already starve the organization's runners (A burst of pull requests here starves the organization's runners and delayed a production deploy by an hour #475), so prefer one grouped pull request per ecosystem per week.
Acceptance criteria
- A census, kept as a test, lists every version pin in workflows, actions and modules, and fails when a pin is neither tracked nor in the manifest.
- Every module with dependencies receives grouped weekly updates.
- No step runs a container image by a mutable tag while holding a token that can write.
- The weekly number of update pull requests is measured before and after, and does not grow by more than one per ecosystem.
Priority rationale: removes the cause of the missed security fixes and closes a supply-chain gap in an App-token job. Effort: medium. Prerequisites: none.
Rough size: M.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Projects
- StatusShow more project fields📥 Backlog
Activity
devantler commentedon Oct 17, 2026
Refinement against producer
mainat22ae86ea8e9062e1973b6a071ed01dd16da8bc69after #631 delivered the immediate tool patches.The smallest coherent first delivery is Go dependency update coverage plus a checked module census. Four modules have updateable external dependencies:
actions/validate-naming,actions/validate-shell-pipelines,.github/tests/catalogue-credentialsand.github/tests/go-postgresql-fixture. Preserve the two advisory fixtures' wildcard ignores and vulnerablex/text v0.3.0; those are acceptance-test inputs. Classifytodo-scannerseparately because its only dependency is a local replacement atv0.0.0. The other eight modules have no dependencies; that does not make their compiler selectors covered by dependency automation.A weekly grouped gomod configuration with the existing seven-day cooldown is a candidate, subject to verifying actual grouping across directories and security-update behavior. A valid configuration alone cannot prove the promised pull-request-volume bound. A repository baseline query found 15 Dependabot PRs created during 2026-10-03–09 and 14 during 2026-10-10–16, across all current ecosystems; these are creation counts, not runner cost or a post-change result. The after window remains outstanding.
Important distinction for the tool-version slice:
prepare-gh-digest-update.shreads the three existing GitHub CLI defaults, requires equality, and refreshes that same version's four checksums. It does not discover new releases or advance the defaults. Its reviewed-source, delayed-credential and signed-manifest publication boundaries are reusable, but version discovery and source acceptance must be added explicitly.Tool or image changes must also regenerate
validate-go-project-readonly.yamlthrough the existing generator; credential checks compare the complete projection, and pin-parity controls bind the relevant production/fixture values. Conditional service-image updater support still needs verification. Keep #627 open until the full version-policy census, native updater execution, merged update output and observed weekly volume are proven; the module slice alone does not close it.