fix(cache): make the contract true, and derive the surface it must cover - #181
Merged
Conversation
The catalog recorded astral-sh/setup-uv as not caching by default. The pinned action declares `enable-cache: auto`, and its getEnableCache() returns true when RUNNER_ENVIRONMENT is github-hosted, so the entry asserted the opposite of the behaviour and nothing executed the assertion. Two gate jobs carried a comment saying their explicit `false` changed nothing today. It changed something. upstream_default now records the literal default the pinned action.yml declares, and check_cache_upstream_defaults.py resolves it from that commit each sweep, so default_caches stops being prose about somebody else's code. The refusal list was hand-written, and the contract's closing paragraph claimed the undeclared remainder could not reach a release or a required check. It could. check_cache_contract.py now derives the required surface from ci-gate's own `needs` graph and follows a `uses:` job into the workflow it calls. That found two leaks rather than the one that was known: zizmor-sarif, which backs the required zizmor job, and actions/setup-go in shell-gates, which caches by default and had never been named. Twelve call sites now state their refusal. python-ci.yml keeps enable-cache: true deliberately -- it caches the consumer's own dependencies. Two of those sites, qt-ci.yml and runtime-fixtures-languages.yml, had no `with:` block at all and so were not pinning uv itself: setup-uv's `version` defaults to the version in pyproject.toml or, absent one, latest, and there is none here. A SHA-pinned action was installing an unpinned tool in a product reusable. Both now pin 0.11.30. All six affected reusables were re-proven by real fixture runs before their proven_digest was updated.
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.
The declaration was the opposite of the behaviour
catalog/cache-contract.ymlrecorded:The pinned action declares
enable-cache: auto, and itsgetEnableCache()returnsRUNNER_ENVIRONMENT === "github-hosted"— true on every hosted runner. Two gatejobs carried a comment saying their explicit
false"changes nothing today". Itchanged something.
default_cacheswas also read by no line of code. It is now backed byupstream_default— the literal default the pinnedaction.ymldeclares — andcheck_cache_upstream_defaults.pyresolves it from that exact commit each sweep.The refusal list was hand-written, and the contract knew better than it could
The old closing paragraph said the undeclared remainder were "advisory lanes where a
poisoned entry cannot reach a release or a required check".
check_cache_contract.pynow derives the required surface from
ci-gate's ownneedsgraph, following auses:job into the workflow it calls.It immediately found two leaks, not the one that was known:
actions/setup-goinshell-gateswas in nobody's list — not the review's, not mine.Deriving the surface found it; listing it never would have.
A second finding, adjacent
Two call sites —
qt-ci.ymlandruntime-fixtures-languages.yml— had nowith:block at all, so they were also not pinning uv itself. setup-uv's
versioninput defaults to
'', documented as "the version inpyproject.tomlorlatest",and there is no
pyproject.tomlhere.A SHA-pinned action was installing whatever uv was latest at run time — including
in
qt-ci.yml, a product reusable consumers call. Both now pin0.11.30.What changed
python-ci.ymlkeepsenable-cache: true— deliberate, it caches the consumer'sown dependencies.
trueentries" (there werefour; there are now five) is corrected.
ci.ymlcomments are corrected.Evidence, before the ledger was updated — not after
Touching six product reusables invalidated their
proven_digest, exactly as designed.Rather than downgrade them, the branch was pushed as
fixtures/**and the estatere-proved every one:
private-static.ymlzizmor-no-sarif.ymlzizmor-sarif.ymlsemgrep-ci.ymlsql-ci.ymlqt-ci.ymlRuns 31853478055
and 31853477977.
proven_digestandlast_runwere updated only after those succeeded, and the sixfiles are byte-identical to the commit they proved.
Mutations
Verification
validate_all— all tiers OK withGH_TOKENactionlint— clean ·zizmor@1.26.1 --persona pedantic --min-severity low— no findings