Skip to content

docs(autofix): design runner-level isolation for PAT-bearing steps - #9525

Merged
wenshao merged 2 commits into
mainfrom
docs/autofix-gate-isolation-9089
Aug 21, 2026
Merged

docs(autofix): design runner-level isolation for PAT-bearing steps#9525
wenshao merged 2 commits into
mainfrom
docs/autofix-gate-isolation-9089

Conversation

@wenshao

@wenshao wenshao commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Adds a design doc for the structural close of #9089: move the autofix trust boundary from inside a step to between jobs.

  • execute — agent, verification gate, repair. Runs branch code, holds no push credential. Emits fix.patch plus an advisory verdict as an artifact.
  • publishneeds: execute. Runs no branch code at all (no npm, no build, no test, no repo script, no hooks), re-derives its own decision from the patch text on the trusted side (applies cleanly to the recorded base, footprint allowlist, workflow/lockfile refusal, growth budget, commit-message contract, head-SHA lease) and pushes with the PAT.

Plus: kill agent process trees by cgroup lineage instead of an env marker (the source of R8-8/R9-3/R11-10), ephemeral registrations for execute, running only publish on a GitHub-hosted runner so the PAT leaves the shared host entirely, and — explicitly part of the work — deleting the in-step enumeration machinery the split makes redundant. The goal is a smaller trust surface, not another layer.

No behaviour change: this PR adds one file under docs/design/.

Why it's needed

PR #9214 attempted to close #9089 from inside the job, by running the verification gate in an ephemeral container. It did not converge: eleven review rounds took its own diff from 329 to 2,700 lines while the per-round Critical count rose 8 → 9 → 15 → 19 → 29. Rounds 10 and 11 changed no code at all, and round 11 still produced 14 new Criticals on byte-identical files — six of them of the form "the site this diff ADDS lacks the discipline this diff installs elsewhere." #9214 is now frozen (draft, autofix/needs-human); its findings are inventoried in #9524.

Two results from that attempt shape this design:

  1. A container around the executor cannot close autofix: PAT-bearing jobs share a host with untrusted branch code — needs runner-level isolation #9089, because the root of trust sits outside it. The gate's digest chain is rooted in steps.stage.outputs.*; the runner parses a step's $GITHUB_OUTPUT last-wins at step end, from a file under attacker-writable $RUNNER_TEMP, and no sweep runs before the staging step. A same-uid co-resident can steer both sides of every downstream comparison.
  2. The wrapper could never have run post-merge anyway — it digest-verifies a copy of itself that the staging loop never creates, and the helper digest is path-dependent across two different path sets. CI stayed green because the pre-merge -z skip path masks it.

The honest trade is stated in the doc: "verified" weakens to "deterministically checked + advisory build/test", because the publish side cannot execute the branch. The comparison is not against a working guarantee — today's verdict is forgeable, and on the #9214 branch it was never produced at all.

Reviewer Test Plan

How to verify

Read the doc against #9089 (the threat model it closes), #9524 (the findings it must account for), and the frozen #9214 (the approach it supersedes). Specifically worth checking: that section B's re-derivation list contains nothing requiring branch execution, and that section E's deletion pass is scoped so issue-autofix keeps what it still depends on. Docs-only — prettier --check is the whole mechanical gate.

Evidence (Before & After)

N/A — documentation only, no user-visible or runtime change.

Tested on

OS Status
🍏 macOS N/A
🪟 Windows N/A
🐧 Linux

Environment (optional)

N/A — no runtime involved; npx prettier --check docs/design/autofix-gate-runner-isolation.md passes.

Risk & Scope

  • Main risk or tradeoff: none in this PR (docs only). The design's own tradeoff is that "verified" weakens to deterministic checks plus an advisory build/test, because the publish side must not execute the branch. The doc says so rather than hiding it.
  • Not validated / out of scope: the implementation itself; issue-autofix, which has the same shape but creates a branch and a PR rather than pushing to an existing head, so its publish-side checks differ and are not designed here. Two open questions are left open rather than assumed — whether the ECS pool permits --ephemeral registrations, and whether a GitHub-hosted runner is acceptable for the PAT-bearing publish job under the current egress policy.
  • Breaking changes / migration notes: none. Rollout is sequenced in the doc so the PAT leaves the shared host first and the infrastructure change lands last.

Linked Issues

Refs #9089 — the structural close this designs.
Refs #9524 — the findings inventory it must account for.
Refs #9556 — the same question on the review side.
Supersedes the approach in #9214.

中文说明

本 PR 做了什么

#9089 的结构性收口新增一份设计文档:把 autofix 的信任边界从"步骤内部"上移到"job 之间"。

  • execute——agent、验证门、修复。执行分支代码,不持有任何推送凭据,只产出 fix.patch 与仅供参考的 verdict 作为产物。
  • publish——needs: execute完全不执行分支代码(无 npm、无构建、无测试、无仓库脚本、无 git hook),在可信侧基于补丁文本自行推导判定(能否干净应用于记录的基线、足迹白名单、拒绝 workflow 与锁文件、增长预算、提交信息规范、head SHA 租约),然后用 PAT 推送。

此外:用 cgroup 血缘取代 env 标记来清杀 agent 进程树(R8-8/R9-3/R11-10 的来源);为 execute 启用一次性注册;只把 publish 放到 GitHub 托管 runner,使 PAT 彻底离开共享主机;并且明确把删除因拆分而冗余的步骤内枚举机制纳入本项工作——目标是更小的信任面,而不是再加一层。

