Repository navigation
fix(apply-review-hold)!: take a cost decision's decided head from this lane's check-run notices - #904
Conversation
…s lane's check-run notices carryDecision took the decided head from the newest unedited github-actions[bot] `claude-lane-hold` marker comment before the decision. Any workflow running on GITHUB_TOKEN posts as github-actions[bot], so a workflow could post a marker naming a commit not yet pushed and carry an earlier cost decision onto it. The hold step now reads the decided head from this lane's own status-job notices, as the merge-side readers in claude-code-plugins do (#10357): every pull_request run of this run's workflow on the pull request's branch of this repository started before the decision, each run's head vetted (base...head under 300 files, not changing the caller's workflow file), the newest `claude-lane-hold lane=<lane>` cost notice naming its own run's head from a status job done before the decision. Two heads at that time, none, a head pushed after the decided head with no run of this lane (repository activity API), or any failed read carries nothing. The comment edit and deletion reads are gone with the comment read. The status job now requests actions: read and checks: read. A caller that does not grant both fails at startup, hence the `!`. Refs: melodic-software/claude-code-plugins#9635 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 4m 55s —— View job Security review complete
No security issues found. This is a trust-boundary hardening change, and I traced it specifically for new attack surface rather than just restating the PR's own claims:
I did not execute the test suite directly in this sandbox (the critical-findings: 0 claude-lane-summary: lane=claude-security-review sha=b371aaefd5979b5a6220dea50aa66199faac07cf run=40776900221 |
|
Claude finished @kyle-sexton's task in 4m 50s —— View job Code review:
|
|
claude-security-review has reviewed this pull request through b371aae; a later push is reviewed from there. |
|
claude-review has reviewed this pull request through b371aae; a later push is reviewed from there. |
…contract (#902) Refs: melodic-software/claude-code-plugins#10782 ## Summary Registers the reviewed `pr-review-cli.yml@20a822d73b6e2d7e21d48e609a01b427e0e161e7` (v0.66.1) contract. The claude-code-plugins repin fails `runner-target-contract` because surface-diff auto-approval declines: `jobPermissions changed since the previously reviewed ...pr-review-cli.yml@3180217076b19bbdfccc43026c7f91c604da673d`. ## Fix - `policy.json`: the new entry copies the v0.65.14 (`3180217`) entry forward unchanged. From `3180217` to `20a822d`, the workflow changes in three non-comment lines, all from melodic-software/ci-workflows#904: the `status` job adds `actions: read` and `checks: read` (the hold step reads this workflow's earlier runs and their check-run cost notices), and that step takes a `STATUS_JOB` env built from the `lane` input. No input, secret, write scope or routing change. A hosted-only contract records no job permissions and checks no caller permissions, so the callers' existing read grants need no entry. - `README.md`: a v0.66.1 paragraph that names ci-workflows#904 and the permission change. - `runner-policy.test.mjs`: pins the new entry as equal to its v0.65.14 entry. ## Verification - `node --test components/runner-policy/runner-policy.test.mjs`: 371 pass, 0 fail. - `npm run lint:runner-policy` on this repo: `Runner policy passed.` - On the claude-code-plugins repin branch `ci/repin-pr-review-cli-v0.66.1`: - before (its synced policy): both review callers fail `runner-target-contract` with the auto-approval decline above, exit 1. - after (`--policy` pointed at this branch's `policy.json`): `Runner policy passed.`, exit 0. ## Related - melodic-software/claude-code-plugins#10782 (the repin this unblocks) - melodic-software/ci-workflows#904 (the permission change) - #893 (precedent) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…tatus job reads (#900) Refs: melodic-software/claude-code-plugins#9635 ## Summary This PR registers the reviewed `pr-review-cli.yml` contract at the [ci-workflows v0.66.1](https://github.com/melodic-software/ci-workflows/releases/tag/v0.66.1) tag (`20a822d73b6e2d7e21d48e609a01b427e0e161e7`), so callers can pin that release. Auto-approval declines it today: "jobPermissions changed since the previously reviewed ...pr-review-cli.yml@3180217". The change is [ci-workflows#904](melodic-software/ci-workflows#904): the status job adds `actions: read` and `checks: read` so the cost hold can read its earlier runs' check-run notices. The owner approved those read-only scopes for this lane (claude-code-plugins#9635, Q1(a)). ## Fix - `policy.json`: the v0.66.1 `pr-review-cli.yml` entry copies its v0.65.14 (`3180217`) entry forward unchanged. A hosted-only contract has no field for caller permissions (the schema refuses `minimumCallerPermissions` without `runnerInput`), so the reviewed change is recorded in the README and test, not in the entry. - `README.md`: one paragraph on the v0.66.1 contract and the reviewed permission change. - `runner-policy.test.mjs`: a test that the v0.66.1 entry equals the v0.65.14 entry. ## Verification - Surface diff of `pr-review-cli.yml` between `3180217` and `20a822d` (comments excluded): the status job's `actions: read` and `checks: read` lines and one `STATUS_JOB` step env value. `on.workflow_call` inputs, secrets and `runs-on` do not change. - `node --test components/runner-policy/runner-policy.test.mjs components/claude-lanes/repin-policy-lockstep.test.mjs`: 398 pass, 0 fail. - `runner-policy.mjs --root <claude-code-plugins#10782 head d4b21de>`: - with this `policy.json`: `Runner policy passed.` - with the currently synced `policy.json`: the two `pr-review-cli.yml@20a822d` runner-target-contract findings that fail #10782's `lint-repo`. - Left out: `pr-review-cli.yml@9a886d5` (v0.66.0). No caller pins it. ## Related - [claude-code-plugins#10782](melodic-software/claude-code-plugins#10782): repins the review callers to v0.66.1. Its `lint-repo` and `ci-status` fail on this missing contract and pass once it syncs. - [#895](#895): the claude-lanes re-pin to v0.66.0. It copies forward `pr-review.yml`, `pr-review-security.yml` and `maintenance-sync-standards.yml` but not `pr-review-cli.yml`. - [#885](#885): the v0.65.14 `pr-review-cli.yml` registration, which this follows. - [ci-workflows#904](melodic-software/ci-workflows#904): the permission change reviewed here. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes melodic-software/claude-code-plugins#9635
Refs: melodic-software/claude-code-plugins#9635
Summary
The review lanes' hold step (
apply-review-hold/hold.cjscarryDecision) took a cost decision's decided head from the newest uneditedgithub-actions[bot]claude-lane-holdmarker comment. Any workflow onGITHUB_TOKENposts asgithub-actions[bot], so a workflow could post a marker naming a commit it had not pushed yet and carry an earlier cost decision onto it. The hold step now reads the decided head from this lane's own check-run notices, as the three merge-side readers in claude-code-plugins already do (claude-code-plugins#10357). This is the ci-workflows half of #9635 and merges last.Fix
pull_requestrun of this run's workflow on the pull request's branch of this repository, started before the decision.base...headmust list fewer than 300 files and must not change the caller's workflow file, since apull_requestrun takes that file from the head.claude-lane-hold lane=<lane> ... criteria=...cost... label=notices that name the run's own head, and keeps the newest one.unranHead), or any failed read.actions: readandchecks: read, and takes a newSTATUS_JOBenv. A caller that does not grant both fails at startup, so the title carries!. Both claude-code-plugins callers already grant them (pr-review-hosted.yml:167-171andpr-review-security-hosted.yml:172,175). The sandbox callers gain them in pr-pipeline-sandbox#243.Verification
node --test .github/scripts/*.test.cjs: 735 pass, 0 fail.apply-review-hold.test.cjshas 41 tests.origin/main'shold.cjs. Two tests failed with the hold output'false' !== 'true'(apply-review-hold.test.cjs:1025and:1046). In the first, agithub-actions[bot]marker comment with no lane notice made the old code carry the decision. In the second, a newer forged marker naming the current head made it carry.core.notice/core.warningescape newlines.decidedHead, so removing it changes nothing.actionlintandzizmor --offlineonpr-review-cli.yml: no findings.Left out: no live run. The change takes effect once callers re-pin.
Risk
The callers reach this change only by re-pinning. Before the claude-code-plugins callers re-pin (
pr-review-hosted.yml:175,pr-review-security-hosted.yml:180), standards runner-policy needs an approved contract for the new SHA. UNVERIFIED: whether another workflow holdingchecks: writecould PATCH an Actions job's check run to add a notice. The merge-side readers from #10357 have the same open question, and it trusts no more than the comment rule did.Related
checks: readbefore the sandbox callers re-pin.🤖 Generated with Claude Code