ci(deps): carry licence rows forward automatically, so an action bump stops holding the lane - #803
Conversation
CLOUD-1213 `sbom-check`'s licence table needs a human on every action pin move, and only a person can regenerate it
Why Found while fixing CLOUD-1207 and deliberately not repaired there, because
What #771 already settled, so this row is smaller than when it was filed The original body carried two concerns. The second — that the lane burned CI So what remains is only the first: should this class need a person at all? A correction to the measurement above (2026-08-31) This row said *"Measured on #676: 34 × * The options
Refinement — Ready Refinement gate: Definition of Ready & Done. This body carries only specializations.
{
"source_of_truth": "mise-tasks/sbom-actions.tsv",
"gate": { "task": "sbom-check", "exits": [0, 1] },
"commit_type": "ci",
"blockers": [],
"tests": [
{
"file": "tests/sbom-check.bats",
"mutation": "drop the per-pin unmapped loop, so a moved action pin reports mapped"
}
]
}REOPENED 2026-09-01. Closed against #788 with §2's Option 1 never built — Acceptance
|
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughAdded the Merge Risk: ⚪ Minimal · up to This PR adds a localized scheduled workflow for carrying licence rows forward when action licence files are unchanged; no actionable merge-blocking risk remains after normal checks and review. Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing. Comment |
… stops holding the lane CLOUD-1213 §2's Option 1, which that row was closed against and never built — `git grep -l sbom-actions -- .github/` returned nothing across 25 workflow files, and the class reproduced immediately on #676: nine days open, 36 `sbom-action-unmapped` findings, holding `prConcurrentLimit: 1` against four queued updates until it was cleared by hand. WHY NO OTHER SURFACE COULD CARRY IT. `sbom-check.sh` is frozen by `V-SHELL-RULE-EDITED` and its port is blocked on CLOUD-1265's tool-verdict producer. A new `crates/batten` verb is refused outright by CLOUD-1159 §1 ("no new `crates/batten` verb") whose HOMES section says Batten does not grow an SBOM subsystem. A new `mise-tasks/*.sh` would need a `# stays-bash:` declaration owning an increase against a campaign retiring 144 programs. A workflow on a clock is what is left, and it is what §2 decided. IT DEPARTS FROM §2's LITERAL WORDING IN ONE WAY, DELIBERATELY. §2 says "fetches each new pin's LICENSE bytes at its sha" and writes the rows. That re-derives a verdict, and the table's own header records four rows where a naive read gets it WRONG: LGPL boilerplate mistaken for the project's copyright holder, a dual-licensed action whose single-file read would have recorded MIT alone, a holder with no year. Automating the derivation would reproduce CLOUD-629's class at the rate of every bump. So it never derives a licence. It CARRIES AN EXISTING ROW FORWARD to a new sha, and only when every candidate licence file is byte-identical between the mapped sha and the new one — identical bytes mean the judgement already recorded was made about those exact bytes and still holds. A repository with no row, or any licence file added, removed or changed, is reported as a warning and left for a person. That is §2's Option 3 refused rather than smuggled in. Keying by action name would delete the drift detector; this keeps it firing on real drift and stops it firing only where there provably is none. It writes its own PR against `main` and never the bot's head, preserving the update lane's decision never to check a bot branch out under a write token — the same route the rows added on 2026-08-31 took. Two defects found and fixed in this file before it landed: heredoc terminators inside a YAML block scalar keep the block's indentation and are a runtime-only syntax error, so the PR body and commit message are built with `printf`; and shellcheck reads the markdown backticks in those strings as command substitution, which is a false positive disabled with its reason at the site. Verified: `actionlint` clean, `zizmor` clean over 26 workflows. Refs: CLOUD-1213, CLOUD-1159, CLOUD-629 Admits: 8dce613c87a56209018583ae31368c2a68d1002ef5db00f9635bdeb7beff5f6c Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: .github/workflows/sbom-actions-currency.yml Admits-head: a673667 Admits-epoch: 6653a7e618ce30bcce12361e2d99a731c68d00143157f0e3af4be10ca574ba0b Admits-author: alec@wenzowski.com Admits-prev: - Admits-answer-lost: Nothing existing is changed. This adds one schedule-only workflow; no `pull_request` job, no existing workflow edited, no gate's verdict altered. `sbom-check` keeps its predicate and its drift detector exactly as they are — the workflow only supplies rows for pins whose licence bytes are provably unchanged, so the class of drift the gate exists to catch still fails it. Admits-answer-precondition: CLOUD-1213 §2 decided this fix as "a workflow on `main`, shaped like `.github/workflows/lock-currency.yml`", and a workflow can only be expressed as a file under `.github/workflows/` — no other surface runs on a clock or can open a pull request. The three alternatives are each closed by a landed decision: CLOUD-1159 §1 says "no new `crates/batten` verb" and its HOMES section says Batten does not grow an SBOM subsystem; `sbom-check.sh` is frozen by V-SHELL-RULE-EDITED and its port is blocked on CLOUD-1265; and a new `mise-tasks/*.sh` would need a `# stays-bash:` declaration owning an increase against a campaign retiring 144 programs. The write is one a reviewer sees in the diff it lands in, and the file is new rather than an edit to an existing workflow. Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE does not reach it: `.github/workflows/` IS the owning surface for a workflow, and no config row or policy module can schedule a job or open a pull request. R-RESTORE-IT would leave the update lane blocked by hand-maintenance on every action bump, which is the defect CLOUD-1213 was reopened for.
…le minute Two findings from `batten-check` on the previous commit, both correct. NO TOKEN IN A URL. `no-secrets` refused the push, which embedded the token in the remote URL as userinfo. That is not a false positive: git writes the URL into `.git/config` and echoes it in any error it prints about the remote, so the credential outlives the step and reaches the run log. `gh auth setup-git` installs gh as git's credential helper instead, and the push authenticates from $GH_TOKEN in the environment with the token in no URL, no argv and no log line. The gate then refused the FIX's own comment, which quoted the bad spelling to explain it. Also correct, and left standing rather than waived: a pattern is a pattern wherever it appears, and a comment carrying the literal is exactly the thing that gets copied. The shape is described now instead of reproduced. SCHEDULE COLLISION. `schedules-do-not-collide` refused `0 5 * * *`, which `perf.yml` already owns. Two runners starting on the same minute is a queue, and the perf series is the one measurement a queue distorts — the gate is protecting the numbers `perf-gate` compares against. Moved to `40 5 * * *`, which no workflow holds. Refs: CLOUD-1213 Admits: e03b883be1a24354b6eaeedb59a2c39f16052d832ef6dde2ceab292ca964fa5b Admits-rule: protected-mutation Admits-verdict: V-PROTECTED-MUTATION Admits-subject: .github/workflows/sbom-actions-currency.yml Admits-head: 0e65771 Admits-epoch: 6653a7e618ce30bcce12361e2d99a731c68d00143157f0e3af4be10ca574ba0b Admits-author: alec@wenzowski.com Admits-prev: 8dce613c87a56209018583ae31368c2a68d1002ef5db00f9635bdeb7beff5f6c Admits-answer-lost: Nothing. No other workflow is touched, no job's behaviour changes beyond the two repairs, and both make the file strictly safer: the token stops reaching `.git/config` and the run log, and the schedule stops queueing a runner against the perf series that `perf-gate` compares. Admits-answer-precondition: The write repairs two findings `batten-check` raised against this same workflow file — a credential embedded in a push URL, and a cron minute `perf.yml` already owns — and a workflow's only expressible home is a file under `.github/workflows/`. No config row, policy module or task can change a job's schedule or how its push authenticates. The change is one a reviewer sees in the diff it lands in. Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular — `.github/workflows/` IS the owning surface for a workflow. R-RESTORE-IT would restore the credential-in-URL and the colliding cron, which are exactly the two defects this commit exists to remove.
7d60898 to
a6013ff
Compare
|
❌ The last analysis has failed. |
|
/fast-forward |
What this is
CLOUD-1213 §2's Option 1, which that row was closed against on 2026-09-01 and never built.
git grep -l sbom-actions -- .github/returned nothing across 25 workflow files, and the class reproduced immediately: #676 sat nine days open with 36sbom-action-unmappedfindings, holdingprConcurrentLimit: 1against four queued updates, until it was cleared by hand in77fbad3b.mise-tasks/sbom-actions.tsvmaps each pinned action byrepo@shatogether, andsbom-checkrefuses a pin with no row. Renovate rewrites the sha and has no idea the table exists — so every action bump opens red on a gate no bot can satisfy.Why a workflow, and not any of the three other shapes
Each was closed by a landed decision, not by preference:
sbom-check.shis frozen byV-SHELL-RULE-EDITED; its port is blocked on CLOUD-1265's tool-verdict producer.crates/battenverb is refused by CLOUD-1159 §1 outright — "no newcrates/battenverb" — whose HOMES section adds that Batten does not grow an SBOM subsystem (CLOUD-455).mise-tasks/*.shwould need a# stays-bash:declaration owning an increase against a campaign retiring 144 programs.A workflow on a clock is what remains, and it is what §2 decided, shaped like
lock-currency.yml.The one place it departs from §2, deliberately
§2 says "fetches each new pin's LICENSE bytes at its sha" and writes the rows. That re-derives a verdict, and the table's own header records four rows where a naive read gets it wrong: LGPL boilerplate mistaken for the project's copyright holder, a dual-licensed action whose single-file read would have recorded MIT alone, a holder with no year. Automating the derivation would reproduce CLOUD-629's class once per bump.
So it never derives a licence. It carries an existing row forward to a new sha, and only when every candidate licence file is byte-identical between the mapped sha and the new one — identical bytes mean the judgement already recorded was made about those exact bytes and still holds. A repository with no row, or any licence file added, removed or changed, is reported as a warning and left for a person.
That is §2's Option 3 refused rather than smuggled in: keying by action name would delete the drift detector, whereas this keeps it firing on real drift and stops it firing only where there provably is none.
It opens its own PR against
mainand never writes the bot's head, preserving the update lane's decision never to check a bot branch out under a write token.Two defects caught before landing
printfinstead, with the reason at the site.sbom-check.actionlintclean;zizmorclean over 26 workflows;timeout-checkgreen (41 jobs, every timeout justified).Note for review
The budget is
grandfatheredrather than a measured p95 because the job has never run and the other legal form demands a number I cannot honestly produce yet. Re-derive it once the schedule has fired a few times.Closes CLOUD-1213