无行为变更:本 PR 只新增 docs/design/ 下的一个文件。

为什么需要

PR #9214 尝试在 job 内部关闭 #9089——把验证门放进一次性容器里运行。该方案没有收敛:11 轮评审把它自身的 diff 从 329 行推到 2700 行,每轮 Critical 数量为 8 → 9 → 15 → 19 → 29。第 10、11 轮一行代码都没改,第 11 轮仍在逐字节相同的文件上产生 14 个新 Critical,其中 6 条的形态是"这个 diff 新加的地方,缺少这个 diff 在别处安装的纪律"。#9214 现已冻结(draft + autofix/needs-human),其发现清单见 #9524

该尝试的两个结论决定了本设计:

  1. 把执行方装进容器无法关闭 autofix: PAT-bearing jobs share a host with untrusted branch code — needs runner-level isolation #9089,因为信任根在容器之外。 门的摘要链根植于 steps.stage.outputs.*;runner 在步骤结束时以 last-wins 方式解析位于可写 $RUNNER_TEMP 下的 $GITHUB_OUTPUT,且暂存步骤之前没有任何清扫。同 uid 的同驻进程可以同时操控下游每一次比较的两侧。
  2. 该 wrapper 合入后本来也跑不起来——它校验一个暂存循环从未创建的自身副本,且 helper 摘要带路径、两侧路径集不同。CI 保持全绿只是因为 pre-merge 的 -z 跳过路径把它挡住了。

文档中如实写明了代价:"已验证"会弱化为"确定性检查 + 仅供参考的构建/测试",因为发布侧不能执行分支代码。但对比基准并不是"原本可用的保证":现有 verdict 本就可伪造,而在 #9214 分支上它根本没被产生过。

评审验证计划

如何验证

对照 #9089(它要关闭的威胁模型)、#9524(它必须交代的发现清单)与已冻结的 #9214(它取代的方案)阅读本文档。特别值得核对两点:B 节的重新推导清单中不含任何需要执行分支代码的项;E 节的删除范围有没有把 issue-autofix 仍依赖的东西一并删掉。纯文档改动,机械门只有 prettier --check

证据(改动前后)

N/A——纯文档,无用户可见变化,也无运行时变化。

测试平台

系统 状态
🍏 macOS N/A
🪟 Windows N/A
🐧 Linux

环境(可选)

N/A——不涉及运行时;npx prettier --check docs/design/autofix-gate-runner-isolation.md 通过。

风险与范围

  • 主要风险或权衡: 本 PR 无(纯文档)。设计本身的权衡是"已验证"弱化为确定性检查加仅供参考的构建/测试,因为发布侧不得执行分支代码——文档如实写明,未加掩饰。
  • 未验证 / 不在范围内: 实现本身;issue-autofix 形态相同但它是新建分支并开 PR,发布侧判定不同,本文未涵盖。两个未决问题如实留白而非假定——ECS 池是否允许 --ephemeral 注册,以及当前出网策略下携带 PAT 的 publish 能否放在 GitHub 托管 runner 上。
  • 破坏性变更 / 迁移说明: 无。文档中的推进顺序刻意让 PAT 先离开共享主机,基础设施改动排在最后。

关联 Issue

Refs #9089——本文所设计的结构性收口。
Refs #9524——它必须交代的发现清单。
Refs #9556——评审侧的同一问题。
取代 #9214 的方案。

PR #9214 tried to close issue #9089 from inside the job by running the
verification gate in an ephemeral container. Eleven review rounds took its
diff from 329 to 2,700 lines while the per-round Critical count rose
8 -> 9 -> 15 -> 19 -> 29; rounds 10 and 11 changed no code and round 11
still produced 14 new Criticals on byte-identical files, six of them
reporting that a site the diff added lacked the discipline the same diff
installed elsewhere. That PR is frozen; its findings are inventoried in
issue #9524.

Two of its results shape this design. The container cannot help, because
the gate's root of trust sits outside it: the digest chain is rooted in
step outputs that the runner parses last-wins at step end, from a file
under attacker-writable RUNNER_TEMP, with no sweep before the staging
step. And the wrapper could never have run post-merge at all, which the
pre-merge skip path hid from CI.

The design moves the boundary from inside a step to between jobs: an
execute job that runs branch code and holds no credentials, and a publish
job that runs no branch code, re-derives its own decision from the patch
instead of trusting the gate verdict, and holds the PAT. Agent process
trees are killed by cgroup lineage rather than by an env marker, and the
in-step enumeration machinery the split makes redundant is deleted rather
than kept.
@github-actions github-actions Bot added the review/self-reported The linked issue was opened by the PR author (self-reported) label Aug 20, 2026
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the design doc — and for the honest post-mortem of the #9214 attempt behind it. One gate item before content review: the PR body doesn't follow the PR template. It uses freeform headings (## Why, ## What this proposes, ## Notes) where the template asks for ## What this PR does, ## Why it's needed, ## Reviewer Test Plan, ## Risk & Scope, and ## Linked Issues.

@wenshao could you restructure the body onto the template headings? The substance is already all there, so this is a heading remap: "What this proposes" → ## What this PR does, "Why" → ## Why it's needed, "Notes" → ## Risk & Scope, plus a docs-applicable ## Reviewer Test Plan (How to verify: review the design against #9089 / #9524; Evidence and Tested on: N/A) and lifting "Refs #9089, #9524. Supersedes the approach in #9214" into ## Linked Issues. A @qwen-code /triage re-run will pick it up from there.

