Repository navigation
fix(release): use the run-scoped token for the publish checkout - #15728
Conversation
âĶAT (#15726) The publish job's read-only checkout used secrets.CI_BOT_PAT while every other checkout in the release workflow uses the run-scoped token. Two release runs failed at exactly that step with "could not read Username for 'https://github.com': terminal prompts disabled" (git exit 128), and both passed on re-run. The bot PAT is already exported to the push and release-creation steps that write, so the read-only fetch does not need it.
Release failure v0.26.2-preview.1 â publish checkout authRoot causeThe
Both runs passed the identical checkout on re-run (attempt 3 of Fix
Verification
äļæčŊīæååļåĪąčīĨ v0.26.2-preview.1 ââ ååļäŧŧåĄæĢåšéīææ đå
äļĪæŽĄčŋčĄåĻéč·æķé―éčŋäšåŪå
ĻįļåįæĢåšïž äŋŪåĪ
éŠčŊ
|
|
â Qwen Triage finished â view run. See the stage comments in this thread for the result. â Qwen Triage å·ēåŪæ ââ æĨįčŋčĄãįŧæč§æŽįšŋįĻäļįåéķæŪĩčŊčŪšã |
|
Thanks for the PR â I dug into this one properly, because a change to release credential plumbing is exactly the kind of thing that should not be waved through. The diagnosis holds up, and I could confirm it from the failed run rather than taking the description's word for it. I'm escalating to a maintainer rather than approving, for the policy reason at the bottom â not because I found a defect. Template looks good â â every required heading is present, the Risk & Scope bullets are filled in rather than boilerplate, and the Chinese section is a real translation. Problem: observed, with hard evidence. #15726 is an open, machine-filed release failure. I pulled run Direction: aligned, and I verified the mechanism independently rather than trusting the write-up.
CHANGELOG: no direct reference â the only hit for these keywords upstream is an unrelated footer-badge change. Expected, since this is internal CI plumbing; the area is clearly relevant regardless. Size: not applicable â neither file is under a Stage 0 core path. 2 production lines ( Approach: minimal and correctly scoped. One wiring line plus a meta-test that pins both halves of the split, which satisfies the AGENTS.md rule about updating workflow meta-tests when CI definitions change. I checked the change against every existing pin that could have caught it, and none break:
No existing test pinned the removed Three non-blocking notes, none of which I'd hold the PR for:
Risk: no elevated Stage 1e signals â neither file matches the revert-correlated path set. Why I'm escalating instead of approving. This is the gate's release/auth rule, not a judgement call about quality: changes touching the release pipeline or credential wiring go to a maintainer rather than being auto-approved. So: I think the change is correct and well-targeted, and I'd be comfortable with it â but the call belongs to the release owners. @pomelo-nwu (lower current load of the two owners; cc @wenshao), assigning to you. Two things would make this a quick yes: a dry-run release to confirm the publish checkout succeeds on the run-scoped token, and the one-line description fix in note 1. Note on CI at the time of writing: nothing red, but the unit and integration suites ( Stopping at the gate here â no code-review or verdict comment will follow from this run. äļæčŊīææč°ĒčīĄįŪïžčŋäļŠ PR æčŪĪįįčŋäšïžå äļšååļæĩįĻįåæŪæĨįšŋæĢæŊäļč―éäūŋæūčŋįæđåĻãčŊææįŦïžčäļææŊäŧåĪąčīĨį run éįīæĨįĄŪčŪĪįïžäļæŊåŠéäŋĄ PR æčŋ°ãææēĄæįīæĨæđåïžčæŊč―ŽäšĪįŧīæĪč ââåå æŊäļéĒéĢæĄįįĨč§åïžäļæŊå äļšåį°äšįžšé·ã æĻĄæŋåŪæī â ââ ææåŋ éæ éĒé―åĻïžRisk & Scope äļæĄæŊåŪåĄŦčéæĻĄæŋåĨčŊïžäļæéĻåæŊįæĢįįŋŧčŊã éŪéĒïžå·ēč§æĩïžäļæįĄŽčŊæŪã #15726 æŊäļäļŠåžåŊįķæįãæšåĻæäšĪįååļåĪąčīĨ issueãææåäš run æđåïžåŊđé―ïžåđķäļæįŽįŦéŠčŊäšæšåķïžæēĄæįīæĨéäŋĄæčŋ°ã
CHANGELOGïžæ įīæĨåŊđåš ââ äļæļļæčŋäšå ģéŪčŊåŠå―äļäļåĪæ å ģį footer badge æđåĻãčŋåĻææäđäļïžå äļščŋæŊå éĻ CI æĨįšŋïžæ čŪšåĶä―čŊĨéĒåæūįķįļå ģã **č§æĻĄïž**äļéįĻ ââ äļĪäļŠæäŧķé―äļåĻ Stage 0 æ ļåŋč·Ŋåūäļã2 čĄįäš§äŧĢį ïž æđæĄïžæå°äļčåīåįĄŪã äļčĄæĨįšŋæđåĻïžå äļäļŠéåŪåå·ĨäļĪįŦŊįå æĩčŊïžįŽĶå AGENTS.md äļ"äŋŪæđ CI åŪäđéåæĨæīæ°å·Ĩä―æĩå æĩčŊ"įčĶæąãæææđåĻåŊđį §äšææåŊč―æĶä―åŪįæĒææčĻïžé―äļäžčĒŦį īåïž
æēĄæäŧŧä―æĒææĩčŊéåŪčĒŦį§ŧéĪį äļæĄäļéŧåĄįæč§ïžæé―äļäžäļšæĪåĄä―čŋäļŠ PRïž
éĢéĐïžæ Stage 1e åįš§äŋĄå· ââ äļĪäļŠæäŧķé―äļåđé äļåæŧįļå ģįč·Ŋåūéåã äļšäŧäđéæĐäļæĨčäļæŊæđåã čŋæŊå
ģåĄį release/auth č§åïžäļæŊåŊđčīĻéįäļŧč§åĪæïžč§ĶåååļæĩįĻæåæŪæĨįšŋįæđåĻåšäšĪįąįŧīæĪč
åģåŪïžčéčŠåĻæđåã įŧčŪšïžæčŪĪäļščŋäļŠæđåĻæĢįĄŪäļįŪæ įēūåïžæäļŠäššæŊåŊäŧĨæĨåį ââ ä―čŋäļŠåģåŪåąäšååļæĩįĻį ownerã@pomelo-nwuïžäļĪä― owner äļå―åčīč――čūä―įäļä―ïžæé @wenshaoïžïžå·ēæ PR ææīūįŧä― ãæäļĪäŧķäšč―čŪĐåŪåūåŋŦéčŋïžäļæŽĄ dry-run ååļäŧĨįĄŪčŪĪ publish æĢåšåĻčŋčĄčåīäŧĪįäļæåïžäŧĨåįŽŽ 1 æĄéĢäļčĄæčŋ°æīæĢã å
ģäšæ°åæķį CI įķæïžæēĄæįšĒčēïžä―åå
äļéææĩčŊåĨäŧķïž æŽæŽĄčŋčĄå°æĪäļšæĒ ââ äļäžåæäŧĢį åŪĄæĨæįŧčŪščŊčŪšã â Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
|
Verdict: äļææčĶįŧčŪšïž äļåŋäļŧåž æįŦïž
Central claim and A/BThe PR's central claim is narrow: the publish job's first checkout is a read-only fetch, it already disables credential persistence, and it is the last read-only fetch in Two structural facts make the claim testable rather than rhetorical, both scripted:
Witness for A1âA3: Mutation matrixEach row applies exactly one literal edit to the head workflow, runs the selected test through the repo's own vitest config, then restores with
Witness: Real-action arms and production evidenceThe pinned action was downloaded at its exact SHA and executed with a scrubbed
Arm C is the incident mechanism reproduced locally; the retry cadence (18 s, 16 s) matches the production log (20 s, 11 s). Production run
Witness: CorrectionsThese correct descriptions, not code. The triage stage-1 comment raised the first three; this round confirms each independently and adds the measurement.
One measurement note: the PR body's "103 tests pass" is the Linux figure. On this macOS host the same file is 102 passed + 1 skipped, because one case is gated on GNU FindingsAll findings are non-blocking; none argues against merging. S1 â the new test leaves the downstream dispatch unpinned. Suggested addition (one assertion, same shape as the existing two): expect(
steps.find((step) => step.name === 'Trigger ECS runner qwen update').env
.GITHUB_TOKEN,
).toBe('${{ secrets.CI_BOT_PAT }}');S2 â the same read-only-PAT pattern survives in N1 (note, not a request). M6 shows the test fails on any explicit token, including Not covered
MethodologyThree detached worktrees in a shallow clone: base Figures |
|
â AutoFix round 1 finished â view run. See this round's report below. äļæčŊīæâ AutoFix įŽŽ 1 č―Ūå·ēåŪæ ââ æĨįčŋčĄãæŽč―ŪæĨåč§äļæđã |
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
ðĪ Addressed the latest review feedback (round 1/10). What changed, and what I pushed back on: · å·ēåĪįææ°čŊåŪĄåéĶïžįŽŽ 1/10 č―ŪïžãæđåĻå åŪđäļæåéĐģäŋįäđåĪåĶäļïž Round summary â PR #15728 (head
|
qqqys
left a comment
There was a problem hiding this comment.
Critical-only scan at head d1632c1a. Verdict: APPROVE â no prior blocking findings exist on this PR, and the current scan found no provable blocking defect.
What the change does
One production line: the publish job's read-only Checkout in .github/workflows/release.yml:656-662 drops token: '${{ secrets.CI_BOT_PAT }}' and falls back to the run-scoped GITHUB_TOKEN, keeping ref, fetch-depth: 0 and persist-credentials: false unchanged.
Why the run-scoped token is sufficient here
- The
publishjob declarespermissions: contents: 'write'(:646-647), so the default token can read this repository; the checkout names norepository:override, so it fetches from the same repo the token is scoped to. refisneeds.prepare.outputs.release_sha, a commit of this repository â the same value,fetch-depthand persistence behaviour as before, so only the authenticating identity changed.- The workflow already proves the default token can fetch here: the
checkout_release_workflow_scriptsanchor (:161-180) has no token override and is reused seven times insidepublishitself (:693,:703,:725,:733,:744,:756,:764), andprepare's own full-depth checkout (:156-160) uses it too. Those paths are exercised on every release. - Triggers are
scheduleandworkflow_dispatch(:3-10), neverpull_request, so there is no restricted fork-token context in which the default token would be read-only.
No write path lost its credential
CI_BOT_PAT appears exactly three times after the change, and all three are writes:
:713âConditionally push release branch(push_release_branch), which also receivesGITHUB_TOKEN: github.token;:780âCreate GitHub Release and Tag, with the in-file reason that aGITHUB_TOKENevent cannot trigger downstream release-event workflows;:795âTrigger ECS runner qwen update(repository_dispatch).
No step's env block was touched, and the removed token was never persisted (persist-credentials: false predates this PR), so nothing downstream could have inherited git credentials from that checkout.
Test
scripts/tests/release-workflow.test.js:3479-3495 pins both halves of the split: the publish checkout has no token and keeps persist-credentials: false, while push_release_branch still gets CI_BOT_PAT and Create GitHub Release and Tag still gets it as GITHUB_TOKEN. The lookups fail loudly rather than passing vacuously â a missing step makes .with / .env throw. The reworded canonicalWipe rationale at :295-301 leaves the pinned body byte-identical, so the equality pin still holds.
CI at this head
Everything reported is green â Test (ubuntu-latest, Node 22.x) (35m37s), Lint & Static, Integration Tests (no-AK), web-shell E2E Smoke, the TUI gates and all four Installed npm global and npx lanes. Nothing red or pending is attributable to this change.
One non-blocking number worth knowing, since it bears on the next PR that touches this file: release.yml is 40032 bytes at this head against a recorded .size-baseline:58 of 35955 â an overage of 4077 bytes, inside the growth allowance of 4096 that check-workflow-size.sh:33 sets and the workflow-size.test.js "is within its baseline allowance" case reads back from it, with 19 bytes of headroom left. The ratchet's stale-baseline leniency would not cover this file, because it only applies when the file is byte-identical to the PR's base and this PR edits it; the allowance is what keeps the gate green here.
|
Released in v0.26.3. |




What this PR does
The release workflow's
Publish Releasejob now fetches the release tree with the run-scoped GitHub token instead of the long-lived bot PAT. The bot PAT remains exported only to the steps that write: the release-branch force push, GitHub Release creation, and the downstream dispatch.A workflow meta-test pins that split: the read-only checkout must not override the token, while the push and release-creation steps must keep receiving the PAT.
Why it's needed
On 2026-10-27 two release runs failed in
Publish ReleaseatCheckoutwithcould not read Username for 'https://github.com': terminal prompts disabledand git exit 128, then passed the identical checkout on re-run, with run 40486976670 completing successfully on that attempt. That checkout was the only read-only fetch in the workflow authenticating with the long-lived PAT, and it already disables credential persistence, so the PAT added an auth dependency without adding access. The PAT was only needed where the job actually writes; moving the read-only fetch onto the run-scoped token removes the failing dependency and narrows credential exposure.Reviewer Test Plan
How to verify
Read the
publishjob in the release workflow: its first checkout should have no token override and should keeppersist-credentials: false; the release-branch push step should still receiveCI_BOT_PAT, and "Create GitHub Release and Tag" should still use it asGITHUB_TOKEN.Run the focused meta-tests:
npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/release-workflow.test.jsExpected: 103 tests pass. Re-adding
token: '${{ secrets.CI_BOT_PAT }}'to the publish checkout should make the new test fail, which is the regression witness. A production dry-run release is the end-to-end check when credentials are available; this session could not dispatch one.Evidence (Before & After)
Non-UI CI wiring change, so there are no screenshots. Before: the publish checkout passed
token: secrets.CI_BOT_PAT, and two runs failed at that step with the git auth error above. After: the checkout uses the run-scoped token, the PAT stays on the write steps, and the new test pins both halves. Mutation probe: re-adding the token made the new test fail (1 failed | 102 skipped); restoring the change returned103 passed.Tested on
Environment (optional)
Linux workspace:
npm run build,npm run typecheck,npm run lint, and focused Vitest suites. No production GitHub credentials were available, so the release run itself was not exercised.Risk & Scope
GITHUB_TOKENinstead of the PAT. The token hascontents: writeon this job and can read a public repository, so the fetch is unchanged in capability; the PAT remains available for every write path.secrets.CI_BOT_PATat job level for the write steps.Linked Issues
Fixes #15726
äļæčŊīæ
æŽ PR åäšäŧäđ
ååļå·Ĩä―æĩį
Publish ReleaseäŧŧåĄį°åĻä―ŋįĻæŽæŽĄčŋčĄčåīå į GitHub äŧĪįæåååļäŧĢį æ ïžčäļæŊéŋæææįæšåĻäšš PATãæšåĻäšš PAT äŧåŠåŊžåšįŧæ§čĄåå ĨįæĨéŠĪïžååļåæŊåžšåķæĻéãååŧš GitHub ReleaseïžäŧĨåäļæļļ dispatchãæ°åĒįå·Ĩä―æĩå æĩčŊéåŪäščŋäļåå·ĨïžåŠčŊŧæĢåšäļåūčĶįäŧĪįïžčæĻéäļååŧš Release įæĨéŠĪåŋ éĄŧįŧ§įŧæĨæķ PATã
äļšäŧäđéčĶåŪ
2026-10-27 æäļĪæŽĄååļčŋčĄåĻ
Publish ReleaseįCheckoutæĨéŠĪåĪąčīĨïžæĨéäļšcould not read Username for 'https://github.com': terminal prompts disabledäŧĨå git éåšį 128ïžéååĻéč·æķįļåįæĢåšåīéčŋäšïžäļčŋčĄ 40486976670 åĻčŊĨæŽĄå°čŊäļåŪæīæåãčŊĨæĢåšæŊå·Ĩä―æĩäļåŊäļä―ŋįĻéŋæ PAT éīæįåŠčŊŧæåïžčäļåŪå·ēįŧįĶįĻäšåæŪæäđ åïžå æĪ PAT åŠåĒå äšéīæäūčĩïžåđķæēĄæåĒå čŪŋéŪč―åãPAT åŠåĻäŧŧåĄįæĢåå Ĩįå°æđæéčĶïžæåŠčŊŧæåæđå°čŋčĄčåīäŧĪįäļïžį§ŧéĪäšåĪąčīĨįäūčĩåđķįžĐå°äšåæŪæīéēéĒãåŪĄæĨč æĩčŊčŪĄå
åĶä―éŠčŊ
æĨįååļå·Ĩä―æĩäļį
publishäŧŧåĄïžåŪįéĶæŽĄæĢåšäļåščĶį tokenïžåđķåšäŋįpersist-credentials: falseïžååļåæŊæĻéæĨéŠĪäŧåšæķå°CI_BOT_PATïžâCreate GitHub Release and TagâäŧåšæåŪä―äļšGITHUB_TOKENä―ŋįĻãčŋčĄčįĶįå æĩčŊïž
npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/release-workflow.test.jséĒæïž103 äļŠæĩčŊéčŋãæ
token: '${{ secrets.CI_BOT_PAT }}'å åååļäŧŧåĄæĢåšåšä―ŋæ°æĩčŊåĪąčīĨïžčŋå°ąæŊåå―čŊæŪãæåæŪæķïžįäš§ dry-run ååļæŊįŦŊå°įŦŊæĢæĨïžæŽäžčŊæ æģæīūåãčŊæŪïžåååŊđæŊïž
čŋæŊé UI į CI æĨįšŋæđåĻïžå æĪæēĄææŠåūãäŋŪæđåïžååļäŧŧåĄæĢåšäž å Ĩ
token: secrets.CI_BOT_PATïžäļĪæŽĄčŋčĄåĻčŊĨæĨéŠĪå äļčŋ° git éīæéčŊŊåĪąčīĨãäŋŪæđåïžæĢåšä―ŋįĻčŋčĄčåīäŧĪįïžPAT äŋįåĻåå ĨæĨéŠĪäļïžæ°æĩčŊéåŪäščŋäļĪéĻåãååžæĒéïžæ token å ååæ°æĩčŊåĪąčīĨïž1 failed | 102 skippedïžïžæĒåĪæđåĻååäļš103 passedãæĩčŊåđģå°
įŊåĒïžåŊéïž
Linux å·Ĩä―åšïž
npm run buildãnpm run typecheckãnpm run lintïžäŧĨåčįĶį Vitest åĨäŧķãæēĄæįäš§ GitHub åæŪïžå æĪæŠåŪé čŋčĄååļæĩįĻãéĢéĐäļčåī
GITHUB_TOKENčäļæŊ PATãčŊĨäŧĪįåĻæĪäŧŧåĄäļå ·æcontents: writeïžäđč―čŊŧåå Žåžäŧåšïžå æĪæåč―åäļåïžPAT äŧåŊįĻäšææåå Ĩč·Ŋåūãsecrets.CI_BOT_PATäūåå ĨæĨéŠĪä―ŋįĻãå ģč Issue
Fixes #15726