fix(ci): keep successful external sweep dispatch green / 修复 CI:避免通知失败覆盖扫描调度成功 - #2455
Conversation
Use pull-request write permission for run-link comments and keep a successful sweep dispatch green if notification still fails.\n\n中文:使用 pull request 写权限发布运行链接,并在通知仍失败时保持已成功调度的扫描为成功状态。
|
Claude finished @cquil11's task in 1m 9s —— View job Review of PR #2455
LGTM - no blocking issues found. Verified details:
|
There was a problem hiding this comment.
Beyond the inline nit about the unprotected listWorkflowRuns polling loop, I also checked the permission swap itself (dropping issues: write/pull-requests: read for pull-requests: write) — issues.createComment on a PR issue number is covered by the pull-requests scope in the GITHUB_TOKEN permission model, so the new permission set is correct for this call, not a regression.
Extended reasoning...
One short paragraph per instructions for this exception case.
| `已为获批的外部提交 \`${pull.head.sha}\` 调度${runLink}。`, | ||
| '后续新提交不会自动获得信任;如需批准新的 SHA,请移除并重新添加主扫描标签。', | ||
| ].join('\n'); | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: pull.number, | ||
| body, | ||
| }); | ||
| try { | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: pull.number, | ||
| body, | ||
| }); | ||
| } catch (error) { | ||
| core.warning( | ||
| `Sweep dispatched successfully, but the PR comment failed: ${error.message}`, | ||
| ); | ||
| } |
There was a problem hiding this comment.
🟡 The fix only wraps issues.createComment in try/catch, but the listWorkflowRuns polling loop just above it (also running after the successful createWorkflowDispatch) is left unwrapped. If that call throws (transient 5xx, secondary rate limit, network blip), the step still fails uncaught despite the sweep already being dispatched — the same failure class this PR sets out to fix. Consider wrapping the polling loop (or the whole post-dispatch block) the same way for full coverage.
Extended reasoning...
This PR's stated goal is to ensure "a notification-policy failure cannot make an already-dispatched sweep appear unsuccessful," and it achieves that for one specific call: github.rest.issues.createComment (now wrapped in try/catch at the end of the script). However, the github.rest.actions.listWorkflowRuns polling loop that runs immediately after createWorkflowDispatch succeeds — and before the comment call — is not given the same protection.
Code path: createWorkflowDispatch succeeds (line ~109, the irreversible action that starts the e2e run), then the script enters a loop that polls listWorkflowRuns up to 15 times to resolve dispatchedRun for the run-link comment. This loop already tolerates the "run not found" case gracefully — if no matching run turns up after 15 attempts, dispatchedRun stays undefined and the code falls back to a generic workflow link. But that graceful handling only covers a benign not-found outcome, not an actual API failure. If listWorkflowRuns itself rejects (a transient 5xx, a secondary rate limit, or a network blip), the await throws inside the loop, propagates uncaught, and the whole github-script step fails — exactly the "green dispatch, red job" scenario this PR was written to eliminate.
Why the existing fix doesn't prevent it: the new try/catch block only surrounds the createComment call, which executes after this loop. Anything that throws during the loop itself never reaches that try/catch, so it's outside the scope of the current fix even though it shares the identical failure class (a non-dispatch API call failing after the dispatch already succeeded).
Step-by-step reproduction of the gap:
- Maintainer applies the sweep label; the workflow authorizes the actor and calls
createWorkflowDispatch— this succeeds and the e2e run is now queued/running. - The script enters the polling loop and calls
listWorkflowRunsto find the new run's URL for the notification comment. - GitHub's Actions API returns a transient 502/503, or the token hits a secondary rate limit on this call (both are realistic under load, since this endpoint is being polled up to 15 times).
- The
await github.rest.actions.listWorkflowRuns(...)throws. There is no try/catch around it, so the exception unwinds out of the loop and out of the script. - The
github-scriptstep fails, the job goes red — even though the sweep was already successfully dispatched in step 1 — reproducing the precise inconsistency (successful dispatch, failed-looking job) that this PR's description calls out as the bug being fixed.
Impact: this is a genuine gap relative to the PR's own stated invariant, but it's a lower-probability trigger than the deterministic 403 this PR was written to fix (that 403 was on the comment endpoint specifically, due to a permissions mismatch that's now corrected). listWorkflowRuns only needs actions: read/write, which this workflow already has, so it won't hit the same permissions failure — it would need an actual transient GitHub API error to fail. The consequence is also contained: a misleading red job status that could at worst prompt a maintainer to remove/re-add the sweep label and trigger a redundant dispatch, not data loss or a broken sweep.
Suggested fix: wrap the polling loop (or the entire post-dispatch block from after createWorkflowDispatch through the comment) in the same try/catch-and-core.warning pattern already used for the comment call, so any post-dispatch API failure is treated as best-effort and doesn't flip the job status.
Use pull-request write permission for run-link comments and keep a successful sweep dispatch green if notification still fails.\n\n中文:使用 pull request 写权限发布运行链接,并在通知仍失败时保持已成功调度的扫描为成功状态。
Summary
pull-requests: writefor PR run-link commentsRoot cause
In run 30764133602, authorization and
workflow_dispatchsucceeded, creating e2e run 30764143282. The dispatcher failed only afterward when the PR-comment endpoint returned403 Resource not accessible by integrationdespite the workflow requestingissues: write.The endpoint advertises
pull_requests=writeas an accepted permission, so this switches to that repository-consistent permission. The fallback warning ensures a notification-policy failure cannot make an already-dispatched sweep appear unsuccessful.Validation
actionlint .github/workflows/trusted-external-sweep.yml摘要
pull-requests: write,用于在 PR 中发布运行链接根本原因
在运行 30764133602中,授权和
workflow_dispatch均成功,并创建了 e2e 运行 30764143282。调度器只在随后调用 PR 评论接口时失败;尽管工作流请求了issues: write,该接口仍返回403 Resource not accessible by integration。该接口将
pull_requests=write列为可接受权限,因此本修复改用与仓库现有工作流一致的权限。警告回退保证通知策略失败不会让已成功调度的扫描显示为失败。验证
actionlint .github/workflows/trusted-external-sweep.yml