中文说明

感谢这份设计文档,也感谢背后对 #9214 尝试的坦诚复盘。进入内容审查前有一个门槛项:PR 正文没有遵循 PR 模板。正文使用了自由标题(## Why## What this proposes## Notes),而模板要求的是 ## What this PR does## Why it's needed## Reviewer Test Plan## Risk & Scope## Linked Issues

@wenshao 能否把正文调整到模板标题下?内容已经齐全,主要是标题对应调整:"What this proposes" → ## What this PR does,"Why" → ## Why it's needed,"Notes" → ## Risk & Scope,加上文档类 PR 适用的 ## Reviewer Test Plan(How to verify:对照 #9089 / #9524 审阅设计;Evidence 与 Tested on:N/A),并把 "Refs #9089, #9524. Supersedes the approach in #9214" 放进 ## Linked Issues。之后用 @qwen-code /triage 重新触发即可继续。

Qwen Code · qwen3.8-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

📄 Docs-only change — the automatic review ran at --effort medium (verified findings, no reverse audit; medium posts no inline comments). Outcome:

(no relayable "Review complete:" line in the run output — see the run log)

Reviewed head: 35cfd3eb069eebfb25a7f92a2640320c39bd5006. Full report in the workflow run. For a full high-effort review with inline comments, comment @qwen-code /review.

中文说明

📄 纯文档变更 —— 自动评审以 --effort medium 运行(发现已验证、无反向审计;medium 不发布行内评论),结果见上方引用行。评审的 head:35cfd3eb069eebfb25a7f92a2640320c39bd5006。完整报告见 workflow 运行;如需带行内评论的完整高强度(high-effort)评审,请评论 @qwen-code /review

@wenshao

wenshao commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

@qwen-code-dev-bot qwen-code-dev-bot added the autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+) label Aug 20, 2026
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。移除 autofix/takeover 标签(或评论 @qwen-code /takeover stop)即可释放。

@qwen-code-dev-bot

qwen-code-dev-bot commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

AutoFix round 2 finishedview run. See this round's report below.

中文说明

AutoFix 第 2 轮已完成 —— 查看运行。本轮报告见下方。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind main, so it merged current main in via update-branch and will retry on the next scan. A stale base (a dependency or symbol main already changed) can fail the build without being the fix's fault; if it still fails once current, it hands off to a human.

What I found before stopping:

Blocker

The round's only finding is triage review rv:4978214393 (CHANGES_REQUESTED, stage 1a): the PR body must move from freeform headings (## Why, ## What this proposes, ## Notes) onto the repository PR template headings. That fix is a GitHub PR-body edit. This agent holds no GitHub credentials, and the review workflow has no PR-body update channel — it can only push commits and post comments. No allowed action this round can apply the fix, and no in-checkout change addresses it: the diff is one design doc (docs/design/autofix-gate-runner-isolation.md, +249 lines) against which the triage gate raised no content objection. I made no changes and committed nothing.

What needs a human (mechanical remap, per the review)

The PR author or a maintainer remaps the body headings: "What this proposes" -> ## What this PR does; "Why" -> ## Why it's needed; "Notes" -> ## Risk & Scope; adds a docs-applicable ## Reviewer Test Plan (How to verify: review the design against #9089 / #9524; Evidence and Tested on: N/A); lifts "Refs #9089, #9524. Supersedes the approach in #9214" into ## Linked Issues. Then re-run @qwen-code /triage to continue to content review.

中文说明

🤖 AutoFix 更新了一个过期的 base —— 修复未通过验证,但本 PR 落后于 main,因此已通过 update-branch 合入当前 main,并将在下次扫描时重试。过期的 base(main 已改动的依赖或符号)可能让构建失败而并非修复本身的错;若 base 更新后仍然失败,将移交人工处理。

停止前我了解到的情况:

阻塞点

