Skip to content

ci(pr-pipeline): fund work-resolve-issue from the issue-lane subscription token - #8437

Merged
kyle-sexton merged 1 commit into
mainfrom
ci/issue-lane-oauth-token
Oct 19, 2026
Merged

kyle-sexton merged 1 commit into
mainfrom
ci/issue-lane-oauth-token

Conversation

@kyle-sexton

Copy link
Copy Markdown
Member

No related issue: interim funding switch from the lane-funding design round

Hold: a human merges this

Summary

work-resolve-issue runs on its own funding role's subscription token (issue-lane, as docs/conventions/pr-pipeline.yaml funding: already maps it) instead of the automations token. The write runner's lane record now names the credential the caller actually passed, not a hardcoded AUTOMATIONS_CLAUDE_CODE_OAUTH_TOKEN.

Fix

  • .github/workflows/work-resolve-issue.yml: passes secrets.ISSUE_LANE_CLAUDE_CODE_OAUTH_TOKEN, and role: issue-lane on both write-runner calls (resolve-issue, report-outcome).
  • .github/workflows/pr-run-activity-write.yml: new required role input. A step before report-lane-outcome checks it is lowercase letters, digits and hyphens, and outputs <ROLE>_CLAUDE_CODE_OAUTH_TOKEN (upper-cased, - to _), which credential: now reads. The summary job uses the same claude-code-oauth-token secret slot and calls no report-lane-outcome, so it needs nothing else.
  • .github/workflows/pr-refine.yml, .github/workflows/pr-unblock.yml: pass role: automations on every write-runner call (1 and 7 calls).
  • docs/conventions/pr-pipeline/README.md Funding: a claude-code-action lane runs with its role's OAuth token, and the write runner takes the role as input. A .changes/pr-pipeline/ fragment records the change.

This PR edits pr-run-activity-write.yml, so the broker-checked pr-refine / fix-docs check is expected red on it.

Verification

  • actionlint on the four changed workflows: exit 0, no findings.
  • node .github/standards/runner-policy/runner-policy.mjs --root .: Runner policy passed.
  • scripts/check-affected.sh --tests: 6 passed, 3 skipped over 6 changed files (skips: shellcheck, validate-plugins, ruff, with no matching files).

Related

🤖 Generated with Claude Code

…tion token

work-resolve-issue passes ISSUE_LANE_CLAUDE_CODE_OAUTH_TOKEN. The write
runner takes a required role input and names <ROLE>_CLAUDE_CODE_OAUTH_TOKEN
as the lane record's credential instead of a hardcoded name; pr-refine and
pr-unblock pass role: automations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T14:58:39.164499Z f1e6839 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

claude-review reviewed f1e6839ddf6e1c3feef94ed737ed6232b8feea4a: 0 finding(s), 0 as inline comments.

No blocking findings on head f1e6839.

What I checked (I read the code myself; I did not run actionlint or the tests):

  • Callers: every uses: ./.github/workflows/pr-run-activity-write.yml caller passes the new required role input. That is 1 in pr-refine.yml, 7 in pr-unblock.yml and 2 in work-resolve-issue.yml, ten calls in all (the PR body says "1 and 7" for the other two files, then adds the work-resolve-issue pair). No caller is missing it.
  • Secret wiring: work-resolve-issue.yml passes secrets.ISSUE_LANE_CLAUDE_CODE_OAUTH_TOKEN only on the resolve-issue call. The report-outcome call passes no secret, so act-skill is skipped and the Name the run's credential and Record the lane outcome steps are skipped with it. This is unchanged by the PR.
  • Credential step: the role is passed through env: rather than interpolated into the script, and the regex rejects anything but lowercase letters, digits and hyphens. The output name ${ROLE^^} with - replaced by _ gives ISSUE_LANE_CLAUDE_CODE_OAUTH_TOKEN for issue-lane and AUTOMATIONS_CLAUDE_CODE_OAUTH_TOKEN for automations. That matches the old hardcoded value for the existing callers.
  • Docs and fragment: the change fragment and the Funding paragraph in the pr-pipeline README match the code.

Unverified:

  • Whether the ISSUE_LANE_CLAUDE_CODE_OAUTH_TOKEN secret exists in the repository or org. I can't see secrets from this lane. If it is missing, resolve-issue runs with an empty token.
  • The PR's verification claims (actionlint, runner-policy, check-affected.sh) are author-claimed and I did not rerun them.
  • The expected red pr-refine / fix-docs check is the author's claim and I did not confirm it.

Nit, not reported as a finding: the new Name the run's credential step sits between the existing "The lane record: …" comment block and the Record the lane outcome step it describes. That comment is now separated from its step in pr-run-activity-write.yml. Moving the new step and its comment above that block would keep them adjacent.

No closing issue: the body says "No related issue", so there are no acceptance criteria to check. The PR body's "Hold: a human merges this" line is a merge hold and is respected as such.

@github-actions

Copy link
Copy Markdown
Contributor

claude-security-review reviewed f1e6839ddf6e1c3feef94ed737ed6232b8feea4a: 0 finding(s), 0 as inline comments.

Security review: PR #8437 at f1e6839

No security findings.

What the PR changes. It adds a required role input to pr-run-activity-write.yml. A new credential step derives the credential name recorded in the lane record from that role. work-resolve-issue now passes ISSUE_LANE_CLAUDE_CODE_OAUTH_TOKEN as the OAuth secret, and the pr-refine and pr-unblock callers pass role: automations.

Checked:

  • Injection in the new step. inputs.role reaches the shell through an env: variable, not through ${{ }} inside run:. The step validates it against ^[a-z][a-z0-9-]*$ before writing name=... to $GITHUB_OUTPUT, so a value with a newline or other special characters cannot inject extra outputs. Every caller passes a literal role in with:.
  • Secret handling. The credential output is only the secret's name, passed as the credential: label to the lane-record step. No secret value is read or echoed. The OAuth token is still passed through secrets: to the action, unchanged.
  • Secret scoping. The work-resolve-issue resolve-issue job moves from the shared automations token to the dedicated issue-lane token. That narrows the token's reach. Trust triggers, permissions and the secrets: surface are otherwise unchanged. The report-outcome job passes role: issue-lane but no secret, so no token reaches it.
  • Callers. The only workflows that call pr-run-activity-write.yml are pr-refine, pr-unblock and work-resolve-issue. All now pass role, so the new required input breaks none of them.
  • Instruction surfaces. The docs/conventions/pr-pipeline/README.md edit adds a description and removes no guardrail. I did not consult the instruction exception register, because nothing in the diff deletes or softens a standing rule.

GitHub Actions hardening items such as pins and triggers are zizmor's lane, and nothing here needed the deeper reasoning this lane adds.

@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit a060b10 Oct 19, 2026
29 checks passed
@kyle-sexton
kyle-sexton deleted the ci/issue-lane-oauth-token branch October 19, 2026 15:07
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.

1 participant