Repository navigation
fix(ci): move the estate's gh-actions-lock pin to v0.2.0, with a real-binary contract test - #1250
Conversation
…-binary contract test
v0.1.6 refuses to read lockfile v0.0.3 ("newer than this binary
supports"), and every current `gh actions-lock` writes v0.0.3. One lock
refreshed with an upgraded extension therefore failed every v0.1.6
reader: governance's Actions lockfile verify at this tree's HEAD, the
scorecard reconciler, the lock regen, and each repo's copied
workflow-linter (proof-burrower#111/#112).
v0.2.0 reads v0.0.2 and v0.0.3. On the main locks of echidna,
echidnabot, proof-burrower and standards, scripts/update-actions-lock.sh
--verify-local gives the same verdict under both versions.
scripts/tests/gh-actions-lock-contract-test.sh runs the real binary
(offline, --verify-local) and pins the contract the lock tooling relies
on:
- every pin in .github/workflows/ names one version;
- both lockfile versions are read;
- a too-new lockfile is refused loudly;
- the JSON shape and the four finding categories are as expected;
- update-actions-lock.sh accepts reusable-workflow coverage and rejects
a real desync.
12/12 on v0.2.0. Negative controls: v0.1.6 fails 6 of 12, disagreeing
pins fail 2, and no binary exits 2. self-test.yml installs the pinned
release, checked against its SHA-256.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 40 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
K9 contract conformancerun https://github.com/hyperpolymath/standards/actions/runs/38546323549 K9 normative contract typecheckK9 contract self-testK9 conformance fixturesK9 corpus conformance (L2) |
On standards' own tree, governance's Actions lockfile verify failed
under v0.2.0. v0.2.0 reports two categories v0.1.6 never did, and both
contradict what GitHub and the estate measure.
- `not-pinned` with no dependency ("workflow has no lockfile entry").
A v0.1.6-written lock omits workflows that have nothing to pin.
GitHub runs them without an entry: lock-sync-gate (only `run:`
steps), and scorecard, secret-scanner and self-ci (only ./ reusable
calls) all succeed on main. The finding is accepted only when every
`uses:` in the workflow is ./… or $/…, or there is none.
- `local-action` with no dependency ("local path actions are not
supported; rewrite to $/…"). The estate measured the opposite:
check-lock-sync.sh fails the `$/` spelling as an invalid rewrite. The
finding is accepted only when every ./ action the workflow uses
exists in the checkout.
Any other finding still blocks: an unlisted workflow with a remote
action, a not-pinned dependency, or a missing ./ action.
Evidence:
- update-actions-lock-test.sh adds 5 cases (fake gh).
- gh-actions-lock-contract-test.sh: 19/19 on the real v0.2.0 binary.
The rule mutants (no dependency check; no nothing-to-pin check; no
existence check) are each caught.
- Verdicts across six trees, v0.1.6 vs v0.2.0:
- echidna, echidnabot and standards main: identical;
- proof-burrower main: identical (red for real drift);
- proof-burrower#112 and rsr-template-repo, both v0.0.3 locks: v0.1.6
exits 2 (cannot read); v0.2.0 passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
…1251) ## Why A sweep copied a "Verify immutable action lockfile" step into repos' `workflow-linter.yml`. The step downloads gh-actions-lock **v0.1.6** and runs it raw, beside governance's lockfile gate. v0.1.6 cannot read lockfile v0.0.3, so the step goes red whenever a current tool refreshes a repo's lock. That is what failed "Workflow Security Linter / lint-workflows" on proof-burrower#111/#112. The step didn't come from rsr-template-repo; that template's linter never had it. So fixing the template wouldn't reach the repos that carry it, and the estate needs a list of them. Owner decisions 2026-10-14 (selector): - drop the step from copied linters; - pilot first: proof-burrower#113, echidna#437 and echidnabot#181; - clear the rest of the estate in the wave; - move the estate's own pin to v0.2.0 in #1250. ## What - `scripts/check-copied-lock-step.sh REPO_DIR [SLUG]` lists every workflow that downloads or installs gh-actions-lock itself, with the version it pins. Output is TSV: `repo workflow pins`. - Exit codes: 0 none found, 1 found, 2 usage error. - Report-only; it never edits. - standards is skipped, because its installs are the estate pin, which `gh-actions-lock-contract-test.sh` (#1250) holds to one version. - `lockfile-drift-detect.yml` (weekly, report-only) runs the detector over the clones it already makes. It adds a `copied-lock-step.tsv` artifact, a step-summary section and a row in the tracking issue's table. There's no new `uses:`, so `actions.lock` is unchanged. ## Evidence - `scripts/tests/check-copied-lock-step-test.sh`: **8/8**. Cases: - raw download, with version extraction; - `gh extension install`, pinned and unpinned, one row per workflow; - a KYAML `run:` scalar; - comment-only mentions are not counted; - standards skipped; - no workflows; - usage errors. - Mutants "comments counted" and "standards not skipped" each fail the suite. - Real repos: it flags `main` of proof-burrower, echidna and echidnabot (v0.1.6), and finds nothing on their fixed branches. - actionlint clean; duplicate-key check clean; the sweep's `run:` passes `bash -n`. Status: TESTED locally. It hasn't run live yet; the first scheduled or dispatched sweep after merge produces the wave's list. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3 --- _Generated by [Claude Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_ Co-authored-by: Claude <noreply@anthropic.com>
K9 contract conformancerun https://github.com/hyperpolymath/standards/actions/runs/38547814413 K9 normative contract typecheckK9 contract self-testK9 conformance fixturesK9 corpus conformance (L2) |
SonarCloud rated #1250's new code C for security: `curl -fsSL` follows redirects with no protocol restriction. The fix uses the estate idiom from ci-pipeline.yml and k9-contractile.yml (--proto '=https' --proto-redir '=https' --tlsv1.2). The download was re-fetched with these flags and still matches the pinned SHA-256. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
…com/hyperpolymath/standards into claude/new-session-th4e9w-lock-v020
K9 contract conformancerun https://github.com/hyperpolymath/standards/actions/runs/38547862332 K9 normative contract typecheckK9 contract self-testK9 conformance fixturesK9 corpus conformance (L2) |
K9 contract conformancerun https://github.com/hyperpolymath/standards/actions/runs/38547927873 K9 normative contract typecheckK9 contract self-testK9 conformance fixturesK9 corpus conformance (L2) |
|
…w linter (#113) ## Summary "Workflow Security Linter / lint-workflows" has failed on every `main` push since 2026-10-05, and now on #111/#112. It failed for two reasons, both caused by the copied "Verify immutable action lockfile" step: - **Version skew.** The step pins its own gh-actions-lock **v0.1.6**, which cannot read lockfile **v0.0.3**: ``` lockfile version v0.0.3 is newer than this binary supports (v0.0.2) ``` Every current `gh actions-lock` writes v0.0.3, including the regeneration in #112. - **Duplicate verifier.** It ran a second lock check beside governance's, with its own version pin. That pin drifts from the estate's, and the raw tool doesn't apply the reusable-workflow coverage rule that governance's verifier applies. Governance's **Actions lockfile verify** (standards `scripts/update-actions-lock.sh`) is the single tested implementation. This PR removes the duplicate step and leaves a comment pointing at the gate. Owner decision 2026-10-14 (selector): drop the lock step from copied linters, and move the estate to gh-actions-lock v0.2.0 (hyperpolymath/standards#1250). Pilot repos first: proof-burrower, echidna, echidnabot. The rest of the estate follows in the wave. ## Changes - `.github/workflows/workflow-linter.yml`: the pinned-binary lock step is replaced by a comment. The SPDX, permissions and duplicate-workflow checks are unchanged. - No `uses:` changes, so `actions.lock` is untouched. ## RSR Quality Checklist ### Required - [x] Tests pass: the remaining linter steps are unchanged. - [x] Code is formatted (n/a, YAML only). - [x] Linter is clean: actionlint v1.7.7 clean; the workflow duplicate-key check is clean. - [x] No banned language patterns. - [x] No `unsafe` blocks without `// SAFETY:` comments (n/a). - [x] No banned functions (n/a). - [x] SPDX license headers present on all new/modified source files. - [x] No secrets, credentials, or `.env` files included. ### As Applicable - [ ] `.machine_readable/descriptiles/STATE.a2ml` updated (n/a; A2ML is retired) ## Testing - Reproduced the failure locally with the release binaries: v0.1.6 `--rescan --no-fix` on #111's lock exits 2 with the message above. - Governance's verifier still covers this repo: governance.yml pins standards 8f2ee508, whose `actions-lock-verify` job passed on #111/#112. - This repo's `main` lock is stale (#110). It stays red under governance's gate until #112 lands, which is the intended behaviour. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3 --- _Generated by [Claude Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
…w linter (#437) ## Summary The copied "Verify immutable action lockfile" step in `workflow-linter.yml` pins its own gh-actions-lock **v0.1.6**, which cannot read lockfile **v0.0.3**. Every current `gh actions-lock` writes v0.0.3, so the step fails the first time a current tool refreshes this repo's lock. That has already happened in proof-burrower (#111/#112 there). The step was also a second verifier with a second version pin. Governance already verifies the lock through standards `scripts/update-actions-lock.sh`. This repo's governance pin (571cc734) runs it inside its workflow-lint job. That is one tested implementation, with one pin, and it accepts reusable-workflow coverage. Owner decision 2026-10-14 (selector): drop the lock step from copied linters, and move the estate to gh-actions-lock v0.2.0 (hyperpolymath/standards#1250). Pilot repos first: proof-burrower, echidna, echidnabot. ## Changes - `.github/workflows/workflow-linter.yml`: the pinned-binary lock step is replaced by a comment pointing at the governance gate. The issue-regression and allow-fail steps are unchanged. - No `uses:` changes, so `actions.lock` is untouched. ## RSR Quality Checklist ### Required - [x] Tests pass: `scripts/ci/test-issue-regressions.sh` passes. - [x] Code is formatted (n/a, YAML only). - [x] Linter is clean: actionlint v1.7.7 clean; the workflow duplicate-key check is clean. - [x] No banned language patterns. - [x] No `unsafe` blocks without `// SAFETY:` comments (n/a). - [x] No banned functions (n/a). - [x] SPDX license headers present on all new/modified source files. - [x] No secrets, credentials, or `.env` files included. ## Testing - Standards `update-actions-lock.sh --verify-local` on this branch passes (exit 0) under both gh-actions-lock v0.1.6 and v0.2.0. - `lint-workflows` is green on `main` today. This removes the failure before it happens rather than fixing a red check. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3 --- _Generated by [Claude Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_ Co-authored-by: Claude <noreply@anthropic.com>
…w linter (#181) ## Summary The copied "Verify immutable action lockfile" step in `workflow-linter.yml` pins its own gh-actions-lock **v0.1.6**, which cannot read lockfile **v0.0.3**. Every current `gh actions-lock` writes v0.0.3, so the step fails the first time a current tool refreshes this repo's lock. That has already happened in proof-burrower. The step was also a second verifier with a second version pin. Governance's **Actions lockfile verify** job (this repo pins standards fad242d3, which has it) already runs standards `scripts/update-actions-lock.sh`. That is one tested implementation, with one pin, and it accepts reusable-workflow coverage. Owner decision 2026-10-14 (selector): drop the lock step from copied linters, and move the estate to gh-actions-lock v0.2.0 (hyperpolymath/standards#1250). Pilot repos first: proof-burrower, echidna, echidnabot. ## Changes - `.github/workflows/workflow-linter.yml`: the pinned-binary lock step is replaced by a comment pointing at the governance gate. The SPDX and permissions checks are unchanged. - No `uses:` changes, so `actions.lock` is untouched. ## Testing - actionlint v1.7.7 clean; the workflow duplicate-key check is clean. - Standards `update-actions-lock.sh --verify-local` on this branch passes (exit 0) under both gh-actions-lock v0.1.6 and v0.2.0. - `lint-workflows` is green on `main` today. This removes the failure before it happens rather than fixing a red check. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3 --- _Generated by [Claude Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_ Co-authored-by: Claude <noreply@anthropic.com>
Resolves the one conflict, in .github/workflows/self-test.yml: this branch and main (#1250) both add setup steps after the ijson-jcs install. Both blocks are kept: the Bun, Deno and pnpm setup this branch needs for js-runtimes-test.sh, then main's hash-checked gh-actions-lock install for gh-actions-lock-contract-test.sh. actions.lock merged cleanly; every uses: in the merged workflow is keyed in it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4U5XuN4NWs8FTxoe5PuH7
…weep (#1248) ## What `dependabot-lock-regen.yml` only repaired **open** Dependabot and applier PRs. A stale `actions.lock` that had already reached a default branch stayed stale. That happened with proof-burrower#110, which dependabot-automerge merged red because "Actions lockfile verify" is not a required check. After that, every caller workflow in the repo hits `startup_failure` and its required checks never report. proof-burrower#111 sat on "analyze (actions, none) — Expected" for this reason. This PR adds a default-branch repair mode, `REGEN_MAIN=1`: - **When it runs.** A new daily `41 4 * * *` tick, or a dispatch with `main-repair: true`. The half-hourly ticks behave as before. - **What it does.** For each repo it runs the same repair chain on the default branch: 1. `gh actions-lock` 2. relock-sha-keys 3. complete-job-refs 4. close-lock 5. prune-stale 6. `--verify-local` 7. `check-lock-sync.sh` If the lock changes, it creates `chore/regenerate-actions-lock` from the default-branch head, commits the lock through `createCommitOnBranch` (with `expectedHeadOid`), and opens one lock-only PR. - **Safety.** - It skips a repo that already has the repair PR open. - It skips a repo whose default branch moved during the run. - It skips an unverified regeneration. - It reuses an existing repair branch only when the branch's head commit is its own leftover repair commit. It never force-moves a branch it did not write. - `select_prs` now also matches bot-authored PRs from the repair branch, so later sweeps keep that PR's lock current. - **No new `uses:`.** The gh-actions-lock pin is the estate pin, which matches the governance reusable workflow. Since `main` was merged in (58d3c80, carrying #1250), both are v0.2.0. `scripts/tests/gh-actions-lock-contract-test.sh` holds every install to one version. ## Owner action this depends on (decision O11, "App + regen + required") The workflow is `disabled_manually` and the applier App doesn't exist yet. To turn this on: 1. Create the applier App with Contents R/W, Workflows R/W and **Pull requests R/W** (R/W is new for this mode). 2. Install it on both owners. 3. Set `vars.APP_ID` and `secrets.APP_PRIVATE_KEY` on standards. 4. Re-enable `dependabot-lock-regen.yml`. After one green sweep, the follow-up makes "Actions lockfile verify" required, so a red lock can no longer auto-merge. ## Evidence - `scripts/tests/regen-dependabot-locks-test.sh`: **59/59 pass**. New cases: - stale lock → PR opened; - current lock → no-op; - dry run; - unverified regeneration; - default branch moved; - repair PR already open; - `select_prs`, bot vs human author; - foreign branch refused; - own leftover reused; - PR creation refused; - `REGEN_MAIN` wiring on and off. - Mutants: "always force-move the branch" and "ignore an open repair PR" each fail the suite. - `bash -n`: clean. actionlint v1.7.7: clean. Workflow duplicate-key check: clean. Status: TESTED (stubbed `gh`, local fixture clone). Not yet run live, because the App is absent. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3 --- _Generated by [Claude Code](https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3)_ Co-authored-by: Claude <noreply@anthropic.com>
…in (#7) ## Summary **This fixes `governance / Actions lockfile verify`, red on `main`.** It is the follow-up promised in #4. At `da2c748`, governance's lock gate had two problems: - it checked out its scripts at a fixed helper pin (`874ffe5`); - it installed gh-actions-lock unpinned. Under v0.2.0, the verifier accepted each of the seven job-level reusable refs as coverage ("Accepted reusable-workflow lock coverage …"). It still failed, because v0.2.0 reports those refs as `stale` at `error` severity, and that old verifier failed on any error-severity finding. hyperpolymath/standards#1250 fixed this: the verifier decides by category, gh-actions-lock is pinned to v0.2.0, and the gate runs at the reusable's own commit (`job.workflow_sha`). ## Changes - **Six workflows** move from `hyperpolymath/standards@da2c748` to `@934b879f6068295e42dac20d80e010d555ebec82` (standards `main`): governance, hypatia-scan, mirror, rust-ci, scorecard and secret-scanner. - **`actions.lock`**, repaired with standards' own chain (`complete-job-refs.sh` → `close-lock.sh` → orphan prune): - The `hyperpolymath/standards` record is rewritten at the new pin. Its `uses:` is the union over the called workflows. - The new union adds four refs, each now with its own record: `oven-sh/setup-bun` and `denoland/setup-deno` (from the js-runtimes jobs that #1249 added to governance), plus `actions/upload-artifact@cf430e0` and `dtolnay/rust-toolchain@e2a55d2`. - The old `da2c748` record is removed, along with the three refs only it named. - The repair ran offline. `close-lock.sh`'s `GH_BIN` stub answered from local git (standards and cicd-suite) and from ids already recorded in estate locks. Where the stub can't answer, close-lock skips the ref (exit 3) and writes no guessed record. - **`CHANGELOG.adoc`**: an entry. **What the new pin brings.** Governance at `934b879` includes the js-runtimes jobs from standards#1249. This repo has no `package.json`, so they pass with a notice (denominator 0). ## RSR Quality Checklist ### Required - [x] Tests pass (see Testing) - [x] Code is formatted - [x] Linter is clean - [x] No banned language patterns - [x] No `unsafe` blocks without `// SAFETY:` comments - [x] No banned functions - [x] SPDX license headers present on all new/modified source files (unchanged headers; no new files) - [x] No secrets, credentials, or `.env` files included ### As Applicable - [x] `CHANGELOG` or release notes updated ## Testing Run with the real gh-actions-lock v0.2.0 (`linux-amd64`, SHA-256 `79ec84c1…` as pinned in standards' `self-test.yml`) and mikefarah yq v4.44.3: | Gate scripts | Tree | Result | |---|---|---| | `da2c748`-era (`874ffe5`) | resource-algebra `main` | **exit 1**: `lockfile verification FAILED`, the same failure CI shows | | standards `main` (`934b879`) | resource-algebra `main` | exit 0 | | standards `main` (`934b879`) | this branch | exit 0: `Immutable direct and transitive lockfile coverage verified.` | ``` ./scripts/check-lock-sync.sh * every lockfile entry is still referenced * every ref named in the lockfile resolves to a dependencies: record (0 dangling edges) * every workflow file has a lockfile key (zero-uses: workflows included) ``` Still red on `main`, and not this PR's: `openssf-compliance` and `call-estate-audit` (as noted on #4). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Y6FD63UrriRBHqmhhEca9t --- _Generated by [Claude Code](https://claude.ai/code/session_01Y6FD63UrriRBHqmhhEca9t)_ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated the project’s automated governance, security scanning, mirroring, and Rust CI checks. These maintenance changes do not add or remove user-facing features. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…928) ## Why gh-actions-lock v0.2.0 writes lockfile **v0.0.3**, and the estate's lock gate now pins v0.2.0 (hyperpolymath/standards#1250). `Hypatia.Rules.ActionsLock` accepts only v0.0.2. - **Other repositories:** any repo whose lock is regenerated with the estate's tool fails closed with: ``` invalid_actions_lock: {:line, 4, {:unsupported_version, "v0.0.3"}} ``` The finding comes from both `workflow_audit` and `workflow_hardening`, at high severity. It happened on hyperpolymath/palimpsest-license#177 as code-scanning alerts 347 and 349. - **This repository:** Hypatia's own `actions.lock` has been v0.0.3 since #926. Its existing test `"parses the repository's authoritative generated lockfile"` therefore fails against the unpatched module. ## What **114d015.** For github.com dependencies, v0.0.3 uses the v0.0.2 line grammar. I measured this on this repo's lock and on `rsr-template-repo`'s, both v0.0.3: - the same `workflows:` and `dependencies:` sections; - the same record fields (`ref`, `commit`, `owner_id`, `repo_id`, `uses`); - the same `'<path>': []` form for a workflow with nothing to lock. So: - `@supported_version "v0.0.2"` becomes `@supported_versions ["v0.0.2", "v0.0.3"]`, both parsed by the one strict grammar. - Every other version string is still `{:unsupported_version, v}`, and a second `version:` line is still `:duplicate_version`. **a50c0e5** is for CodeRabbit's finding on #929. v0.0.3 adds one optional per-dependency field, `hostname`. The v0.2.0 binary has `json:"hostname,omitempty"`, and it is written only for GHE.com data-residency tenants, never for github.com. Neither real v0.0.3 lock in the estate carries it. Rather than model multi-host identity for hosts the estate doesn't use: - `hostname: 'github.com'` is accepted, as the default it states; - any other host is refused by name, `{:unsupported_dependency_hostname, host}`; - in a v0.0.2 lock, the field is still malformed. The moduledoc records both points. ## Tests `test/rules/actions_lock_test.exs` gains three cases: - v0.0.3 is accepted with the same association semantics, and a malformed v0.0.3 lock still fails closed. - `v0.0.1`, `v0.0.4`, `v0.1.0` and a bare `0.0.3` are each refused, and a second version line is a duplicate. - `hostname` behaves as listed above, including a duplicate `hostname` line. I couldn't run the full suite in my sandbox, because repo.hex.pm is blocked there, so `mix deps.get` cannot run. Instead I ran this test file standalone against the compiled module with Elixir 1.14. I left out only the legacy `Hypatia.Rules` case, which needs the full engine. | Module | Result | |---|---| | patched | **15 / 15 pass** | | unpatched (`main`) | the own-lock test fails | The patched parser also reads four real locks: - this repo's: v0.0.3, 40 dependencies; - rsr-template-repo's: v0.0.3, 37; - palimpsest-license's: v0.0.2, 38; - standards': v0.0.2, 26. `lib/rules/actions_lock.ex` is formatter-clean. I left the untouched test lines as CI's Elixir 1.17 formatter has them. ## Relation to #929 #929 merges this branch unchanged (114d015 and a50c0e5), so CI there exercises this code too. The two PRs merge in either order. ## Follow-up When this merges, standards' `hypatia-scan-reusable.yml` and `governance-reusable.yml` can move their default `hypatia-ref` from `51ab649` to the merge commit. That makes the estate scanner accept v0.0.3 locks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LET2eHeDbN3b4WuxYjMUX9 --------- Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>



Why
gh-actions-lock v0.1.6 refuses to read a lockfile v0.0.3:
Every current
gh actions-lockwrites v0.0.3, so a lock refreshed with an upgraded extension fails every v0.1.6 reader:workflow-linter.ymlin each repo.That is what turned proof-burrower#111/#112 red. rsr-template-repo's lock is already v0.0.3.
Owner decision (selector, 2026-10-14): move the estate to v0.2.0.
What
gh extension install github/gh-actions-lock --pinsites move from v0.1.6 to v0.2.0: governance-reusable, scorecard-reusable ×2, and dependabot-lock-regen.scripts/update-actions-lock.sh(the one lock verifier) narrowly accepts the two new v0.2.0 finding classes. v0.1.6 never reported them, and both contradict measured behaviour:not-pinnedwith no dependency ("workflow has no lockfile entry"). Accepted only when everyuses:in the workflow is./…or$/…, or there is none. GitHub runs these workflows without an entry: lock-sync-gate (onlyrun:steps), and scorecard, secret-scanner and self-ci (only./reusable calls), all green on main.local-action("local path actions are not supported, rewrite to$/…"). Accepted only when every./action the workflow uses exists in the checkout. The estate measured the reverse:check-lock-sync.shfails the$/rewrite as invalid.not-pinneddependency, a missing./action, and every other category.scripts/tests/gh-actions-lock-contract-test.shruns the real binary, offline. It checks:reconcile-scorecard-actions-lock.rbkey on;self-test.ymlinstalls the pinned release (HTTPS-only redirects, SHA-256 checked) so the contract runs on every PR.Evidence
./existence checkupdate-actions-lock-test.sh(fake gh)Verdicts of
update-actions-lock.sh --verify-local:Correction to the first version of this PR. I first reported "identical verdicts on four repos" from exit codes alone. That hid the two new categories on standards, which made this PR's first self-lint red. Item 2 fixes that, and the table above now compares the categories as well as the exit codes.
Notes
check-lock-sync-test.shandcheck-actions-lock-gate-test.shfail in an environment whoseawkis mawk, or whoseyqis the Python wrapper; they pass with mikefarah yq.job.workflow_sha.[[vs[, explicitreturn) matching the surrounding scripts. The security finding (unrestrictedcurl -Lredirects) is fixed.--verify-local, v0.1.6 and v0.2.0 gave identical findings on a KYAML fixture. YAML-POLICY.adoc's "v0.1.6 cannot see auses:inside a KYAML workflow" needs a fix-mode measurement before it changes.Status: TESTED (real binary, offline).
Companions:
🤖 Generated with Claude Code
https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3