From 95662f6e2a53dd5140e994c9113d6d9b24c12d41 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Sun, 25 Oct 2026 21:47:48 -0400 Subject: [PATCH 1/4] ci(lanes): repin the Claude lane callers to ci-workflows v0.65.12 and pass the fallback token Repin the reusable-workflow callers (pr-review-hosted.yml, pr-review-security-hosted.yml, intake-triage.yml) and the composite-action callers (pr-run-activity-read.yml, pr-run-activity-write.yml, pr-unblock.yml, pr-verify.yml) to v0.65.12 (78ee7a26). The three reusable callers pass FALLBACK_CLAUDE_CODE_OAUTH_TOKEN by name, as the runner-policy contracts for that SHA require, so the reusables' fallback job can run after the subscription job hands off. The lane-funding catalog lists the fallback secret for the three lanes that now read it, and callers.test.mjs admits it only on a call of a ci-workflows reusable with a fallback job. The pin tests move with the SHA; lane.cjs at 78ee7a26 passes --permission-prompts none at lines 404-405. Co-Authored-By: Claude Opus 5.5 --- .../actions/resolve-config/callers.test.mjs | 20 ++++++++++++++----- .github/lane-funding.json | 6 +++--- .github/scripts/pr-verify/probe/replay.mjs | 2 +- .github/workflows/intake-triage.yml | 5 ++++- .github/workflows/pr-review-hosted.yml | 6 ++++-- .../workflows/pr-review-security-hosted.yml | 6 ++++-- .github/workflows/pr-run-activity-read.yml | 14 ++++++------- .github/workflows/pr-run-activity-write.yml | 2 +- .github/workflows/pr-unblock.yml | 8 ++++---- .github/workflows/pr-verify.yml | 12 +++++------ scripts/ci-review-lanes.test.sh | 6 +++--- scripts/ci-review-plugin-source.test.sh | 4 ++-- 12 files changed, 54 insertions(+), 37 deletions(-) diff --git a/.github/actions/resolve-config/callers.test.mjs b/.github/actions/resolve-config/callers.test.mjs index 81810a94522..488686a18bb 100644 --- a/.github/actions/resolve-config/callers.test.mjs +++ b/.github/actions/resolve-config/callers.test.mjs @@ -1367,12 +1367,20 @@ test("every job that reads a Claude secret is a catalog lane, and every catalog }); // run-claude-cli names the lane record's credential from `role:`, never from -// the secret passed, so the role and the secret are checked together. +// the secret passed, so the role and the secret are checked together. The one +// exception is the central fallback token, the same org secret for every role, +// which only a call of a ci-workflows reusable with a fallback job may pass +// (intake-triage.yml and pr-review-cli.yml from v0.65.12, ci-workflows#890). +const FALLBACK_SECRET = "FALLBACK_CLAUDE_CODE_OAUTH_TOKEN"; +const FALLBACK_REUSABLE = /^melodic-software\/ci-workflows\/\.github\/workflows\/(?:intake-triage|pr-review-cli)\.yml@[0-9a-f]{40}$/; test("every catalog lane reads only its role's secrets, and every role: it passes is its role", () => { const jobs = claudeSecretJobs(); for (const { role, lane, key } of catalogLanes()) { - for (const name of lane.currentSecrets) assert.ok([role.keySecret, role.tokenSecret].includes(name), `${key} reads ${name}`); const { job } = jobs.get(key); + const fallback = FALLBACK_REUSABLE.test(String(job.uses ?? "")) && job.secrets?.[FALLBACK_SECRET] === `\${{ secrets.${FALLBACK_SECRET} }}`; + for (const name of lane.currentSecrets) { + assert.ok([role.keySecret, role.tokenSecret, ...(fallback ? [FALLBACK_SECRET] : [])].includes(name), `${key} reads ${name}`); + } const roles = [job.with?.role, ...(job.steps ?? []).map((step) => step.with?.role)].filter((value) => value !== undefined); for (const value of roles) assert.equal(value, role.id, key); } @@ -1537,7 +1545,7 @@ test("pr-run-activity-read.yml: the run job can only read, and each launcher ste const { jobs } = workflow("pr-run-activity-read.yml"); assert.deepEqual(jobs.run.permissions, { contents: "read", "pull-requests": "read" }, "read-only, no id-token"); const step = (id) => jobs.run.steps.find((s) => s.id === id); - const launcher = "melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8"; + const launcher = "melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc"; for (const [id, input, secret] of [ ["act-key", "api-key", "claude-api-key"], ["act-token", "subscription-token", "claude-code-oauth-token"], @@ -1594,13 +1602,15 @@ test("no run-claude-cli plugin-dirs or add-dirs value names runner.temp, RUNNER_ // Launcher SHAs checked to pass `--permission-prompts none` unconditionally, // under which the default mode denies every call no rule allows, as dontAsk // does; check-permission-mode.sh accepts default for dontAsk on that basis. -// 7b362428: lane.cjs:311-312; 164c2809: lane.cjs:355-358; d02b8697 and e5167fc2: lane.cjs:357-358; in cliArgs. A pin +// 7b362428: lane.cjs:311-312; 164c2809: lane.cjs:355-358; d02b8697 and e5167fc2: lane.cjs:357-358; +// 78ee7a26: lane.cjs:404-405; in cliArgs. A pin // bump fails here until its lane.cjs is read and its SHA added. const PERMISSION_PROMPTS_NONE_LAUNCHERS = new Set([ "7b362428c76085a160e28656cd2c75c3147a69ff", "164c2809f6150429b6f24d4a2777bb377af953d9", "d02b8697e092705153f0996549b05f95a446bb52", "e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8", + "78ee7a2609a84b0073c5e09dfe3bc59613e689dc", ]); test("pr-run-activity-read.yml: every run-claude-cli pin is a launcher checked to pass --permission-prompts none", () => { @@ -3703,7 +3713,7 @@ test("scan job: every gate, skip and launcher class value the runner sets passes const schema = JSON.parse(read("../../../docs/conventions/pr-pipeline/pr-pipeline.schema.json")); const gateReasons = Object.keys(JSON.parse(read("../report-check-run/gate-skip-reasons.json"))); // run-claude-cli's failure classes, the keys of SUMMARY_NOTES in lane.cjs at - // the pinned e5167fc2. cant-fail-ok: an external contract's value list. + // the pinned 78ee7a26. cant-fail-ok: an external contract's value list. const laneClasses = ["credit-stop", "rate-limit", "auth", "overloaded", "max-turns", "timeout", "other"]; const cases = [ ...schema.$defs["skip-reason"].enum.map((value) => ["skip-reason", value]), diff --git a/.github/lane-funding.json b/.github/lane-funding.json index 6a5ed86145d..059aa52e453 100644 --- a/.github/lane-funding.json +++ b/.github/lane-funding.json @@ -10,8 +10,8 @@ "keyed": true, "category": "review", "lanes": [ - { "id": "pr-review", "workflow": "pr-review-hosted.yml", "launcher": "run-claude-cli", "triggers": ["pull_request"], "currentSecrets": ["REVIEWS_CLAUDE_API_KEY", "REVIEWS_CLAUDE_CODE_OAUTH_TOKEN"] }, - { "id": "pr-review-security", "workflow": "pr-review-security-hosted.yml", "launcher": "run-claude-cli", "triggers": ["pull_request"], "currentSecrets": ["REVIEWS_CLAUDE_API_KEY", "REVIEWS_CLAUDE_CODE_OAUTH_TOKEN"] } + { "id": "pr-review", "workflow": "pr-review-hosted.yml", "launcher": "run-claude-cli", "triggers": ["pull_request"], "currentSecrets": ["REVIEWS_CLAUDE_API_KEY", "REVIEWS_CLAUDE_CODE_OAUTH_TOKEN", "FALLBACK_CLAUDE_CODE_OAUTH_TOKEN"] }, + { "id": "pr-review-security", "workflow": "pr-review-security-hosted.yml", "launcher": "run-claude-cli", "triggers": ["pull_request"], "currentSecrets": ["REVIEWS_CLAUDE_API_KEY", "REVIEWS_CLAUDE_CODE_OAUTH_TOKEN", "FALLBACK_CLAUDE_CODE_OAUTH_TOKEN"] } ] }, { @@ -34,7 +34,7 @@ "keyed": true, "category": "intake", "lanes": [ - { "id": "intake-triage", "workflow": "intake-triage.yml", "launcher": "run-claude-cli", "triggers": ["issues", "workflow_dispatch"], "gate": "author", "currentSecrets": ["INTAKE_CLAUDE_API_KEY", "INTAKE_CLAUDE_CODE_OAUTH_TOKEN"] }, + { "id": "intake-triage", "workflow": "intake-triage.yml", "launcher": "run-claude-cli", "triggers": ["issues", "workflow_dispatch"], "gate": "author", "currentSecrets": ["INTAKE_CLAUDE_API_KEY", "INTAKE_CLAUDE_CODE_OAUTH_TOKEN", "FALLBACK_CLAUDE_CODE_OAUTH_TOKEN"] }, { "id": "refine-issue", "workflow": "intake-triage.yml", "launcher": "claude-code-action", "triggers": ["issues", "workflow_dispatch"], "gate": "author", "currentSecrets": ["INTAKE_CLAUDE_CODE_OAUTH_TOKEN"] } ] }, diff --git a/.github/scripts/pr-verify/probe/replay.mjs b/.github/scripts/pr-verify/probe/replay.mjs index 38665d69305..6760cadce88 100644 --- a/.github/scripts/pr-verify/probe/replay.mjs +++ b/.github/scripts/pr-verify/probe/replay.mjs @@ -60,7 +60,7 @@ const REPOSITORY = "melodic-software/claude-code-plugins"; // apply-claude-managed-settings to. cliArgs, LEG_ENV, CLI_VERSION and // MANAGED_SETTINGS were read from that SHA; the parity test fails when the // pin moves, so they are read again. -export const RUN_CLAUDE_CLI_PIN = "e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8"; +export const RUN_CLAUDE_CLI_PIN = "78ee7a2609a84b0073c5e09dfe3bc59613e689dc"; export const CLI_VERSION = "latest"; export const MANAGED_SETTINGS = Object.freeze({ apiKeyHelper: "", diff --git a/.github/workflows/intake-triage.yml b/.github/workflows/intake-triage.yml index a17a76f7107..a0d9afbf5d3 100644 --- a/.github/workflows/intake-triage.yml +++ b/.github/workflows/intake-triage.yml @@ -201,7 +201,7 @@ jobs: concurrency: group: intake-triage-${{ github.event.issue.number || inputs.issue-number || github.run_id }} cancel-in-progress: false - uses: melodic-software/ci-workflows/.github/workflows/intake-triage.yml@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/workflows/intake-triage.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 with: runner: ubuntu-24.04 role: intake @@ -330,9 +330,12 @@ jobs: e. When the decision settles every open question and no person is needed, apply no status label, quote the decision, say in one sentence that it settles the open questions, and ask nothing again. Triage the rest as usual. + # Named secrets only, never `secrets: inherit`. The central fallback token + # runs only after the subscription token hands off. secrets: CLAUDE_API_KEY: ${{ secrets.INTAKE_CLAUDE_API_KEY }} CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.INTAKE_CLAUDE_CODE_OAUTH_TOKEN }} + FALLBACK_CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.FALLBACK_CLAUDE_CODE_OAUTH_TOKEN }} # Writes the triage run's verdict on the issue as the lanes App, so the work # lanes count it: the work-class label, the Size, Complexity and Uncertainty diff --git a/.github/workflows/pr-review-hosted.yml b/.github/workflows/pr-review-hosted.yml index ce89a51910f..397af3a66a0 100644 --- a/.github/workflows/pr-review-hosted.yml +++ b/.github/workflows/pr-review-hosted.yml @@ -169,7 +169,7 @@ jobs: contents: read pull-requests: write # the review, its inline comments and the lane's # reviewed-head marker comment - uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 with: lane: code publish: comments @@ -203,7 +203,9 @@ jobs: **/CODEOWNERS **/.gitmodules # The reviews role's key runs first; its subscription token only after the - # key hands off. Named secrets only, never `secrets: inherit`. + # key hands off, and the central fallback token only after the + # subscription token hands off. Named secrets only, never `secrets: inherit`. secrets: CLAUDE_API_KEY: ${{ secrets.REVIEWS_CLAUDE_API_KEY }} CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.REVIEWS_CLAUDE_CODE_OAUTH_TOKEN }} + FALLBACK_CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.FALLBACK_CLAUDE_CODE_OAUTH_TOKEN }} diff --git a/.github/workflows/pr-review-security-hosted.yml b/.github/workflows/pr-review-security-hosted.yml index 78f9cd024d1..9d1df39e17c 100644 --- a/.github/workflows/pr-review-security-hosted.yml +++ b/.github/workflows/pr-review-security-hosted.yml @@ -174,7 +174,7 @@ jobs: contents: read pull-requests: write # the review, its inline comments and the lane's # reviewed-head marker comment - uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 with: lane: security publish: comments @@ -203,7 +203,9 @@ jobs: **/CODEOWNERS **/.gitmodules # The reviews role's key runs first; its subscription token only after the - # key hands off. Named secrets only, never `secrets: inherit`. + # key hands off, and the central fallback token only after the + # subscription token hands off. Named secrets only, never `secrets: inherit`. secrets: CLAUDE_API_KEY: ${{ secrets.REVIEWS_CLAUDE_API_KEY }} CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.REVIEWS_CLAUDE_CODE_OAUTH_TOKEN }} + FALLBACK_CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.FALLBACK_CLAUDE_CODE_OAUTH_TOKEN }} diff --git a/.github/workflows/pr-run-activity-read.yml b/.github/workflows/pr-run-activity-read.yml index 20899e899a2..053365d00b8 100644 --- a/.github/workflows/pr-run-activity-read.yml +++ b/.github/workflows/pr-run-activity-read.yml @@ -1059,7 +1059,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.launch.outcome == 'success' && steps.go.outputs.run == 'true' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 # Nothing after this step needs sudo or docker. - name: Isolate the runner @@ -1344,7 +1344,7 @@ jobs: if: steps.key-present.outputs.present == 'true' continue-on-error: true timeout-minutes: ${{ fromJSON(steps.launch.outputs.step-minutes || '50') }} - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: # No work may outlive the result message the launcher reads. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" @@ -1396,7 +1396,7 @@ jobs: if: steps.token-present.outputs.present == 'true' continue-on-error: true timeout-minutes: ${{ fromJSON(steps.launch.outputs.step-minutes || '50') }} - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" @@ -1611,7 +1611,7 @@ jobs: always() && steps.key-present.outputs.present != 'false' && steps.act-key.outputs.handoff != 'true' && (steps.act-key.outcome == 'success' || steps.act-key.outcome == 'failure' || steps.act-token.outcome == 'success' || steps.act-token.outcome == 'failure') - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 with: outcome: ${{ steps.act-key.outcome != 'skipped' && steps.act-key.outcome || steps.act-token.outcome }} execution-file: ${{ steps.act-key.outputs.execution-file || steps.act-token.outputs.execution-file }} @@ -2958,7 +2958,7 @@ jobs: id: summary-settings if: steps.summary-prompt.outcome == 'success' continue-on-error: true - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 - name: Isolate the runner id: isolate @@ -2977,7 +2977,7 @@ jobs: if: steps.isolate.outcome == 'success' && inputs.fallback == '' continue-on-error: true timeout-minutes: 15 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" with: @@ -3003,7 +3003,7 @@ jobs: if: steps.isolate.outcome == 'success' && inputs.fallback != '' continue-on-error: true timeout-minutes: 15 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" with: diff --git a/.github/workflows/pr-run-activity-write.yml b/.github/workflows/pr-run-activity-write.yml index 1d124303ce5..55e4b39834f 100644 --- a/.github/workflows/pr-run-activity-write.yml +++ b/.github/workflows/pr-run-activity-write.yml @@ -1644,7 +1644,7 @@ jobs: - name: Record the lane outcome id: lane-record if: always() && (steps.act-skill.outcome == 'success' || steps.act-skill.outcome == 'failure') - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 with: outcome: ${{ steps.act-result.outputs.outcome || steps.act-skill.outcome }} execution-file: >- diff --git a/.github/workflows/pr-unblock.yml b/.github/workflows/pr-unblock.yml index 5a49c2ac3ce..42c9d44e4b2 100644 --- a/.github/workflows/pr-unblock.yml +++ b/.github/workflows/pr-unblock.yml @@ -935,7 +935,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.key.outputs.present == 'true' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 # Nothing after this step needs sudo or docker. - name: Isolate the runner @@ -968,7 +968,7 @@ jobs: if: steps.key.outputs.present == 'true' && fromJSON(steps.prepare.outputs.count || '0') > 0 continue-on-error: true timeout-minutes: 20 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" @@ -1029,7 +1029,7 @@ jobs: if: steps.key.outputs.present == 'true' && fromJSON(steps.prepare.outputs.count || '0') > 1 continue-on-error: true timeout-minutes: 20 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" @@ -1090,7 +1090,7 @@ jobs: if: steps.key.outputs.present == 'true' && fromJSON(steps.prepare.outputs.count || '0') > 2 continue-on-error: true timeout-minutes: 20 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" diff --git a/.github/workflows/pr-verify.yml b/.github/workflows/pr-verify.yml index edda0bce878..1f7e069bfef 100644 --- a/.github/workflows/pr-verify.yml +++ b/.github/workflows/pr-verify.yml @@ -213,7 +213,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.agree.outcome == 'success' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 - name: Isolate the runner if: steps.agree.outcome == 'success' @@ -263,7 +263,7 @@ jobs: if: steps.credential.outputs.present == 'true' continue-on-error: true timeout-minutes: 22 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: # No work may outlive the result message the launcher reads. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" @@ -322,7 +322,7 @@ jobs: # it, and auth as auth. - name: Report the judgment's outcome if: (steps.judge.outcome == 'success' || steps.judge.outcome == 'failure') && (steps.judge.outputs.handoff != 'true' || steps.key-leg.outcome == 'failure') - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 with: outcome: ${{ steps.judge.outcome }} execution-file: ${{ steps.judge.outputs.execution-file }} @@ -542,7 +542,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.agree.outcome == 'success' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 - name: Isolate the runner if: steps.agree.outcome == 'success' @@ -590,7 +590,7 @@ jobs: if: steps.credential.outputs.present == 'true' continue-on-error: true timeout-minutes: 22 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 env: # No work may outlive the result message the launcher reads. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" @@ -625,7 +625,7 @@ jobs: - name: Report the judgment's outcome if: steps.judge.outcome == 'success' || steps.judge.outcome == 'failure' - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0.65.11 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 with: outcome: ${{ steps.judge.outcome }} execution-file: ${{ steps.judge.outputs.execution-file }} diff --git a/scripts/ci-review-lanes.test.sh b/scripts/ci-review-lanes.test.sh index 8a5ea9c5159..272407666d2 100755 --- a/scripts/ci-review-lanes.test.sh +++ b/scripts/ci-review-lanes.test.sh @@ -76,10 +76,10 @@ for pair in 'pr-review-hosted.yml pr-review:' 'pr-review-security-hosted.yml pr- caller="$ROOT/.github/workflows/$file" if grep -qxF " $job" "$caller" && grep -qxF ' publish: comments' "$caller" && grep -qxF ' hold-label: needs-human' "$caller" && - grep -qE '^ uses: melodic-software/ci-workflows/\.github/workflows/pr-review-cli\.yml@e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8 # v0\.65\.11$' "$caller"; then - ok "$file calls pr-review-cli v0.65.11 as job ${job%:} with publish: comments and hold-label: needs-human" + grep -qE '^ uses: melodic-software/ci-workflows/\.github/workflows/pr-review-cli\.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0\.65\.12$' "$caller"; then + ok "$file calls pr-review-cli v0.65.12 as job ${job%:} with publish: comments and hold-label: needs-human" else - fail "$file lost its job id, publish: comments, hold-label or v0.65.11 pin" + fail "$file lost its job id, publish: comments, hold-label or v0.65.12 pin" fi # pr-review-cli's check-key-credit job requests actions: read; a caller that # does not grant it fails at startup. diff --git a/scripts/ci-review-plugin-source.test.sh b/scripts/ci-review-plugin-source.test.sh index ca1421941c0..1f1a4d7e611 100755 --- a/scripts/ci-review-plugin-source.test.sh +++ b/scripts/ci-review-plugin-source.test.sh @@ -50,10 +50,10 @@ for (const file of ["pr-review-hosted.yml", "pr-review-security-hosted.yml"]) { } // The check itself rejects each shape it guards against. -const sha = "e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8"; +const sha = "78ee7a2609a84b0073c5e09dfe3bc59613e689dc"; const call = (uses, inputs) => ({ review: { uses, with: inputs } }); for (const [name, jobs] of [ - ["a tag ref", call(`${REUSABLE}v0.65.11`, {})], + ["a tag ref", call(`${REUSABLE}v0.65.12`, {})], ["a short SHA", call(`${REUSABLE}${sha.slice(0, 12)}`, {})], ["another repository's copy", call(`someone/ci-workflows/.github/workflows/pr-review-cli.yml@${sha}`, {})], ["a plugin-dirs input", call(`${REUSABLE}${sha}`, { "plugin-dirs": "plugins/review" })], From c06b16d2bd685fa8295cf31dd69d6bec4473bee3 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:29:53 -0400 Subject: [PATCH 2/4] ci(lanes): repin the Claude lane callers to ci-workflows v0.65.13 v0.65.13 fixes the pr-review-cli status job's read of the token leg's job result (ci-workflows#892), which made v0.65.12 report no-outcome when the key leg was skipped by the credit window. Co-Authored-By: Claude Opus 5.5 --- .github/actions/resolve-config/callers.test.mjs | 8 ++++---- .github/scripts/pr-verify/probe/replay.mjs | 2 +- .github/workflows/intake-triage.yml | 2 +- .github/workflows/pr-review-hosted.yml | 2 +- .github/workflows/pr-review-security-hosted.yml | 2 +- .github/workflows/pr-run-activity-read.yml | 14 +++++++------- .github/workflows/pr-run-activity-write.yml | 2 +- .github/workflows/pr-unblock.yml | 8 ++++---- .github/workflows/pr-verify.yml | 12 ++++++------ scripts/ci-review-lanes.test.sh | 6 +++--- scripts/ci-review-plugin-source.test.sh | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/actions/resolve-config/callers.test.mjs b/.github/actions/resolve-config/callers.test.mjs index 488686a18bb..6c9baaf2cd3 100644 --- a/.github/actions/resolve-config/callers.test.mjs +++ b/.github/actions/resolve-config/callers.test.mjs @@ -1545,7 +1545,7 @@ test("pr-run-activity-read.yml: the run job can only read, and each launcher ste const { jobs } = workflow("pr-run-activity-read.yml"); assert.deepEqual(jobs.run.permissions, { contents: "read", "pull-requests": "read" }, "read-only, no id-token"); const step = (id) => jobs.run.steps.find((s) => s.id === id); - const launcher = "melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc"; + const launcher = "melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe"; for (const [id, input, secret] of [ ["act-key", "api-key", "claude-api-key"], ["act-token", "subscription-token", "claude-code-oauth-token"], @@ -1603,14 +1603,14 @@ test("no run-claude-cli plugin-dirs or add-dirs value names runner.temp, RUNNER_ // under which the default mode denies every call no rule allows, as dontAsk // does; check-permission-mode.sh accepts default for dontAsk on that basis. // 7b362428: lane.cjs:311-312; 164c2809: lane.cjs:355-358; d02b8697 and e5167fc2: lane.cjs:357-358; -// 78ee7a26: lane.cjs:404-405; in cliArgs. A pin +// ba7af78d: lane.cjs:404-405; in cliArgs. A pin // bump fails here until its lane.cjs is read and its SHA added. const PERMISSION_PROMPTS_NONE_LAUNCHERS = new Set([ "7b362428c76085a160e28656cd2c75c3147a69ff", "164c2809f6150429b6f24d4a2777bb377af953d9", "d02b8697e092705153f0996549b05f95a446bb52", "e5167fc29d948ab7d0923cf62f5ea9eeeef8e9e8", - "78ee7a2609a84b0073c5e09dfe3bc59613e689dc", + "ba7af78d291f10bd75651857a0db2357c23df0fe", ]); test("pr-run-activity-read.yml: every run-claude-cli pin is a launcher checked to pass --permission-prompts none", () => { @@ -3713,7 +3713,7 @@ test("scan job: every gate, skip and launcher class value the runner sets passes const schema = JSON.parse(read("../../../docs/conventions/pr-pipeline/pr-pipeline.schema.json")); const gateReasons = Object.keys(JSON.parse(read("../report-check-run/gate-skip-reasons.json"))); // run-claude-cli's failure classes, the keys of SUMMARY_NOTES in lane.cjs at - // the pinned 78ee7a26. cant-fail-ok: an external contract's value list. + // the pinned ba7af78d. cant-fail-ok: an external contract's value list. const laneClasses = ["credit-stop", "rate-limit", "auth", "overloaded", "max-turns", "timeout", "other"]; const cases = [ ...schema.$defs["skip-reason"].enum.map((value) => ["skip-reason", value]), diff --git a/.github/scripts/pr-verify/probe/replay.mjs b/.github/scripts/pr-verify/probe/replay.mjs index 6760cadce88..d0750d3e6ac 100644 --- a/.github/scripts/pr-verify/probe/replay.mjs +++ b/.github/scripts/pr-verify/probe/replay.mjs @@ -60,7 +60,7 @@ const REPOSITORY = "melodic-software/claude-code-plugins"; // apply-claude-managed-settings to. cliArgs, LEG_ENV, CLI_VERSION and // MANAGED_SETTINGS were read from that SHA; the parity test fails when the // pin moves, so they are read again. -export const RUN_CLAUDE_CLI_PIN = "78ee7a2609a84b0073c5e09dfe3bc59613e689dc"; +export const RUN_CLAUDE_CLI_PIN = "ba7af78d291f10bd75651857a0db2357c23df0fe"; export const CLI_VERSION = "latest"; export const MANAGED_SETTINGS = Object.freeze({ apiKeyHelper: "", diff --git a/.github/workflows/intake-triage.yml b/.github/workflows/intake-triage.yml index a0d9afbf5d3..b8638217815 100644 --- a/.github/workflows/intake-triage.yml +++ b/.github/workflows/intake-triage.yml @@ -201,7 +201,7 @@ jobs: concurrency: group: intake-triage-${{ github.event.issue.number || inputs.issue-number || github.run_id }} cancel-in-progress: false - uses: melodic-software/ci-workflows/.github/workflows/intake-triage.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/workflows/intake-triage.yml@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 with: runner: ubuntu-24.04 role: intake diff --git a/.github/workflows/pr-review-hosted.yml b/.github/workflows/pr-review-hosted.yml index 397af3a66a0..b43151aa7f6 100644 --- a/.github/workflows/pr-review-hosted.yml +++ b/.github/workflows/pr-review-hosted.yml @@ -169,7 +169,7 @@ jobs: contents: read pull-requests: write # the review, its inline comments and the lane's # reviewed-head marker comment - uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 with: lane: code publish: comments diff --git a/.github/workflows/pr-review-security-hosted.yml b/.github/workflows/pr-review-security-hosted.yml index 9d1df39e17c..969864c2631 100644 --- a/.github/workflows/pr-review-security-hosted.yml +++ b/.github/workflows/pr-review-security-hosted.yml @@ -174,7 +174,7 @@ jobs: contents: read pull-requests: write # the review, its inline comments and the lane's # reviewed-head marker comment - uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/workflows/pr-review-cli.yml@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 with: lane: security publish: comments diff --git a/.github/workflows/pr-run-activity-read.yml b/.github/workflows/pr-run-activity-read.yml index 053365d00b8..6a5bf90bfbe 100644 --- a/.github/workflows/pr-run-activity-read.yml +++ b/.github/workflows/pr-run-activity-read.yml @@ -1059,7 +1059,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.launch.outcome == 'success' && steps.go.outputs.run == 'true' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 # Nothing after this step needs sudo or docker. - name: Isolate the runner @@ -1344,7 +1344,7 @@ jobs: if: steps.key-present.outputs.present == 'true' continue-on-error: true timeout-minutes: ${{ fromJSON(steps.launch.outputs.step-minutes || '50') }} - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: # No work may outlive the result message the launcher reads. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" @@ -1396,7 +1396,7 @@ jobs: if: steps.token-present.outputs.present == 'true' continue-on-error: true timeout-minutes: ${{ fromJSON(steps.launch.outputs.step-minutes || '50') }} - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" @@ -1611,7 +1611,7 @@ jobs: always() && steps.key-present.outputs.present != 'false' && steps.act-key.outputs.handoff != 'true' && (steps.act-key.outcome == 'success' || steps.act-key.outcome == 'failure' || steps.act-token.outcome == 'success' || steps.act-token.outcome == 'failure') - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 with: outcome: ${{ steps.act-key.outcome != 'skipped' && steps.act-key.outcome || steps.act-token.outcome }} execution-file: ${{ steps.act-key.outputs.execution-file || steps.act-token.outputs.execution-file }} @@ -2958,7 +2958,7 @@ jobs: id: summary-settings if: steps.summary-prompt.outcome == 'success' continue-on-error: true - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 - name: Isolate the runner id: isolate @@ -2977,7 +2977,7 @@ jobs: if: steps.isolate.outcome == 'success' && inputs.fallback == '' continue-on-error: true timeout-minutes: 15 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" with: @@ -3003,7 +3003,7 @@ jobs: if: steps.isolate.outcome == 'success' && inputs.fallback != '' continue-on-error: true timeout-minutes: 15 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" with: diff --git a/.github/workflows/pr-run-activity-write.yml b/.github/workflows/pr-run-activity-write.yml index 55e4b39834f..33123d41a2b 100644 --- a/.github/workflows/pr-run-activity-write.yml +++ b/.github/workflows/pr-run-activity-write.yml @@ -1644,7 +1644,7 @@ jobs: - name: Record the lane outcome id: lane-record if: always() && (steps.act-skill.outcome == 'success' || steps.act-skill.outcome == 'failure') - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 with: outcome: ${{ steps.act-result.outputs.outcome || steps.act-skill.outcome }} execution-file: >- diff --git a/.github/workflows/pr-unblock.yml b/.github/workflows/pr-unblock.yml index 42c9d44e4b2..13d078feadf 100644 --- a/.github/workflows/pr-unblock.yml +++ b/.github/workflows/pr-unblock.yml @@ -935,7 +935,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.key.outputs.present == 'true' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 # Nothing after this step needs sudo or docker. - name: Isolate the runner @@ -968,7 +968,7 @@ jobs: if: steps.key.outputs.present == 'true' && fromJSON(steps.prepare.outputs.count || '0') > 0 continue-on-error: true timeout-minutes: 20 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" @@ -1029,7 +1029,7 @@ jobs: if: steps.key.outputs.present == 'true' && fromJSON(steps.prepare.outputs.count || '0') > 1 continue-on-error: true timeout-minutes: 20 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" @@ -1090,7 +1090,7 @@ jobs: if: steps.key.outputs.present == 'true' && fromJSON(steps.prepare.outputs.count || '0') > 2 continue-on-error: true timeout-minutes: 20 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" LD_LIBRARY_PATH: "" diff --git a/.github/workflows/pr-verify.yml b/.github/workflows/pr-verify.yml index 1f7e069bfef..76f59800233 100644 --- a/.github/workflows/pr-verify.yml +++ b/.github/workflows/pr-verify.yml @@ -213,7 +213,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.agree.outcome == 'success' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 - name: Isolate the runner if: steps.agree.outcome == 'success' @@ -263,7 +263,7 @@ jobs: if: steps.credential.outputs.present == 'true' continue-on-error: true timeout-minutes: 22 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: # No work may outlive the result message the launcher reads. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" @@ -322,7 +322,7 @@ jobs: # it, and auth as auth. - name: Report the judgment's outcome if: (steps.judge.outcome == 'success' || steps.judge.outcome == 'failure') && (steps.judge.outputs.handoff != 'true' || steps.key-leg.outcome == 'failure') - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 with: outcome: ${{ steps.judge.outcome }} execution-file: ${{ steps.judge.outputs.execution-file }} @@ -542,7 +542,7 @@ jobs: # need sudo, so they are written before the runner is isolated. - name: Apply the Claude managed settings if: steps.agree.outcome == 'success' - uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/apply-claude-managed-settings@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 - name: Isolate the runner if: steps.agree.outcome == 'success' @@ -590,7 +590,7 @@ jobs: if: steps.credential.outputs.present == 'true' continue-on-error: true timeout-minutes: 22 - uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/run-claude-cli@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 env: # No work may outlive the result message the launcher reads. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1" @@ -625,7 +625,7 @@ jobs: - name: Report the judgment's outcome if: steps.judge.outcome == 'success' || steps.judge.outcome == 'failure' - uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0.65.12 + uses: melodic-software/ci-workflows/.github/actions/report-lane-outcome@ba7af78d291f10bd75651857a0db2357c23df0fe # v0.65.13 with: outcome: ${{ steps.judge.outcome }} execution-file: ${{ steps.judge.outputs.execution-file }} diff --git a/scripts/ci-review-lanes.test.sh b/scripts/ci-review-lanes.test.sh index 272407666d2..ca73a1fb594 100755 --- a/scripts/ci-review-lanes.test.sh +++ b/scripts/ci-review-lanes.test.sh @@ -76,10 +76,10 @@ for pair in 'pr-review-hosted.yml pr-review:' 'pr-review-security-hosted.yml pr- caller="$ROOT/.github/workflows/$file" if grep -qxF " $job" "$caller" && grep -qxF ' publish: comments' "$caller" && grep -qxF ' hold-label: needs-human' "$caller" && - grep -qE '^ uses: melodic-software/ci-workflows/\.github/workflows/pr-review-cli\.yml@78ee7a2609a84b0073c5e09dfe3bc59613e689dc # v0\.65\.12$' "$caller"; then - ok "$file calls pr-review-cli v0.65.12 as job ${job%:} with publish: comments and hold-label: needs-human" + grep -qE '^ uses: melodic-software/ci-workflows/\.github/workflows/pr-review-cli\.yml@ba7af78d291f10bd75651857a0db2357c23df0fe # v0\.65\.12$' "$caller"; then + ok "$file calls pr-review-cli v0.65.13 as job ${job%:} with publish: comments and hold-label: needs-human" else - fail "$file lost its job id, publish: comments, hold-label or v0.65.12 pin" + fail "$file lost its job id, publish: comments, hold-label or v0.65.13 pin" fi # pr-review-cli's check-key-credit job requests actions: read; a caller that # does not grant it fails at startup. diff --git a/scripts/ci-review-plugin-source.test.sh b/scripts/ci-review-plugin-source.test.sh index 1f1a4d7e611..19ef2aa6a16 100755 --- a/scripts/ci-review-plugin-source.test.sh +++ b/scripts/ci-review-plugin-source.test.sh @@ -50,7 +50,7 @@ for (const file of ["pr-review-hosted.yml", "pr-review-security-hosted.yml"]) { } // The check itself rejects each shape it guards against. -const sha = "78ee7a2609a84b0073c5e09dfe3bc59613e689dc"; +const sha = "ba7af78d291f10bd75651857a0db2357c23df0fe"; const call = (uses, inputs) => ({ review: { uses, with: inputs } }); for (const [name, jobs] of [ ["a tag ref", call(`${REUSABLE}v0.65.12`, {})], From 4b09a3c87869b576c368321406285b44c77bafee Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:32:05 -0400 Subject: [PATCH 3/4] test(ci-review-lanes): expect the v0.65.13 pin comment Co-Authored-By: Claude Opus 5.5 --- scripts/ci-review-lanes.test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci-review-lanes.test.sh b/scripts/ci-review-lanes.test.sh index ca73a1fb594..9a29a57ac5e 100755 --- a/scripts/ci-review-lanes.test.sh +++ b/scripts/ci-review-lanes.test.sh @@ -76,7 +76,7 @@ for pair in 'pr-review-hosted.yml pr-review:' 'pr-review-security-hosted.yml pr- caller="$ROOT/.github/workflows/$file" if grep -qxF " $job" "$caller" && grep -qxF ' publish: comments' "$caller" && grep -qxF ' hold-label: needs-human' "$caller" && - grep -qE '^ uses: melodic-software/ci-workflows/\.github/workflows/pr-review-cli\.yml@ba7af78d291f10bd75651857a0db2357c23df0fe # v0\.65\.12$' "$caller"; then + grep -qE '^ uses: melodic-software/ci-workflows/\.github/workflows/pr-review-cli\.yml@ba7af78d291f10bd75651857a0db2357c23df0fe # v0\.65\.13$' "$caller"; then ok "$file calls pr-review-cli v0.65.13 as job ${job%:} with publish: comments and hold-label: needs-human" else fail "$file lost its job id, publish: comments, hold-label or v0.65.13 pin" From 784414c953c1b1f2c167eed00f2d911dd296c439 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:32:31 -0400 Subject: [PATCH 4/4] test(callers): cite the v0.65.13 pin by full SHA Co-Authored-By: Claude Opus 5.5 --- .github/actions/resolve-config/callers.test.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/resolve-config/callers.test.mjs b/.github/actions/resolve-config/callers.test.mjs index 6c9baaf2cd3..6305d59bdc6 100644 --- a/.github/actions/resolve-config/callers.test.mjs +++ b/.github/actions/resolve-config/callers.test.mjs @@ -1603,7 +1603,7 @@ test("no run-claude-cli plugin-dirs or add-dirs value names runner.temp, RUNNER_ // under which the default mode denies every call no rule allows, as dontAsk // does; check-permission-mode.sh accepts default for dontAsk on that basis. // 7b362428: lane.cjs:311-312; 164c2809: lane.cjs:355-358; d02b8697 and e5167fc2: lane.cjs:357-358; -// ba7af78d: lane.cjs:404-405; in cliArgs. A pin +// ba7af78d291f10bd75651857a0db2357c23df0fe: lane.cjs:404-405; in cliArgs. A pin // bump fails here until its lane.cjs is read and its SHA added. const PERMISSION_PROMPTS_NONE_LAUNCHERS = new Set([ "7b362428c76085a160e28656cd2c75c3147a69ff", @@ -3713,7 +3713,7 @@ test("scan job: every gate, skip and launcher class value the runner sets passes const schema = JSON.parse(read("../../../docs/conventions/pr-pipeline/pr-pipeline.schema.json")); const gateReasons = Object.keys(JSON.parse(read("../report-check-run/gate-skip-reasons.json"))); // run-claude-cli's failure classes, the keys of SUMMARY_NOTES in lane.cjs at - // the pinned ba7af78d. cant-fail-ok: an external contract's value list. + // the pinned ba7af78d291f10bd75651857a0db2357c23df0fe. cant-fail-ok: an external contract's value list. const laneClasses = ["credit-stop", "rate-limit", "auth", "overloaded", "max-turns", "timeout", "other"]; const cases = [ ...schema.$defs["skip-reason"].enum.map((value) => ["skip-reason", value]),