Skip to content

feat(ci): list repos whose workflows run their own gh-actions-lock - #1251

Merged
hyperpolymath merged 1 commit into
mainfrom
claude/new-session-th4e9w-copied-lock-step
Oct 14, 2026
Merged

hyperpolymath merged 1 commit into
mainfrom
claude/new-session-th4e9w-copied-lock-step

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

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):

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.
  • 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.ai/code/session_019a95kk88TZ1iegsBK3kox3


Generated by Claude Code

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 went red whenever a current tool refreshed the lock
(proof-burrower#111/#112). Owner decision 2026-10-14: drop the step from
copied linters (pilot: proof-burrower#113, echidna#437, echidnabot#181),
and let the estate wave clear the rest.

scripts/check-copied-lock-step.sh lists every workflow that installs or
downloads gh-actions-lock itself, with the version it pins. It reports
and never edits; standards is skipped because its installs are the
estate pin. lockfile-drift-detect.yml runs it over the clones it already
makes. It adds a copied-lock-step.tsv artifact, a summary section and an
issue-table row; the workflow has no new `uses:`.

Tests: 8/8 in scripts/tests/check-copied-lock-step-test.sh. They cover:
- the raw download;
- gh extension install, pinned and unpinned;
- a KYAML run scalar;
- comment-only mentions;
- the standards skip;
- usage errors.

The "comments counted" and "standards not skipped" mutants each fail it.
Run on the three pilot repos, it flags main (v0.1.6) and passes the
fixed branches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You'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 41 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 584a23f8-1176-4dc0-bd77-3a8a9a10ffa7
📥 Commits

Reviewing files that changed from the base of the PR and between ae36881 and f74ff11.

📒 Files selected for processing: 3
  • .github/workflows/lockfile-drift-detect.yml
  • scripts/check-copied-lock-step.sh
  • scripts/tests/check-copied-lock-step-test.sh
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

run https://github.com/hyperpolymath/standards/actions/runs/38546909913

K9 normative contract typecheck

k9_contract.ncl typechecks

K9 contract self-test

== the bash mirrors cannot drift from the normative contract ==
ok   leash_levels mirrors k9_contract.ncl
ok   core_capabilities mirrors k9_contract.ncl
ok   contract_version mirrors k9_contract.ncl
ok   schema_major mirrors k9_contract.ncl
== capability arithmetic (§8) ==
ok   capability_ok fs.read accepted
ok   capability_ok rollback.apply accepted
ok   capability_ok x-acme.gpu.alloc accepted
ok   capability_ok x-acme rejected
ok   capability_ok x-.gpu rejected
ok   capability_ok fs.delete rejected
ok   capability_ok  rejected
== the extractor ==
ok   extracts pedigree.security.leash
ok   extracts pedigree.component_type
ok   extracts pedigree.metadata.name
ok   pedigree leash is not reported as top-level leash
ok   required_capabilities for a quiet component
ok   required_capabilities follows allow_network
== the envelope strip keeps line numbers (§3.6) ==
ok   line 1 becomes a comment
ok   line count is preserved
ok   schema_version stays on line 5
== L3: signature presence is not verification (§10) ==
ok   no verifier -> K9-C001 is SKIPPED, never a pass
ok   the skip states presence does not authorise 'Hunt
ok   verifier accepts -> verdict 'Verified, no K9-C001 finding
ok   verifier refuses -> K9-C001 error, verdict 'Rejected
== the fixture runner's attribution cannot be fooled by a filename ==
ok   every extracted finding is well-formed rule+layer
ok   the rule that really fired is attributed
ok   a rule named only in the filename is NOT attributed
ok   K9-C001 is present as a skipped finding
ok   and that same finding is NOT extractable as a rejection
== the dialect discriminator agrees with the coordination grammar (§4.3) ==
ok   magic file opening '---' is coordination
ok   magic file opening 'metadata:' is coordination
ok   plain file opening '---' is unclaimed
ok   plain file opening 'metadata:' is unclaimed
== no Nickel reserved word is used as an identifier ==
ok   the contract and all 27 fixtures avoid Nickel's reserved words

self-test: all assertions passed

K9 conformance fixtures

== positive controls (must pass) ==
ok   extension-capability.k9.ncl
ok   extension-fields.k9.ncl
ok   hunt-fully-granted.k9.ncl
ok   kennel-data.k9.ncl
ok   library-base.ncl
ok   yard-typed-config.k9.ncl

== negative controls (must fail, by the named rule) ==
ok   L0-K9-E001-bad-magic.k9.ncl (rejected by K9-E001 at L0)
ok   L0-K9-E002-nul-byte.k9.ncl (rejected by K9-E002 at L0)
ok   L0-K9-E003-crlf.k9.ncl (rejected by K9-E003 at L0)
ok   L0-K9-E004-no-spdx.k9.ncl (rejected by K9-E004 at L0)
ok   L0-K9-E005-unclaimed-body.k9.ncl (rejected by K9-E005 at L0)
ok   L0-K9-S012-library-with-pedigree.ncl (rejected by K9-S012 at L0)
ok   L0-K9-S014-stray-leash.ncl (rejected by K9-S014 at L0)
ok   L1-K9-S001-no-pedigree.k9.ncl (rejected by K9-S001 at L1)
ok   L1-K9-S002-wrong-major.k9.ncl (rejected by K9-S002 at L1)
ok   L1-K9-S003-todo-component-type.k9.ncl (rejected by K9-S003 at L1)
ok   L1-K9-S004-unknown-leash.k9.ncl (rejected by K9-S004 at L1)
ok   L1-K9-S005-missing-name.k9.ncl (rejected by K9-S005 at L1)
ok   L1-K9-S006-unknown-capability.k9.ncl (rejected by K9-S006 at L1)
ok   L1-K9-S007-ungranted-flag.k9.ncl (rejected by K9-S007 at L1)
ok   L1-K9-S008-hunt-signature-not-required.k9.ncl (rejected by K9-S008 at L1)
ok   L1-K9-S009-hunt-no-signature-block.k9.ncl (rejected by K9-S009 at L1)
ok   L1-K9-S010-hunt-empty-side-effects.k9.ncl (rejected by K9-S010 at L1)
ok   L1-K9-S011-recipes-at-yard.k9.ncl (rejected by K9-S011 at L1)
ok   L1-K9-S013-dangling-import.k9.ncl (rejected by K9-S013 at L1)
ok   L2-K9-N001-two-segment-version.k9.ncl (rejected by K9-N001 at L2)
ok   L2-K9-N001-wrong-field-type.k9.ncl (rejected by K9-N001 at L2)

fixtures: 6 positive, 21 negative (0 needing nickel), 0 failure(s)

K9 corpus conformance (L2)

[validate-k9] 14 conforming, 0 grandfathered (layer all, contract v1.0.0)

@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath marked this pull request as ready for review October 14, 2026 10:11
@hyperpolymath
hyperpolymath merged commit 75064de into main Oct 14, 2026
65 checks passed
@hyperpolymath
hyperpolymath deleted the claude/new-session-th4e9w-copied-lock-step branch October 14, 2026 10:11
hyperpolymath added a commit that referenced this pull request Oct 14, 2026
…-binary contract test (#1250)

## Why

gh-actions-lock v0.1.6 refuses to read a lockfile v0.0.3:

```
lockfile version v0.0.3 is newer than this binary supports (v0.0.2); upgrade the tool that reads this lockfile
```

Every current `gh actions-lock` writes v0.0.3, so a lock refreshed with
an upgraded extension fails every v0.1.6 reader:

- governance's **Actions lockfile verify** at this tree's HEAD;
- the scorecard reconciler;
- the lock regen;
- the copied `workflow-linter.yml` in 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

1. All four `gh extension install github/gh-actions-lock --pin` sites
move from v0.1.6 to v0.2.0: governance-reusable, scorecard-reusable ×2,
and dependabot-lock-regen.
2. `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-pinned` with no dependency** ("workflow has no lockfile
entry"). Accepted only when every `uses:` in the workflow is `./…` or
`$/…`, or there is none. GitHub runs these workflows without an entry:
lock-sync-gate (only `run:` 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.sh`
fails the `$/` rewrite as invalid.
- Still blocking: an unlisted workflow with a remote action, a
`not-pinned` dependency, a missing `./` action, and every other
category.
3. New `scripts/tests/gh-actions-lock-contract-test.sh` runs the
**real** binary, offline. It checks:
   - one pin version everywhere, and that the binary is that version;
   - v0.0.2 and v0.0.3 both verify, and the lock is left byte-identical;
   - a too-new lockfile is refused loudly;
- the JSON shape and the categories the verifier and
`reconcile-scorecard-actions-lock.rb` key on;
- the verifier, end to end, accepts the three false-positive classes and
rejects the four blocking cases.
4. `self-test.yml` installs the pinned release (HTTPS-only redirects,
SHA-256 checked) so the contract runs on every PR.

## Evidence

| Check | Result |
|---|---|
| Contract test on v0.2.0 | **19/19** |
| Negative control: v0.1.6 | fails 8, every v0.0.3- or v0.2.0-specific
check |
| Mutant: no dependency check | caught |
| Mutant: no nothing-to-pin check | caught |
| Mutant: no `./` existence check | caught |
| Mutant: one pin left at v0.1.6 | caught |
| No binary | exit 2 |
| `update-actions-lock-test.sh` (fake gh) | 5 new cases pass |
| gate, regen, complete-job-refs tests | pass |

Verdicts of `update-actions-lock.sh --verify-local`:

| Tree | v0.1.6 | v0.2.0 |
|---|---|---|
| echidna main | 0 | 0 |
| echidnabot main | 0 | 0 |
| standards main | 0 | 0 |
| proof-burrower main (real #110 drift) | 1 | 1 |
| proof-burrower#112 (lock v0.0.3) | **2** (cannot read) | 0 |
| rsr-template-repo main (lock v0.0.3) | **2** (cannot read) | 0 |

**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

- Pre-existing, not from this PR:
- `check-lock-sync-test.sh` and `check-actions-lock-gate-test.sh` fail
in an environment whose `awk` is mawk, or whose `yq` is the Python
wrapper; they pass with mikefarah yq.
  - actionlint v1.7.7 doesn't know `job.workflow_sha`.
- The remaining SonarCloud annotations are style smells (`[[` vs `[`,
explicit `return`) matching the surrounding scripts. The security
finding (unrestricted `curl -L` redirects) is fixed.
- For S7 (KYAML workflows): under `--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 a `uses:` inside a KYAML workflow" needs a fix-mode
measurement before it changes.

Status: TESTED (real binary, offline).

Companions:
- the copied linter step is dropped in proof-burrower#113, echidna#437
and echidnabot#181;
- #1251 (merged) lists the remaining repos for the estate wave.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants