Skip to content

test(deonboard): pin the de-onboard script to the lockfile schemas it is tested on - #53

Merged
hyperpolymath merged 3 commits into
mainfrom
claude/deonboard-schema-test
Oct 14, 2026
Merged

hyperpolymath merged 3 commits into
mainfrom
claude/deonboard-schema-test

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Follow-up to #50.

Why

gh-actions-lock v0.2.0 upgrades actions.lock from schema v0.0.2 to v0.0.3 on its next relock; marches' first Actions lock run logged Upgraded lockfile schema v0.0.2 → v0.0.3. scripts/deonboard-estate-audit.sh edits those lockfiles. Until now, only a hand check showed it still works on v0.0.3. This PR makes that check permanent, so a future v0.0.4 is caught automatically.

What v0.0.3 changes

github/actions-lockfile's own JSON schemas (schema/lockfile-v0.0.2.json vs lockfile-v0.0.3.json) differ in only two places:

  • the version const;
  • an optional per-dependency hostname, which is omitted for home-host pins and so never written on github.com.

workflows, dependencies, ref, commit, owner_id, repo_id and uses are unchanged.

Changes

  • scripts/deonboard-estate-audit.sh fails closed: exit 3, lock untouched, on any schema not in known_versions="v0.0.2 v0.0.3". A repository where the audit isn't onboarded still gets a no-op, because the check comes right before the first write.
  • tests/deonboard-lock-schemas.sh
    • Requires one fixture per known version, so the list can't grow without a test.
    • De-onboards every fixture and requires all of the following:
      • only removals, nothing added or rewritten;
      • the version line kept;
      • every reference still resolving;
      • no orphaned dependencies;
      • a second run changes nothing;
      • the same dependency keys pruned in every schema.
    • Negative controls: an untested schema (v9.9.9) is refused with the lock untouched, and a mutant that skips the prune fails the orphan check.
  • tests/fixtures/actions-lock/ holds marches' lock from before de-onboarding (e2f71fe) in three forms:
    • v0.0.2, verbatim;
    • v0.0.3, the way gh-actions-lock writes it on github.com;
    • v0.0.3 with the optional hostname on two dependencies, one that gets pruned and one that is kept.
  • CI: one more step in Composite shell contract, which now also triggers on scripts/**. There is no new uses:, so actions.lock is unchanged.
  • README: one sentence under Consuming it.

Verification

  • tests/deonboard-lock-schemas.sh: PASS=33 FAIL=0.
  • The test fails against a mutant with the version guard removed (2 FAIL) and against a mutant claiming v0.0.4 with no fixture (1 FAIL).
  • All three fixtures parse, before and after de-onboarding, with the canonical parser github.com/github/actions-lockfile/go v0.0.6, the one gh-actions-lock v0.2.0 uses. That parser rejects v0.0.2 with hostname, an unknown field, and a future version, so it is a real check. CI doesn't run it, because it would need Go; the test covers the structural properties in bash.
  • composite-shell-contract.sh: PASS=28. lock-transitive-closure.sh: PASS=8.
  • actionlint shows no new findings on code-hygiene-self-test.yml; the 5 $/actions findings are already on main.
  • shellcheck on the new test reports only the SC2015 and SC2016 notes that the existing tests also carry.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VTeVWDEJgdYKsUNr4uhnXX


Generated by Claude Code

… is tested on

gh-actions-lock v0.2.0 upgrades actions.lock from schema v0.0.2 to v0.0.3
on its next relock. Only a hand check showed that
scripts/deonboard-estate-audit.sh still worked on v0.0.3. This makes the
check permanent.

- scripts/deonboard-estate-audit.sh fails closed (exit 3, lock untouched)
  on any schema not in known_versions ("v0.0.2 v0.0.3"), so a future
  schema is a loud error rather than a silent edit across the estate.
- tests/deonboard-lock-schemas.sh needs one fixture per known version.
  It de-onboards every fixture and requires: pure removals, the version
  line kept, every reference resolving, no orphans, idempotence, and the
  same keys pruned in every schema. Negative controls: an untested schema
  is refused, and a mutant that skips the prune fails the orphan check.
- tests/fixtures/actions-lock/: marches' pre-de-onboard lock (e2f71fe)
  as v0.0.2 verbatim, as v0.0.3 the way gh-actions-lock writes it on
  github.com, and as v0.0.3 with the optional per-dependency hostname.
- Runs in "Composite shell contract", which now also triggers on
  scripts/**. No new uses:, so actions.lock is unchanged.

Schema facts come from github/actions-lockfile's own JSON schemas: v0.0.3
differs from v0.0.2 only in the version const and an optional
per-dependency hostname, omitted for home-host pins. All three fixtures
parse with the canonical parser (github.com/github/actions-lockfile/go
v0.0.6, the one gh-actions-lock v0.2.0 uses), before and after
de-onboarding. That parser rejects v0.0.2 with hostname, an unknown field,
and a future version.

Verified: deonboard-lock-schemas.sh PASS=33 FAIL=0; it fails on a mutant
with no version guard (2 FAIL) and on one claiming v0.0.4 without a
fixture (1 FAIL); composite-shell-contract PASS=28; lock-transitive-closure
PASS=8; actionlint shows no new findings on code-hygiene-self-test.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VTeVWDEJgdYKsUNr4uhnXX
@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 16 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: 4d3eb018-f0c5-4c6f-85c2-702eee1d9859
📥 Commits

Reviewing files that changed from the base of the PR and between 8bf6d92 and 0f3e05d.

⛔ Files ignored due to path filters: 3
  • tests/fixtures/actions-lock/v0.0.2.lock is excluded by !**/*.lock
  • tests/fixtures/actions-lock/v0.0.3-hostname.lock is excluded by !**/*.lock
  • tests/fixtures/actions-lock/v0.0.3.lock is excluded by !**/*.lock
📒 Files selected for processing: 4
  • .github/workflows/code-hygiene-self-test.yml
  • README.adoc
  • scripts/deonboard-estate-audit.sh
  • tests/deonboard-lock-schemas.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.

@hyperpolymath
hyperpolymath marked this pull request as ready for review October 14, 2026 13:42
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
@hyperpolymath
hyperpolymath merged commit fe13738 into main Oct 14, 2026
13 of 16 checks passed
@hyperpolymath
hyperpolymath deleted the claude/deonboard-schema-test branch October 14, 2026 14:19
@sonarqubecloud

Copy link
Copy Markdown

hyperpolymath added a commit that referenced this pull request Oct 19, 2026
… the schema guard and the case fix (#56)

## What was wrong

`scripts/deonboard-workflow.sh` (#54) is a copy of the estate-audit
de-onboard script, taken before #52 and #53 landed. It has neither fix:

1. **No schema guard.** It accepts any `actions.lock` schema. On a
`v9.9.9` lock it exits 0 and edits the lock. #53's fail-closed guard
(exit 3) lives only in `deonboard-estate-audit.sh`.
2. **Case-sensitive prune.** It compares dependency keys byte for byte.
Take a lock where the `hyperpolymath/standards` record reaches
`swatinem/rust-cache@6323deb…` but the record key is
`Swatinem/rust-cache@6323deb…`. The script prunes that record and leaves
a dangling edge, which startup-fails the run. This is the januskey shape
#52 fixed, but only in the estate-audit copy.

**Who was exposed:** `rollout_language_gates.sh` de-onboards every Rust
CI, Creusot, SPARK and miniKanren caller through
`deonboard-workflow.sh`. Rust CI callers are exactly the repositories
whose locks carry the `standards` → `rust-cache` edge.

As far as this session knows, no rollout has run since #54 merged, so
this is a latent defect rather than a broken estate. That is ASSUMED: I
have no rollout logs.

The `deonboard-workflow.sh` header and README line 273 on main already
said the estate-audit script "now delegates" to it. It did not; it was a
second copy.

## The change

- **`scripts/deonboard-workflow.sh`** is now the one implementation. It
carries #53's `known_versions` guard and #52's `lower_repo` prune, with
their comments carried over verbatim.
- **`scripts/deonboard-estate-audit.sh`** is now just a usage check and
one `exec …/deonboard-workflow.sh "$repo"
.github/workflows/main-estate-audit.yml`. `rollout_estate.sh`, the
templates and the README keep working through it unchanged.
- **`tests/deonboard-lock-schemas.sh`**:
  - It reads `known_versions` from the generic script.
  - Every fixture and the v9.9.9 control run through both entry points.
- The prune-skipping mutant is applied to the generic script and must be
killed through the wrapper as well, which fails if the wrapper ever
stops delegating.
  - The optional argument is now a scripts directory.
- **`tests/deonboard-estate-audit.sh`** (#52):
  - Both entry points run the same checks.
  - The two entry points must produce byte-identical locks.
- The `| lower_repo` mutant is applied to the generic script and must be
killed through both.
- **CI** (`code-hygiene-self-test.yml`):
- `tests/deonboard-estate-audit.sh` was never run in CI. It now runs in
the Composite shell contract job.
  - The workflow also triggers on `scripts/deonboard-workflow.sh`.
  - No `uses:` added.
- **Docs:** README and ARCHITECTURE now describe the delegation as it
is.
- **Ported from #55:** `3325927` is #55's repin, cherry-picked with
`-x`; the diff is byte-identical.
- **Why:** main's `lock-transitive-closure` failure would otherwise stop
the Composite shell contract job before the de-onboard steps run.
  - **If #55 merges first:** this commit becomes a no-op.

## Evidence (TESTED)

I copied the new suites into a tree of `origin/main` (`9a947fa`) and ran
them against main's scripts.

`tests/deonboard-estate-audit.sh`: PASS=14 FAIL=4
- `FAIL pruned Swatinem/rust-cache, which the standards record still
reaches`
- `FAIL dangling edge(s):
Swatinem/rust-cache@6323deb`
- `FAIL the entry points disagree: …`
- `FAIL mutant is identical to the script: the case-folding the test
exists for is gone`

`tests/deonboard-lock-schemas.sh`: PASS=57 FAIL=4
- `FAIL script declares no known_versions`
- `FAIL exit 0 on schema v9.9.9 (want 3)`
- `FAIL lock modified despite refusal`
- `FAIL orphan check passed a mutant that does not prune` (main's
wrapper does not delegate)

On this branch:

| Check | Result |
| --- | --- |
| `tests/deonboard-estate-audit.sh` | PASS=19 FAIL=0 |
| `tests/deonboard-lock-schemas.sh` | PASS=63 FAIL=0 |
| `tests/lock-transitive-closure.sh` | PASS=31 FAIL=0 |
| `tests/composite-shell-contract.sh` | PASS=28 FAIL=0 |
| `bash -n` | clean |
| `shellcheck -S warning` | clean (default severity: same SC2015/SC2016
counts as main) |
| `actionlint` | no new findings (the 8 `"$/actions/…"` findings in the
hygiene self-test are also on main) |

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

https://claude.ai/code/session_01VTeVWDEJgdYKsUNr4uhnXX

---------

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