本轮唯一的发现是 triage 评审 rv:4978214393(CHANGES_REQUESTED,第 1a 阶段):PR 正文必须从自由标题(## Why## What this proposes## Notes)改为遵循仓库 PR 模板的标题。该修复是一次 GitHub PR 正文(元数据)编辑。本 agent 没有任何 GitHub 凭据,review 工作流也没有更新 PR 正文的通道——它只能推送提交和发表评论。本轮没有任何被允许的动作能完成该修复,也不存在任何仓库内的改动能解决它:本 PR 的 diff 只有一份设计文档(docs/design/autofix-gate-runner-isolation.md,+249 行),triage 门对其内容没有提出任何异议。我没有做任何改动,也没有提交任何内容。

需要人工完成的事项(机械的标题重映射,按评审所述)

由 PR 作者或维护者重映射正文标题:"What this proposes" -> ## What this PR does;"Why" -> ## Why it's needed;"Notes" -> ## Risk & Scope;新增适用于文档类 PR 的 ## Reviewer Test Plan(How to verify:对照 #9089 / #9524 审阅设计;Evidence 与 Tested on:N/A);把 "Refs #9089, #9524. Supersedes the approach in #9214" 提升到 ## Linked Issues。然后重新运行 @qwen-code /triage 进入内容审查。

Run log: https://github.com/QwenLM/qwen-code/actions/runs/32355912104


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

Feedback triaged this round — 1 item, 0 addressable by a code change.

[rv:4978214393] (review, CHANGES_REQUESTED, triage stage 1a, 2026-08-20T01:26:59Z): the PR body uses freeform headings (## Why, ## What this proposes, ## Notes) instead of the repository PR template headings (## What this PR does, ## Why it's needed, ## Reviewer Test Plan, ## Risk & Scope, and ## Linked Issues).

Disposition: real and left open — actionable only by the PR author or a maintainer on GitHub, not by this agent.

  • The requested fix is an edit of the PR body, which is GitHub PR metadata: no change inside this checkout can express it, and the triage gate raised no content objection to the PR's actual diff (one design doc, docs/design/autofix-gate-runner-isolation.md, +249 lines).
  • This agent holds no GitHub credentials, and this flow's mutation channels are limited to pushing commits and posting comments — there is no PR-body edit path (verified against the workflow: the address-review flow has no pr-title.txt/pr-body.md output channel and performs no gh pr edit). The review itself addresses the request to the PR author.
  • The same item was already escalated in round 1 (run 32355912104, handoff comment posted 2026-08-20 10:09 UTC) with the full mechanical recipe; the feedback set prepared for this round shows no author/maintainer action or triage re-run since then, so there is nothing new to evaluate.

No code changes were made and nothing was committed. No repository-defined verification command was run this round because nothing in the repository changed; per the workflow-prepared check data, all CI checks on the current head (35cfd3eb06) are green, so there is also no failing check to repair.

What unblocks this PR (per the triage review — a heading remap; the substance is already all there): the PR author or a maintainer edits the PR body so that "What this proposes" → ## What this PR does, "Why" → ## Why it's needed, "Notes" → ## Risk & Scope, adds a docs-applicable ## Reviewer Test Plan (How to verify: review the design against #9089 / #9524; Evidence and Tested on: N/A), lifts "Refs #9089, #9524. Supersedes the approach in #9214" into ## Linked Issues, and then re-runs @qwen-code /triage to continue to content review.

中文说明

本轮分诊的反馈 —— 共 1 条,其中 0 条可通过代码改动解决。

[rv:4978214393](评审,CHANGES_REQUESTED,triage 第 1a 阶段,2026-08-20T01:26:59Z):PR 正文使用自由标题(## Why## What this proposes## Notes),而非仓库 PR 模板要求的标题(## What this PR does## Why it's needed## Reviewer Test Plan## Risk & Scope## Linked Issues)。

处置:真实且保持未解决 —— 只能由 PR 作者或维护者在 GitHub 上处理,本 agent 无法执行。

  • 所请求的修复是编辑 PR 正文,即 GitHub 的 PR 元数据:当前检出(checkout)内的任何改动都无法表达它;triage 门槛对 PR 的实际 diff(一份设计文档 docs/design/autofix-gate-runner-isolation.md,+249 行)也没有提出任何内容异议。
  • 本 agent 不持有任何 GitHub 凭据,且本流程的写入通道仅限于推送提交和发表评论 —— 不存在编辑 PR 正文的通道(已对照工作流核实:address-review 流程没有 pr-title.txt/pr-body.md 输出通道,也不执行任何 gh pr edit)。该评审本身也是向 PR 作者提出这一请求的。
  • 同一事项已在第 1 轮升级移交(run 32355912104,移交评论发布于 2026-08-20 10:09 UTC),并附有完整的机械操作步骤;为本轮准备的反馈集显示,此后没有任何作者/维护者操作或 triage 重跑,因此没有新的内容需要评估。

本轮未做任何代码改动,也没有提交任何内容。由于仓库内没有任何变更,本轮未运行仓库定义的任何验证命令;根据工作流准备的检查数据,当前 head(35cfd3eb06)上的所有 CI 检查均为绿色,因此也不存在需要修复的失败检查。

解除本 PR 阻塞的操作(按 triage 评审所述 —— 标题重映射;内容已齐备):由 PR 作者或维护者编辑 PR 正文,将 "What this proposes" → ## What this PR does、"Why" → ## Why it's needed、"Notes" → ## Risk & Scope,新增适用于文档类 PR 的 ## Reviewer Test Plan(How to verify:对照 #9089 / #9524 审阅设计;Evidence 与 Tested on:N/A),把 "Refs #9089, #9524. Supersedes the approach in #9214" 提升到 ## Linked Issues,然后重新运行 @qwen-code /triage 进入内容审查。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@wenshao
wenshao enabled auto-merge August 21, 2026 02:00
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ⚠️ not run — n/a - workflow run

This PR changes documentation/assets only — there is no code to execute, so a sandboxed verification has nothing to verify.

中文 — 判定:⚠️ 未运行 · 不适用

该 PR 仅改动文档/静态资源,没有可执行的代码,沙箱验证没有验证对象。

Qwen Code · sandboxed verification

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot has neither a verdict nor a deferral on 35cfd3eb069eebfb25a7f92a2640320c39bd5006 — no APPROVED, CHANGES_REQUESTED, or COMMENTED review of its own. A DISMISSED one does not count: dismiss_stale_reviews voids the bot's approval on every push, which is exactly when a fresh one is needed. If this re-run was meant to review or approve, it did not, and an approval left by another account is a separate vote that does not count as the bot's own.

⚠️ 机器人在 35cfd3eb069eebfb25a7f92a2640320c39bd5006既没有裁决也没有 defer —— 没有属于它自己的 APPROVEDCHANGES_REQUESTEDCOMMENTED 评审。DISMISSED 不算:dismiss_stale_reviews 会在每次推送时作废机器人的批准,而那恰恰是需要一次新批准的时刻。如果这次重跑本应评审或批准,那么它没有做到;而其他账号留下的批准是另一张票,不能算作机器人自己的。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

🤖 Reviewed the latest feedback — no changes needed.

Feedback triaged this round:

  • [ic:5364281289] (@qwen-code-ci-bot, sandboxed verification report): informational status only — it reports that sandboxed verification was not run because this PR changes documentation/assets only, so there is no code to execute. It is not a finding or a change request, so no action is required.

Why nothing else:

  • No new reviews or inline comments since the last evaluation (2026-08-20T01:26:59Z).
  • No failed or still-red CI checks (all check runs are SUCCESS or SKIPPED).
  • Diff growth this window: 0 source / 0 test net lines (budgets 400/400).
  • The PR remains a documentation-only change: it adds docs/design/autofix-gate-runner-isolation.md (+249 lines), so no build/typecheck/lint/test verification applies and no commit was made this round.
中文说明

🤖 已审阅最新反馈——无需改动。

本轮分诊的反馈:

  • [ic:5364281289]@qwen-code-ci-bot,沙箱验证报告):仅为状态通报——说明由于本 PR 只改动文档/静态资源、没有可执行代码,沙箱验证未运行。这不是问题发现,也不是改动请求,无需处理。

其余说明:

  • 自上次评估(2026-08-20T01:26:59Z)以来没有新的 review 或行内评论。
  • 没有失败或持续失败的 CI 检查(所有检查项均为 SUCCESS 或 SKIPPED)。
  • 本窗口 diff 增长:源码净增 0 行 / 测试净增 0 行(预算 400/400)。
  • PR 保持为纯文档改动:新增 docs/design/autofix-gate-runner-isolation.md(+249 行),因此不涉及 build/typecheck/lint/测试验证,本轮也未产生提交。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ⚠️ not run — n/a - workflow run

This PR changes documentation/assets only — there is no code to execute, so a sandboxed verification has nothing to verify.

中文 — 判定:⚠️ 未运行 · 不适用

该 PR 仅改动文档/静态资源,没有可执行的代码,沙箱验证没有验证对象。

Qwen Code · sandboxed verification

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot has neither a verdict nor a deferral on 35cfd3eb069eebfb25a7f92a2640320c39bd5006 — no APPROVED, CHANGES_REQUESTED, or COMMENTED review of its own. A DISMISSED one does not count: dismiss_stale_reviews voids the bot's approval on every push, which is exactly when a fresh one is needed. If this re-run was meant to review or approve, it did not, and an approval left by another account is a separate vote that does not count as the bot's own.

⚠️ 机器人在 35cfd3eb069eebfb25a7f92a2640320c39bd5006既没有裁决也没有 defer —— 没有属于它自己的 APPROVEDCHANGES_REQUESTEDCOMMENTED 评审。DISMISSED 不算:dismiss_stale_reviews 会在每次推送时作废机器人的批准,而那恰恰是需要一次新批准的时刻。如果这次重跑本应评审或批准,那么它没有做到;而其他账号留下的批准是另一张票,不能算作机器人自己的。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

No action this round (PR #9525)

Feedback triage

The prepared feedback list contains a single item newer than the last
evaluation (2026-08-21T02:01:34Z): issue-level comment ic:5364517741 from
the automated CI bot (@qwen-code-ci-bot). It is a status notification,
not a defect claim or a change request
: the sandboxed verification job
reported "⚠️ not run — n/a" because this PR changes documentation/assets
only, so there is no code to execute and nothing for the sandbox to verify.

  • No review bodies were filed this window (the one CHANGES_REQUESTED review
    on the PR predates the cutoff and was already evaluated in the prior round).
  • No inline review comments exist.
  • No failed or still-red checks are listed.
  • Diff growth this window: 0 source / 0 test net lines against the 400/400
    budgets — nothing to rein in.

A cross-check of the raw comment feed found no filtered-out actionable item:
the only maintainer activity after the cutoff is @qwen-code /triage, which
invokes the triage bot rather than making a claim about this PR's content
(the bot has already responded to it); the remaining post-cutoff comments are
the workflow's own informational status notes and the prior round's no-action
summary.

Decision

No code or documentation change is warranted. The PR (a single new design doc
under docs/design/, +249 lines) is unchanged this round; no commit was made
and the working tree is clean. No reply is due on any comment — none of them
raises a finding.

中文说明

本轮无需处理(PR #9525

反馈分类

准备好的反馈列表中,自上次评估(2026-08-21T02:01:34Z)之后只有一条内容:
自动化 CI 机器人(@qwen-code-ci-bot)的 issue 级评论 ic:5364517741。这是一条状态通知,而非缺陷报告或修改请求:沙箱验证任务报告
⚠️ 未运行 — 不适用”,因为本 PR 仅改动文档/静态资源,没有可执行的代码,沙箱中没有可验证的内容。

  • 本窗口没有提交任何 review 正文(PR 上唯一一条 CHANGES_REQUESTED
    review 早于截止时间,已在上一轮评估过)。
  • 没有任何行内 review 评论。
  • 没有失败或持续失败的检查项。
  • 本窗口 diff 增长:相对 400/400 的预算,源码净增 0 行 / 测试净增 0 行 ——
    无需收敛。

对原始评论数据做了交叉核对,确认没有被过滤掉的可处理项:截止时间之后唯一的维护者活动是一条 @qwen-code /triage
命令,它调用的是 triage 机器人而非对本 PR 内容提出意见(机器人已作出回应);其余截止时间之后的评论均为工作流自身的状态通报和上一轮的无需处理总结。

决定

没有需要修改代码或文档的理由。本 PR(仅在 docs/design/ 下新增一份设计文档,+249 行)本轮保持不变;未创建任何提交,工作区干净。无需回复任何评论——它们均未提出发现。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ⚠️ not run — n/a - workflow run

This PR changes documentation/assets only — there is no code to execute, so a sandboxed verification has nothing to verify.

中文 — 判定:⚠️ 未运行 · 不适用

该 PR 仅改动文档/静态资源,没有可执行的代码,沙箱验证没有验证对象。

Qwen Code · sandboxed verification

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot has neither a verdict nor a deferral on 35cfd3eb069eebfb25a7f92a2640320c39bd5006 — no APPROVED, CHANGES_REQUESTED, or COMMENTED review of its own. A DISMISSED one does not count: dismiss_stale_reviews voids the bot's approval on every push, which is exactly when a fresh one is needed. If this re-run was meant to review or approve, it did not, and an approval left by another account is a separate vote that does not count as the bot's own.

⚠️ 机器人在 35cfd3eb069eebfb25a7f92a2640320c39bd5006既没有裁决也没有 defer —— 没有属于它自己的 APPROVEDCHANGES_REQUESTEDCOMMENTED 评审。DISMISSED 不算:dismiss_stale_reviews 会在每次推送时作废机器人的批准,而那恰恰是需要一次新批准的时刻。如果这次重跑本应评审或批准,那么它没有做到;而其他账号留下的批准是另一张票,不能算作机器人自己的。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

Autofix review round: no action needed

Triage of feedback newer than the last evaluation (2026-08-21T02:38:27Z) found nothing actionable this round:

  • Issue-level comment [ic:5365072443] (automated sandboxed-verification status): this is an informational report only — it states that sandboxed verification was not run — n/a because PR docs(autofix): design runner-level isolation for PAT-bearing steps #9525 changes documentation/assets only (one new design doc under docs/design/), so there is no code to execute. It contains no finding and no change request; no response or code change is required.
  • Reviews: none newer than the last evaluation.
  • Inline comments: none.
  • Failed / still-red checks: none — all required checks are green (the rest are expected skips for a docs-only change).

No commits were made this round; the PR head is unchanged.

中文说明

Autofix 审查轮次:无需处理

对上次评估(2026-08-21T02:38:27Z)之后的新反馈进行分类后,本轮没有可处理的事项:

  • Issue 级评论 [ic:5365072443](自动沙箱验证状态):这只是一条信息性报告 —— 它说明沙箱验证未运行 —— 不适用,因为 PR docs(autofix): design runner-level isolation for PAT-bearing steps #9525 仅改动文档/静态资源(docs/design/ 下新增一篇设计文档),没有可执行的代码。该评论不包含任何问题发现,也没有提出修改请求;无需回复或改动代码。
  • 审查(Reviews):上次评估之后没有新的审查。
  • 行内评论(Inline comments):无。
  • 失败 / 持续红色的检查:无 —— 所有必需检查均为绿色(其余为仅文档改动的预期跳过项)。

本轮未提交任何 commit;PR 的 head 保持不变。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the design doc at HEAD 35cfd3eb. On content, this is a strong design and I'm approving it — with one non-content gate item noted below.

Content — LGTM. The doc is well-reasoned and honest:

  • The #9214 post-mortem earns its conclusions rather than asserting them: non-convergence (329→2,700 lines, Critical count 8→9→15→19→29, rounds 10–11 changing no code yet still generating findings) and, decisively, R11-8 — the gate's root of trust (steps.stage.outputs.* parsed at step end from attacker-writable $RUNNER_TEMP) sits outside any container you could wrap the executor in. That correctly kills the in-step approach.
  • The core principle — a job that ran branch code must neither hold the PAT nor influence the inputs of the job that does — is the right boundary, and moving it between jobs (execute → artifact → publish) is sound: $GITHUB_ENV/$GITHUB_OUTPUT/$RUNNER_TEMP/live processes don't cross a job boundary.
  • Section B is the load-bearing insight and it's handled honestly: the execute job is assumed compromised, so its verdict is untrusted by construction and no signature fixes that — the publish job re-derives from checks that need no branch execution (patch applies to recorded base, footprint allowlist, workflow/lockfile refusal, growth budget, Conventional Commit, --force-with-lease), with build/test explicitly downgraded to advisory. The doc states that "verified" genuinely weakens, rather than hiding it.
  • Section E (delete what A–D make redundant) is the right instinct — a guard kept "just in case" is exactly what regenerated #9214's findings. The phased rollout (kill switch → move publish to hosted → cgroup lineage kill → ephemeral registration → delete machinery) sequences the highest-value, lowest-infra parts first, and the open questions (org --ephemeral policy, hosted-runner egress for the PAT job, issue-autofix's differing publish-side checks) are the right ones to leave open.

Two small content notes, neither blocking:

  • The publish-side footprint/growth checks (B2, B4) are the same class this pipeline has struggled to make forgery-proof elsewhere; worth stating in the eventual implementation that they run only on the patch text on the trusted side, never re-reading a value the execute job wrote.
  • issue-autofix is correctly flagged as out of scope here — just make sure the follow-up lands before E deletes shared machinery it still relies on.

Gate item (non-content): the automated triage still has CHANGES_REQUESTED open only because the PR body uses freeform headings (## Why / ## What this proposes / ## Notes) instead of the template's (## What this PR does, ## Why it's needed, ## Reviewer Test Plan, ## Risk & Scope, ## Linked Issues). The substance is all present — it's a heading remap. Restructuring the body and re-running @qwen-code /triage should clear that gate; my content approval above stands independently of it.

@wenshao
wenshao added this pull request to the merge queue Aug 21, 2026
Merged via the queue into main with commit 7142a4f Aug 21, 2026
59 checks passed
@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks — both content notes are now in the doc (68135b7521), because both are things an implementer could get wrong from the text as it stood:

  • Patch-text only. Section B now says explicitly that every re-derived check is computed from the patch text on the trusted side, and may never re-read a value the execute job wrote — not a line count it reported, not a footprint list it declared, not a base SHA it echoed back — with the note that shortcutting to "read the count the gate already computed" reintroduces R11-8. You are right that this is the class that has repeatedly failed here; what makes it sound in this position is only that the input is a file the publish job parses itself, so that had to be stated rather than implied.
  • issue-autofix sequencing. Recorded as a constraint rather than a note: the follow-up must land before the deletion pass removes machinery issue-autofix still relies on, which is why that pass is per cluster.

Also cross-referenced #9556 in the header — it is the same question on the review side, and anyone picking up either should see the other.

The gate item is fixed too: the body is now on the template headings, with a docs-applicable Reviewer Test Plan and the refs lifted into Linked Issues. Re-running triage next.

@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

Correction to my reply above: this PR merged (7142a4fd93) before that push landed, so 68135b7521 is not in main and the merged doc does not contain those two additions. They are now in #9652 instead, against main:

Sorry for the noise — the claim was accurate about the branch and wrong about main.

pull Bot pushed a commit to Stars1233/qwen-code that referenced this pull request Aug 21, 2026
…9652)

Review feedback on QwenLM#9525 arrived after that PR was merged, so the notes it
raised never made it into the doc. Both are things an implementer could
get wrong from the text as it stands.

Say what makes the re-derived checks sound in their new position: they are
computed from the patch text on the trusted side and may never re-read a
value the execute job wrote — not a line count it reported, not a
footprint list it declared, not a base SHA it echoed back. This is the
check class that has repeatedly failed to be forgery-proof here, and an
implementation that shortcuts to reading the count the gate already
computed reintroduces exactly that.

Record the sequencing constraint as a constraint: the issue-autofix
follow-up has to land before the deletion pass removes machinery it still
relies on, which is why that pass is per cluster.

Cross-reference QwenLM#9556, which asks the same question on the review side.

Refs QwenLM#9089, QwenLM#9525.
wenshao added a commit that referenced this pull request Aug 22, 2026
… staged file

The extraction put the body in a file and then had to defend that file: a
staged copy under RUNNER_TEMP, a digest recorded in step output, a type
check, bounded reads, and — after three rounds of findings against those —
an env -i clean child with a liveness sentinel and a 38-entry pass-through
list wrapping the whole verify-and-run sequence. Four review rounds have
now been spent on that machinery, and the open findings against it are
about the machinery, not about the move: output buffering that costs the
live log the inline body had, an env allow-list nothing pins, and pin gaps
in the tests that exist only to hold the gate together.

Delete the object being guarded instead. The stage step already reads the
trusted base before any branch code runs, so it captures the body as text
into step output and the step runs those bytes — the delivery the inline
block had, and the one upsert-deferred-issue.sh already uses. With no
agent-writable copy on disk there is nothing to stage, digest, type-check
or re-open, and no check→use window between the steps: R1-2's TOCTOU,
R1-13's FIFO double-open, R2-2/R2-5/R2-6/R2-7's single-open pins and
R4-1's buffering all describe a mechanism that no longer exists.

This is not a security regression. What it drops is protection the inline
block never had; what it keeps is the one property that matters — the
bytes come from the trusted-base checkout through expression context, not
from a path the branch can write. The step shell's inherited environment
(R1-1, R1-3) is the status quo this PR preserves rather than the thing an
extraction should be fixing: #9525's publish job takes the PAT out of that
shell entirely, which is the real close.

Kept from the gate work: the round_reported output. A loader plant that
kills this shell at execve exits 0 having written nothing, so 'Finalize
autofix status comment' can still tell a published round from a no-op —
now without a sentinel, because the write is simply last.

Also corrected, from the same review: the header no longer claims the
block was the largest in the file (it is third, after 'Scan for PRs with
new feedback' and 'Prepare branch and feedback'), the size is measured at
this branch's merge-base (462,720), the env contract is stated as a rule
rather than a list that went stale within one round, and the shellcheck
note says which lane and which severity it is clean under. The R10-8
execution-ban negatives now cover the scripts as well as the workflow, and
the script's own flag line is pinned as a whole rather than by spelling.

Refs #9089, #9525.
qwen-code-dev-bot added a commit to wenshao/qwen-code that referenced this pull request Aug 22, 2026
…file (QwenLM#9653)

* refactor(autofix): move the push-and-report body out of the workflow file

qwen-autofix.yml was 462,656 bytes — 90% of GitHub's 500 KB start-runs
limit and inside the 470,000-byte gate's warning band. Past that limit
GitHub stops starting runs and says nothing: schedule ticks vanish,
dispatches sit queued with zero jobs, and only PR-event runs keep working
because they resolve an older copy from the PR's branch. The file crossed
it once already, on 2026-08-19, and the loop went dark for a day.

'Push and report' was the largest single block in the file at 626 lines of
inline shell. Its body moves to .github/scripts/autofix-push-and-report.sh
byte-identically — the YAML keeps the step's if: and env:, which is where
the questions of when it runs and what reaches it belong. The file drops
to 422,447 bytes.

Extraction moves the trust problem with it. By the time this step runs the
agent and the verification gate have executed branch code on this host, so
the workspace copy is branch-controlled. The step runs the trusted-base
copy staged before any of that, after proving its digest — recorded in
GITHUB_OUTPUT, which a disk write cannot reach — still matches, that the
staged path is a regular file, and with both reads bounded so a planted
FIFO is a refusal rather than a hang until timeout-minutes. A new contract
test pins all of that, including that the workspace copy is never what
runs; each of its assertions was checked against a mutant of the line it
guards.

The census assertions that counted sites across the workflow now count the
script too, so an extraction cannot silently drop a site from a count that
exists to pin it. The two emit_growth_audit_marker copies are compared
dedented, since one is now at column 0 and its twin is still at ten.

This is also the step docs/design/autofix-gate-runner-isolation.md moves
into its own publish job. Carrying it as a file makes that a small diff,
and deletes the staging scaffolding added here: a job that checks out the
trusted base and never executes branch code can run the script where it
lies.

Refs QwenLM#9089.

* fix(autofix): close the push-and-report gate's env-import and TOCTOU holes

The wrapper verified the staged script in the step's inherited shell:
a $GITHUB_ENV-planted PATH or BASH_FUNC_* import could swap the gate's
own words, and the staged path was opened three times, so a watcher
could swap the file between the digest check and the execution read.
Run the whole verify-and-run sequence in one env -i clean child that
opens the staged path once, verifies the digest of the captured bytes,
and executes those same bytes. Also fail staging closed on any cp
failure, fix the script's env contract, and pin the new guards.

* fix(autofix): close the push-and-report gate's silent no-op hole

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(autofix): pin gate pass-through, refusal order, and continuation bans (QwenLM#9653)

Address review suggestions on the push-and-report extraction:

- R2-3: pin the gate child's env -i pass-through list as a sorted
  allow-list equality check (R9-10 precedent), so a dropped variable
  fails loudly instead of expanding empty.
- R4-4: pin the sentinel refusal BEFORE the round_reported write —
  shape-only pins let the ordering rot (probe-verified mutant).
- R4-6: make the execution bans continuation-tolerant; bash joins
  `\<newline>` before tokenizing, so line-continued spellings evaded
  the `[^\n|]*` middle (probe: old regex misses, new catches).
- R1-6: re-scope the paired R10-8 upsert negatives to both halves,
  matching the positive censuses.
- R3-2: correct the stale workflow-size figure (462,656 -> 463,004
  bytes at the post-merge base; 90%/98% still hold).
- R1-5/R1-15/R1-11: correct three disproved claims in the trust-model
  doc (block rank, GITHUB_OUTPUT qualifier, which call sites hold the
  single-open shape).

* refactor(autofix): deliver the push-and-report body as content, not a staged file

The extraction put the body in a file and then had to defend that file: a
staged copy under RUNNER_TEMP, a digest recorded in step output, a type
check, bounded reads, and — after three rounds of findings against those —
an env -i clean child with a liveness sentinel and a 38-entry pass-through
list wrapping the whole verify-and-run sequence. Four review rounds have
now been spent on that machinery, and the open findings against it are
about the machinery, not about the move: output buffering that costs the
live log the inline body had, an env allow-list nothing pins, and pin gaps
in the tests that exist only to hold the gate together.

Delete the object being guarded instead. The stage step already reads the
trusted base before any branch code runs, so it captures the body as text
into step output and the step runs those bytes — the delivery the inline
block had, and the one upsert-deferred-issue.sh already uses. With no
agent-writable copy on disk there is nothing to stage, digest, type-check
or re-open, and no check→use window between the steps: R1-2's TOCTOU,
R1-13's FIFO double-open, R2-2/R2-5/R2-6/R2-7's single-open pins and
R4-1's buffering all describe a mechanism that no longer exists.

This is not a security regression. What it drops is protection the inline
block never had; what it keeps is the one property that matters — the
bytes come from the trusted-base checkout through expression context, not
from a path the branch can write. The step shell's inherited environment
(R1-1, R1-3) is the status quo this PR preserves rather than the thing an
extraction should be fixing: QwenLM#9525's publish job takes the PAT out of that
shell entirely, which is the real close.

Kept from the gate work: the round_reported output. A loader plant that
kills this shell at execve exits 0 having written nothing, so 'Finalize
autofix status comment' can still tell a published round from a no-op —
now without a sentinel, because the write is simply last.

Also corrected, from the same review: the header no longer claims the
block was the largest in the file (it is third, after 'Scan for PRs with
new feedback' and 'Prepare branch and feedback'), the size is measured at
this branch's merge-base (462,720), the env contract is stated as a rule
rather than a list that went stale within one round, and the shellcheck
note says which lane and which severity it is clean under. The R10-8
execution-ban negatives now cover the scripts as well as the workflow, and
the script's own flag line is pinned as a whole rather than by spelling.

Refs QwenLM#9089, QwenLM#9525.

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.22.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+) review/self-reported The linked issue was opened by the PR author (self-reported)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

autofix: PAT-bearing jobs share a host with untrusted branch code — needs runner-level isolation

5 participants