Skip to content

refactor(ci): simplify the review checkout self-heal back to wipe-and-retry - #9327

Merged
wenshao merged 10 commits into
QwenLM:mainfrom
wenshao:refactor/review-checkout-heal
Aug 19, 2026
Merged

refactor(ci): simplify the review checkout self-heal back to wipe-and-retry#9327
wenshao merged 10 commits into
QwenLM:mainfrom
wenshao:refactor/review-checkout-heal

Conversation

@wenshao

@wenshao wenshao commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Shrinks the checkout self-heal added in #9220 back to its load-bearing core. Eight review rounds grew the heal step from about 15 lines into about 60 lines of path-guard layers — realpath canonicalization, two trailing-slash strip loops, a denylist, and a runner-workspace allowlist — plus roughly 450 lines of tests pinning their mutation resistance. This PR removes all of those guard layers and their tests, keeping the wipe-and-retry core: net −294 lines. What survives is still pinned by tests: the pool wipe idiom (including hidden entries), the sudo fallback leg with its exact argv, the never-fail exit contract with survivors named in the warning, the identical retry checkout, and the continue-on-error invariants on all three steps.

Why it's needed

The heal exists for two observed, realistic failure shapes: a corrupt persisted workspace (seven review jobs dead on the same missing SHAs on one runner, 2026-08-13..15) and a transient fetch drop. Both are still fully covered. Everything removed defended against a different shape — a mangled workspace path handed to the wipe. That variable is set by actions/runner itself; the only actors that could mangle it are a compromised runner or a workflow step overriding it, and both already execute arbitrary code on the machine and need no wipe to do damage. A guard inside a script cannot defend against the actor that controls the script's host, so the removed layers carried maintenance and portability cost (a GNU-only realpath flag, a BSD fallback, a host-probe test axis) while defending against nothing realistic. The one guard that does earn its place — failing loud when the variable is dropped entirely — stays, and stays tested.

Reviewer Test Plan

How to verify

The happy path is byte-identical in effect: a failed first checkout still wipes the workspace contents (directory kept), still escalates to passwordless sudo where available, still warns which shape happened, still names any survivors, and still retries the identical checkout. Run the workflow test suite: the checkout self-heal block is now 7 tests (was 13) and all pass; the suite total goes 157 → 151. Three spot mutants were verified red on this branch: deleting the sudo fallback leg, dropping the :? guard, and adding continue-on-error to the wipe step each fail the corresponding test. The pre-existing macOS failure in the #9255 fallback-comment block (repairs a single unwritable directory) is unchanged by this PR — it fails identically on untouched main.

Evidence (Before & After)

N/A — CI infrastructure change, no user-visible output. Before: a 60-line heal step with four guard layers and 19 tests, of which 12 existed to pin guard mutation resistance. After: a 22-line step and 7 behavior tests; the incident it was built for (corrupt workspace → wipe → clean retry) is exercised by the same real-script execution tests as before.

Tested on

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

Environment (optional)

Unit tests only (vitest executing the real wipe script under runner shell flags), plus the three mutation spot-checks above. Removing the GNU-only realpath line also removes the test axis that had to probe for it, so the suite is now host-independent.

Risk & Scope

  • Main risk or tradeoff: this deliberately reverts review feedback accepted in fix(ci): self-heal failed checkouts on the reused review runners #9220 (rounds R2–R8). The case for safety is the threat-model argument above — the removed layers' trigger requires an actor that the layers cannot stop. If the pool ever gains steps that can override the workspace path (none writes the runner env file today), a guard belongs back with that change.
  • Not validated / out of scope: the triage workflow keeps its own denylist copy, which lives in a different context (it handles untrusted PR code) and is untouched; consolidating the pool's wipe copies into one shared script remains a possible follow-up but is not this PR.
  • Breaking changes / migration notes: none.

Linked Issues

None — follow-up to #9220, observed via its review-loop history.

中文说明

这个 PR 做了什么

#9220 引入的 checkout 自愈步骤收缩回承重核心。经过 8 轮 review,这个自愈步骤从约 15 行膨胀到约 60 行路径守卫层——realpath 规范化、两条尾斜杠剥离循环、一个黑名单、一个 runner-workspace 白名单——外加约 450 行钉住它们变异抗性的测试。本 PR 删掉全部守卫层及其测试,保留 wipe-and-retry 核心:净 −294 行。留下来的行为仍被测试钉住:池 wipe 惯用法(含隐藏条目)、带精确 argv 断言的 sudo 兜底分支、命名残留项的永不失败退出契约、完全一致的 retry checkout、以及三个步骤上的 continue-on-error 不变式。

为什么需要

自愈机制面向两种观察到的真实失败形态:损坏的持久化 workspace(一台 runner 上连续 7 个 review job 死于同一批缺失 SHA,2026-08-13..15)和瞬时 fetch 中断。这两种形态仍然完整覆盖。被删除的部分防的是另一种形态——畸变的 workspace 路径被交给 wipe。这个变量由 actions/runner 自己设定;能畸变它的只有被入侵的 runner 或覆写它的 workflow 步骤,而这两者都已经在机器上拥有任意代码执行权,不需要 wipe 就能造成破坏。脚本内的守卫防不住控制脚本宿主的行为者,所以被删的层只带来维护和可移植性成本(GNU 专属的 realpath 标志、BSD 回退、host-probe 测试轴),却没有防御任何现实威胁。唯一值得保留的守卫——变量整个丢失时响亮失败——留下了,并且仍有测试。

Reviewer 测试计划

如何验证

正常路径的效果逐字节等价:第一次 checkout 失败后仍会清空 workspace 内容(保留目录本身)、仍在有免密 sudo 的机器上提权重试、仍会警告发生了哪种情况、仍会点名残留项、仍会用完全一致的参数重试 checkout。运行 workflow 测试套件:checkout self-heal 块现在是 7 个测试(原 13 个),全部通过;套件总数 157 → 151。本分支上验证过 3 个点状变异全部变红:删除 sudo 兜底分支、去掉 :? 守卫、给 wipe 步骤加 continue-on-error,各自对应的测试都会失败。#9255 fallback-comment 块里那个预存的 macOS 失败(repairs a single unwritable directory)与本 PR 无关——在未改动的 main 上同样失败。

Before / After 证据

N/A——CI 基础设施改动,无用户可见输出。Before:60 行自愈步骤、四层守卫、19 个测试,其中 12 个用于钉守卫的变异抗性。After:22 行步骤、7 个行为测试;它为之而生的事故场景(损坏 workspace → wipe → 干净重试)仍由同一套真实脚本执行测试覆盖。

测试平台

OS 状态
🍏 macOS
🪟 Windows N/A
🐧 Linux ⚠️

环境(可选)

仅单元测试(vitest 以 runner shell 标志执行真实 wipe 脚本),加上上述 3 个变异点检。删除 GNU 专属的 realpath 行也删掉了需要探测它的测试轴,套件从此与宿主无关。

风险与范围

  • 主要风险或取舍:本 PR 有意回退了 fix(ci): self-heal failed checkouts on the reused review runners #9220 review 中被接受的意见(R2–R8 轮)。安全性的论据是上面的威胁模型分析——被删层的触发条件需要一个这些层拦不住的行为者。如果未来池上出现能覆写 workspace 路径的步骤(今天没有任何步骤写 runner env 文件),守卫应该随那个改动一起加回来。
  • 未验证 / 不在范围内:triage workflow 保留自己的黑名单拷贝,它处于不同的上下文(处理不可信 PR 代码),本 PR 不动它;把池上各 wipe 拷贝合并成一个共享脚本可以作为后续工作,但不是本 PR 的内容。
  • 破坏性变更 / 迁移说明:无。

关联事项

无——#9220 的后续,源自其 review 循环历史的观察。

…-retry

QwenLM#9220 fixed a real incident (a corrupt persisted workspace made seven
review jobs fail checkout on the same missing SHAs), but eight review
rounds grew the heal step from ~15 lines into ~60 lines of path-guard
layers (realpath canonicalization, two trailing-slash strip loops, a
denylist case, a RUNNER_WORKSPACE allowlist) plus ~450 lines of tests
pinning their mutation resistance.

Every removed layer defended against a mangled GITHUB_WORKSPACE. That
variable is set by actions/runner; anything that could mangle it — a
compromised runner, a step writing GITHUB_ENV — already executes
arbitrary code on the machine and needs no wipe to do damage, so the
guard cannot defend against the only actor able to trigger it. The
realistic contract is the :? guard: fail loud on a dropped variable.

Kept and still pinned by tests: the pool wipe idiom, the sudo fallback
leg (exact argv), the never-fail exit contract with named survivors,
the identical retry checkout, and the continue-on-error invariants.
Also dropped with the guards: the GNU-only realpath flag and its
host-probe test machinery.
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 17, 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

Copy link
Copy Markdown
Collaborator

Thanks for the PR — a tightly scoped cleanup.

Template: all sections present ✓

Problem: real, though it's a complexity removal rather than a bug report. The guard layers removed here carry observable costs: a GNU-only realpath -m flag that forces a BSD fallback and a host-probe test axis, plus a large block of tests pinning their mutation resistance. The threat they defend against — a mangled GITHUB_WORKSPACE handed to the wipe — requires an actor (compromised runner, or a workflow step overriding the variable) that already executes arbitrary code on the machine. The "guard inside a script can't defend against the actor that controls the script's host" analysis reads as correct, not speculative.

Direction: aligned — simplicity-first, and this shrinks the heal step from ~60 lines to ~22. One flag up front: this deliberately reverts feedback accepted in the #9220 review rounds (R2–R8), so the owner of that decision should confirm the reversal — that lands in a maintainer's lap at the end of this review regardless (see the guardrail note in my final comment).

Size: no core package paths touched — 51 production lines (.github/workflows/qwen-code-pr-review.yml, +10/−41), 289 test lines (+13/−276). Net −294.

Approach: the scope is right — every edit either removes a guard layer or a test that pins one; no drive-by changes. What survives (the :? unset-variable guard, wipe + sudo leg, never-fail exit contract, survivors warning, identical retry checkout, continue-on-error invariants) matches what I would have kept independently.

Risk: no high-risk path signals.

Moving on to code review. 🔍

中文说明

感谢贡献——这是一个范围收得很干净的清理 PR。

模板:各节齐全 ✓

问题:真实存在,虽然这是复杂度移除而不是 bug 修复。被删除的守卫层有可观测的成本:GNU 专属的 realpath -m 标志迫使引入 BSD 回退和 host-probe 测试轴,外加一大块钉住它们变异抗性的测试。它们防御的威胁——畸变的 GITHUB_WORKSPACE 被交给 wipe——需要一个已经能在机器上执行任意代码的行为者(被入侵的 runner,或覆写该变量的 workflow 步骤)。"脚本内的守卫防不住控制脚本宿主的行为者"这个分析是成立的,不是臆测。

方向:对齐——simplicity-first,把自愈步骤从约 60 行收缩到约 22 行。先提一个注意点:本 PR 有意回退了 #9220 review 轮次(R2–R8)中被接受的意见,那个决定的 owner 应该确认这次反转——无论如何,review 结束时都会按守卫规则交到 maintainer 手里(见最终评论里的说明)。

规模:未触及核心包路径——生产代码 51 行(.github/workflows/qwen-code-pr-review.yml,+10/−41),测试 289 行(+13/−276)。净 −294。

方案:范围合理——每处改动要么删除守卫层,要么删除钉住守卫层的测试,没有顺手改动。保留下来的部分(:? 变量缺失守卫、wipe + sudo 兜底、永不失败的退出契约、残留项警告、完全一致的 retry checkout、continue-on-error 不变式)与我独立判断会保留的内容一致。

风险:无高风险路径信号。

进入代码审查。🔍

Qwen Code · qwen3.8-max

Reviewed at 42baa9a9061573554d655ed157606ff17f6c8c06 · re-run with @qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

I wrote my independent baseline before opening the diff: keep the :? unset-variable guard, the find-based wipe with its sudo leg, the never-fail contract, and the survivors warning; drop the canonicalization, trailing-slash loops, denylist, and runner-workspace allowlist. The PR does exactly that — I found no simpler surviving shape it missed.

Things I verified while reading:

  • No dangling RUNNER_WORKSPACE usage — the only reference in the workflow was inside the removed script body.
  • The removed spawnSync / realpathSync imports have no remaining users in the test file.
  • The survivors-warning reword is mirrored in the updated assertion; the new non-empty-string check is equivalent to the old count check (tr output is non-empty iff entries survived), and entries are still named for oncall — only the numeric count left the message.
  • qwen-triage.yml keeps its own two denylist copies untouched, as the description says. Right call: that workflow executes untrusted PR code, which is a different threat context from this one (the heal runs on a failed base-branch checkout, before any PR code exists).
  • Test arithmetic checks out: six guard tests removed, heal block 13 → 7.

No correctness, security, or convention findings. What survives is still pinned by tests that execute the real script: the pool wipe idiom (hidden entries included), the sudo leg with its exact argv, the never-fail exit, the identical retry checkout, and the continue-on-error invariants on all three steps. The author additionally reports three mutation spot-checks red on this branch (sudo leg deleted, :? dropped, continue-on-error added to the wipe) — that's the author's own run, but the surviving assertions visibly exercise the real script and would fail on those mutations.

Testing — the PR's own CI, via API

This triage run does not execute PR code (gate rule); the evidence below is the PR's own CI on 42baa9a9. The lane that matters here is Test (ubuntu-latest, Node 22.x) — it runs the workflow test suite against the real YAML — and it was still in progress at this pass. Everything completed so far is green; the macOS/Windows unit lanes and the integration lane are skipped for this change. No failures at time of writing. The finalize job will refresh the table below once CI settles.

Final CI results for 42baa9a (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Classify PR ✅ success
Dependency CVE audit ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
route ✅ success
Secret scan (TruffleHog) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

The author also notes a pre-existing macOS-lane failure in the #9255 fallback-comment block (repairs a single unwritable directory) that fails identically on untouched main. This commit's macOS lane is skipped, so that claim is not observable from this run's CI — recorded as the author's statement, not as verified evidence.

No sandboxed-verification trigger this time, deliberately: the surviving behavior is pinned by real-script-execution tests that CI runs, so there is no behavioural claim left for /verify to settle. What remains open is the threat-model judgement — whether the removed layers were defending against nothing realistic — and that is a maintainer's call, not a testable claim. Real-scenario testing: N/A (CI infrastructure, nothing user-visible).

中文说明

代码审查:我在打开 diff 之前先写下了自己的独立方案——保留 :? 变量缺失守卫、带 sudo 兜底的 find wipe、永不失败契约、残留项警告;删掉规范化、尾斜杠循环、黑名单和 runner-workspace 白名单。PR 的做法与此完全一致,我没有找到更简单的保留形态。

核对过的点:workflow 中 RUNNER_WORKSPACE 没有其他残留引用;被删的两个 import(spawnSync / realpathSync)在测试文件中没有其他使用者;残留项警告的措辞变更与更新后的断言一致,非空字符串判断与原先的计数判断等价,条目仍会被点名,只是消息里不再带数字;qwen-triage.yml 如描述所述保留了自己的两份黑名单拷贝(那个 workflow 执行不可信 PR 代码,威胁上下文不同,保留是对的);测试数量核对无误:删除 6 个守卫测试,13 → 7。

没有正确性、安全性或规范问题。保留的行为仍由执行真实脚本的测试钉住。作者另报告了 3 个变异点检为红(这是作者自己的运行结果)——不过保留的断言确实执行真实脚本,这些变异理应失败。

测试:本次 triage 不执行 PR 代码(门禁规则),以上证据来自 PR 自己的 CI。关键泳道 Test (ubuntu-latest, Node 22.x)(对真实 YAML 运行 workflow 测试套件)在本次检查时仍在运行;已完成的全部为绿,macOS/Windows 单测泳道与集成泳道对本改动跳过。finalize 任务会在 CI 结束后更新上方表格。

作者还提到 #9255 fallback-comment 块中一个预存的 macOS 泳道失败,在未改动的 main 上同样失败——本 commit 的 macOS 泳道被跳过,无法从本次 CI 观测,仅作为作者陈述记录。

这次刻意没有给出沙箱验证触发语:保留的行为已由 CI 运行的真实脚本执行测试钉住,没有留给 /verify 的行为性问题;剩下的威胁模型判断是 maintainer 的决策,不是可测试的声明。真实场景测试:N/A(CI 基础设施,无用户可见面)。

Qwen Code · qwen3.8-max

Reviewed at 42baa9a9061573554d655ed157606ff17f6c8c06 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 3/5 — clean review, but this is a fork refactor that reverts feedback accepted in #9220, so the guardrail caps the score and hands the decision to a maintainer.

Stepping back: the threat-model argument is the whole PR, and it holds. GITHUB_WORKSPACE is set by actions/runner; the only actors who could mangle it — a compromised runner, or a workflow step overriding the variable — already execute arbitrary code on the machine and need no wipe to do damage. A guard inside a script cannot defend against the actor that controls the script's host. Meanwhile the removed layers carried real costs: a GNU-only flag, a BSD fallback, a host-probe test axis, and a large test block pinning mutation resistance against that unrealistic shape. What survives covers the two failure shapes actually observed (a corrupt persisted workspace; a transient fetch drop) and stays pinned by real-script-execution tests.

My independent proposal matched the PR's shape exactly; I found nothing simpler to keep and nothing removed that the observed failures need. The diff is minimal — every edit serves the stated goal. One line worth quoting when this lands: if the pool ever gains steps that can override the workspace path, a guard belongs back with that change.

Why not approving, despite the clean review:

  1. Approval guardrail (deterministic): cross-repository refactor PRs are never auto-approved — a human maintainer must sign off. No exception carved here.
  2. The PR reverts accepted review history: the removed layers were accepted across fix(ci): self-heal failed checkouts on the reused review runners #9220's R2–R8 rounds; reversing that decision deserves the decision owner's confirmation rather than a bot approval.
  3. CI on the decisive lane (Test (ubuntu-latest, Node 22.x)) was still running at review time — which alone would have deferred any approval.
中文说明

回顾整体:威胁模型论证是这个 PR 的全部依据,而且成立。GITHUB_WORKSPACE 由 actions/runner 设定;能畸变它的行为者——被入侵的 runner,或覆写变量的 workflow 步骤——已经能在机器上执行任意代码,不需要 wipe 就能造成破坏。脚本内的守卫防不住控制脚本宿主的行为者。而被删的层有真实成本:GNU 专属标志、BSD 回退、host-probe 测试轴,以及一大块为不现实的威胁形态钉变异抗性的测试。保留的部分覆盖了实际观测到的两种失败形态(损坏的持久化 workspace、瞬时 fetch 中断),且仍由真实脚本执行测试钉住。

我的独立方案与 PR 形态完全一致:没有更简单的保留形态,也没有删掉任何观测到的失败所需要的东西。diff 是最小的——每处改动都服务于既定目标。有一句话值得在这个 PR 落地时引用:如果未来池上出现能覆写 workspace 路径的步骤,守卫应随那个改动一起加回来。

为什么不批准(尽管 review 是干净的):

  1. 批准守卫(确定性规则):跨仓库 refactor PR 永不自动批准——必须由人类 maintainer 签署。此处不开例外。
  2. 本 PR 回退了已接受的 review 历史:被删的层是在 fix(ci): self-heal failed checkouts on the reused review runners #9220 的 R2–R8 轮中被接受的;反转那个决定应该由决定的 owner 确认,而不是由 bot 批准。
  3. 关键泳道(Test (ubuntu-latest, Node 22.x))在 review 时仍在运行——仅此一点也会推迟任何批准。

Qwen Code · qwen3.8-max

Reviewed at 42baa9a9061573554d655ed157606ff17f6c8c06 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

⏸️ Deferring to a maintainer for the final call on this one.

The review itself is clean (see the stage comments above): the threat-model case for dropping the path-guard layers holds, the surviving wipe-and-retry core stays pinned by real-script-execution tests, and the diff is minimal. Two reasons it still needs a human:

  1. Fork refactor approval guardrail — cross-repository refactor PRs always require maintainer sign-off here, by policy.
  2. The PR deliberately reverts feedback accepted in fix(ci): self-heal failed checkouts on the reused review runners #9220's review rounds (R2–R8), so the owner of that decision should confirm the reversal.

@wenshao — you own both sides of this one (author of this PR and of #9220): please approve as a committer if you stand by the reversal, or loop in another maintainer for an independent look. Needs a human call on this one.

中文说明

⏸️ 转交 maintainer 做最终决定。

审查本身是干净的(见上方各阶段评论):删除路径守卫层的威胁模型论证成立,保留的 wipe-and-retry 核心仍由真实脚本执行测试钉住,diff 也是最小化的。仍需要人类介入的两个原因:

  1. fork refactor 批准守卫——按策略,跨仓库 refactor PR 一律需要 maintainer 签署。
  2. 本 PR 有意回退了 fix(ci): self-heal failed checkouts on the reused review runners #9220 review 轮次(R2–R8)中被接受的意见,该决定的 owner 应确认这次反转。

@wenshao——这个 PR 的两边都是你(本 PR 与 #9220 的作者):如果确认这次反转,请以 committer 身份批准,或者拉另一位 maintainer 独立看一眼。这件事需要人来拍板。

Qwen Code · qwen3.8-max

@wenshao

wenshao commented Aug 17, 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 17, 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. This is a fork PR, so the first round comes from the next scheduled scan (usually within minutes). Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。本 PR 来自 fork,首轮处理将由下一次定时扫描执行(通常几分钟内)。移除 autofix/takeover 标签(或评论 @qwen-code /takeover stop)即可释放。

@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.

Reviewed — no blockers. Suggestions are inline.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查——无阻断问题。 建议见行内评论。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

— qwen3.8-max via Qwen Code /review (v0.21.13)

Comment thread scripts/tests/qwen-pr-review-workflow.test.js
@qwen-code-dev-bot

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

Copy link
Copy Markdown
Collaborator

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

中文说明

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

…rkspace wipe

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

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下:

Autofix review round summary — PR #9327

Feedback triage

  • [rc:3794801912]scripts/tests/qwen-pr-review-workflow.test.js:2621[Suggestion] The removal of the runner-workspace allowlist leaves a load-bearing safety premise pinned by no test: nothing ordered before the Reset workspace after failed checkout wipe may override GITHUB_WORKSPACE, or the unguarded find "$WS" … -exec rm -rf {} + deletes the overridden path with no remaining guard.
    • Classification: Optional (automated-reviewer Suggestion), round 1 — addressed per the early-round review policy.
    • Decision: Implemented.

Changes

Added one test, keeps GITHUB_WORKSPACE runner-owned before the wipe, to the existing checkout self-heal describe block in scripts/tests/qwen-pr-review-workflow.test.js (+17 lines, nothing else changed):

  • Asserts the workflow-level env: and the review-pr job-level env: do not define GITHUB_WORKSPACE (the suggested snippet covered step level; workflow/job-level env: entries reach the same pre-wipe steps, so they are the same override vector and are pinned too).
  • Asserts every step ordered before the wipe has no step-level env: GITHUB_WORKSPACE and no GITHUB_WORKSPACE= write in its run: block (the $GITHUB_ENV / export vectors).

The premise was verified to hold at the reviewed commit before editing: zero $GITHUB_ENV writes in the workflow; all pre-wipe GITHUB_WORKSPACE uses read-only; workflow-level env: defines only FALLBACK_MARKER; the only step-level env: block belongs to a different job.

Red probe (recorded): temporarily inserting a hypothetical override step before the wipe (env: GITHUB_WORKSPACE: /tmp/probe-ws plus a $GITHUB_ENV write) turned the new test red — AssertionError: expected '/tmp/probe-ws' to be undefined, Tests 1 failed | 151 passed (152) — matching the reviewer's witness. The probe step was then removed and the workflow file restored byte-identical from HEAD (git show HEAD:… > file); the commit contains only the test file.

No conflict resolution was needed (--conflict false).

Notes

  • Pre-existing failure observed on this runner, unrelated to this round: scripts/tests/verify-capture.test.js > renders 256-colour and truecolor via the default-grey fallback fails with expected false to be true while scanning rendered PNG pixels for #d4d4d4. The test file and the helper it exercises are byte-identical between origin/main and HEAD (git diff origin/main HEAD -- scripts/ shows neither), and this round's diff does not touch them, so the failure reproduces on base-branch code — it is environment-specific (pixel-exact rendering through sharp/librsvg/fonts), not caused by this change.
  • No settings source changed, so npm run generate:settings-schema was not applicable. No bundled-CLI behavior changed, so integration tests were not applicable.

Verification

  • npx vitest run --config ./scripts/tests/vitest.config.ts qwen-pr-review-workflow (baseline) — 151 passed
  • Red probe run with temporary override step — new test failed as expected: 1 failed | 151 passed (152), expected '/tmp/probe-ws' to be undefined; workflow restored from HEAD afterwards
  • npx vitest run --config ./scripts/tests/vitest.config.ts qwen-pr-review-workflow (with the new test, and again on the committed tree) — 152 passed
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js — passed
  • npm run test:scripts (full scripts suite) — 1310 passed, 16 skipped, 1 failed (the pre-existing, environment-specific verify-capture.test.js failure documented above)

Commit: 1d6e1369b3test(ci): pin the runner-owned GITHUB_WORKSPACE premise before the workspace wipe

中文说明

Autofix 审查轮次总结 — PR #9327

反馈分类

  • [rc:3794801912]scripts/tests/qwen-pr-review-workflow.test.js:2621[Suggestion] 移除 runner-workspace 白名单后,有一个承重安全前提没有任何测试钉住:排在 Reset workspace after failed checkout(wipe)步骤之前的任何步骤都不得覆写 GITHUB_WORKSPACE,否则未设防的 find "$WS" … -exec rm -rf {} + 会删除被覆写的路径,且不再有任何守卫。
    • 分类:Optional(自动审查器的 Suggestion),第 1 轮——按早期审查轮次策略予以处理。
    • 决定:已实现。

变更

scripts/tests/qwen-pr-review-workflow.test.js 现有的 checkout self-heal describe 块中新增一个测试 keeps GITHUB_WORKSPACE runner-owned before the wipe(+17 行,未改动其他任何内容):

  • 断言 workflow 级 env:review-pr job 级 env: 均未定义 GITHUB_WORKSPACE(建议的代码片段只覆盖了 step 级;workflow/job 级 env: 同样会作用于 wipe 之前的步骤,属于同一覆写向量,因此一并钉住)。
  • 断言 wipe 之前的每个步骤:step 级 env: 中没有 GITHUB_WORKSPACE,且其 run: 块中不含 GITHUB_WORKSPACE= 写入(即 $GITHUB_ENV / export 两种向量)。

编辑前已验证该前提在被审查 commit 上成立:整个 workflow 中 $GITHUB_ENV 写入为零;wipe 之前对 GITHUB_WORKSPACE 的使用全部是只读;workflow 级 env: 只定义了 FALLBACK_MARKER;唯一的 step 级 env: 块属于另一个 job。

红测 probe(已记录): 临时在 wipe 之前插入一个假想覆写步骤(env: GITHUB_WORKSPACE: /tmp/probe-ws 外加一次 $GITHUB_ENV 写入),新测试随即变红——AssertionError: expected '/tmp/probe-ws' to be undefinedTests 1 failed | 151 passed (152)——与审查器给出的见证一致。随后移除 probe 步骤,并将 workflow 文件从 HEAD 逐字节恢复(git show HEAD:… > file);提交中只包含测试文件。

无需解决冲突(--conflict false)。

说明

  • 本 runner 上观察到一个与本轮回无关的既有失败:scripts/tests/verify-capture.test.js > renders 256-colour and truecolor via the default-grey fallback,在扫描渲染出的 PNG 像素查找 #d4d4d4 时报 expected false to be true。该测试文件及其测试的 helper 在 origin/mainHEAD 之间逐字节一致(git diff origin/main HEAD -- scripts/ 两者均未出现),且本轮 diff 未触碰它们,因此该失败在 base 分支代码上同样复现——属于环境相关失败(经由 sharp/librsvg/字体的像素级精确渲染),并非本次变更引起。
  • 未改动任何 settings 源,因此不适用 npm run generate:settings-schema。未改动任何 bundled CLI 行为,因此不适用集成测试。

验证

  • npx vitest run --config ./scripts/tests/vitest.config.ts qwen-pr-review-workflow(基线)— 151 通过
  • 插入临时覆写步骤的红测 probe 运行 — 新测试按预期失败:1 failed | 151 passed (152)expected '/tmp/probe-ws' to be undefined;随后已从 HEAD 恢复 workflow
  • npx vitest run --config ./scripts/tests/vitest.config.ts qwen-pr-review-workflow(加入新测试后,以及提交后再次运行)— 152 通过
  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js — 通过
  • npm run test:scripts(scripts 全套件)— 1310 通过、16 跳过、1 失败(即上文记录的既有、环境相关的 verify-capture.test.js 失败)

提交:1d6e1369b3test(ci): pin the runner-owned GITHUB_WORKSPACE premise before the workspace wipe

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

@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.

Reviewed — no blockers. Suggestions are inline.

中文说明

已审查——无阻断问题。 建议见行内评论。

— qwen3.8-max via Qwen Code /review (v0.21.13)

Comment thread scripts/tests/qwen-pr-review-workflow.test.js
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
@wenshao

wenshao commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@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.

⚠️ This run could not certify that any of this diff was reviewed.

Not reviewed: coverage — no plan was given, so this run cannot show that any of the diff was read.

— qwen-code via Qwen Code /review (v0.21.10)

@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. Suggestions are inline.

Not explored to full depth (tool budget reached): "本 PR 将 #9220 引入的 checkout 自愈步骤收缩回 wipe-and-retry 核心,删除…": empirical Linux confirmation that find -P does not descend a symlinked starting-point (Windows host could not create a real symlink; relied on documented GNU …; "本 PR 将 #9220 引入的 checkout 自愈步骤收缩回 wipe-and-retry 核心,删除…": none — all planned checks completed within budget. (Note: the suite is excluded on win32 per its own comment, so I verified statically rather than by running vi…; "本 PR 将 #9220 引入的 checkout 自愈步骤收缩回 wipe-and-retry 核心,删除…": could not run scripts/tests/qwen-pr-review-workflow.test.js itself — scripts/tests/vitest.config.ts excludes qwen-*-workflow.test.js on win32 and the work….

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查。 建议见行内评论。

未探索到全部深度(达到工具调用预算):"本 PR 将 #9220 引入的 checkout 自愈步骤收缩回 wipe-and-retry 核心,删除…"empirical Linux confirmation that find -P does not descend a symlinked starting-point (Windows host could not create a real symlink; relied on documented GNU …"本 PR 将 #9220 引入的 checkout 自愈步骤收缩回 wipe-and-retry 核心,删除…"none — all planned checks completed within budget. (Note: the suite is excluded on win32 per its own comment, so I verified statically rather than by running vi…"本 PR 将 #9220 引入的 checkout 自愈步骤收缩回 wipe-and-retry 核心,删除…"could not run scripts/tests/qwen-pr-review-workflow.test.js itself — scripts/tests/vitest.config.ts excludes qwen-*-workflow.test.js on win32 and the work…

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

— qwen3.8-max via Qwen Code /review (v0.21.10)

Comment thread .github/workflows/qwen-code-pr-review.yml Outdated
Comment thread .github/workflows/qwen-code-pr-review.yml
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 2/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 2/100 轮)。改动内容与我反驳保留之处如下:

Autofix review round — PR #9327

Round 2 — all 5 automated-reviewer suggestions resolved in code. Each finding was first reproduced on the reviewed commit (1d6e1369b3) with a mutation probe against the workflow YAML (each probe reverted after the run), then the fix was verified by re-running the same mutation and confirming it is now caught.

Findings

  • [rc:3796309079] R2-1 — resolved. Reproduced: adding env: GITHUB_WORKSPACE: '/tmp/somewhere-else' to the wipe step kept all 8 self-heal tests green. Fix: the premise test now asserts wipe.env?.GITHUB_WORKSPACE is undefined — the pre-wipe slice stops AT the sink, and the wipe step's own env: block is now sealed. The mutation is now caught.
  • [rc:3796309099] R2-5 — resolved. Reproduced: a job-level env: BASH_ENV entry kept the whole suite green. Fix: BASH_ENV is now asserted undefined at every scope — workflow env:, job env:, every pre-wipe step, and the wipe step's own block (the seam between the slice fix and the R2-1 fix). The mutation is now caught.
  • [rc:3796309115] R2-6 — resolved. The premise comment was reworded: the dead channels (export dies at the step process boundary; the runner drops $GITHUB_ENV writes of GITHUB_*/RUNNER_* names) are no longer claimed as sealed, the channels that DO propagate are named (declarative env: entries at every scope including the wipe step's own, BASH_ENV startup-file pointers, $GITHUB_PATH promotion, $GITHUB_ENV writes of unprotected names), and the comment now states why the two dead channels are deliberately not checked.
  • [rc:3796309122] R2-6 location 2 — resolved. Reproduced both failure modes of the old check: a read-only echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" diagnostic turned the suite red (false positive), and export GITHUB_WORKSPACE=… in a pre-wipe run block turned it red on a write that cannot propagate (zero true-positive signal). The GITHUB_WORKSPACE= containment check is dropped; its coverage survives in the env-block assertions plus a retargeted run-block check on $GITHUB_ENV (the env-file channel), which is green today and catches pre-wipe env-file writes such as echo "BASH_ENV=…" >> "$GITHUB_ENV" (mutation-verified).
  • [rc:3796309140] R2-8 — resolved. Reproduced: a pre-wipe echo … >> "$GITHUB_PATH" write kept the suite green. Fix: expect(step.run ?? '').not.toContain('$GITHUB_PATH') added to the pre-wipe loop — green today, since the workflow's only $GITHUB_PATH write is post-wipe in Install capture tools. PATH promotion is named among the sealed channels in the reworded comment. The mutation is now caught.

The test was renamed from keeps GITHUB_WORKSPACE runner-owned before the wipe to seals every override channel into the wipe step to match its widened scope; no other code references the old name.

Review bodies also read: [rv:4951542859] carries no findings beyond the inline ones; [rv:4953214060] is a statement about that review run's own coverage certification (no plan supplied to it) — it contains no defect claim or actionable suggestion, so no code action applies.

Changes

scripts/tests/qwen-pr-review-workflow.test.js only (+18/−8). Mutation probes transiently mutated .github/workflows/qwen-code-pr-review.yml and were reverted after each run; the committed diff does not touch it.

Conflict notes

--conflict false — no merge performed.

Verification

  • Baseline on reviewed commit: npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js — 152 passed (152)
  • Pre-fix mutation probes (each reverted): wipe-step env: GITHUB_WORKSPACE → green (gap confirmed); job-level env: BASH_ENV → green (gap confirmed); pre-wipe $GITHUB_PATH write → green (gap confirmed); read-only echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" → red (false positive confirmed); export GITHUB_WORKSPACE=… → red (dead-channel trip confirmed)
  • Post-fix mutation probes (each reverted): wipe-step env: GITHUB_WORKSPACE → red (caught); job-level env: BASH_ENV → red (caught); pre-wipe $GITHUB_PATH write → red (caught); pre-wipe echo "BASH_ENV=…" >> "$GITHUB_ENV" → red (caught); read-only echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" → green (false positive gone)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js (after fix) — 152 passed (152)
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js — passed
  • npm run lint — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run build — passed (exit 0)
  • No settings source changed → npm run generate:settings-schema not required. Change is test-only under scripts/tests/; no bundled-CLI or integration-harness behavior touched → no integration run required.
中文说明

Autofix 审查轮次 — PR #9327

第 2 轮——自动审查者的 5 条建议全部已在代码中解决。每条发现均先在被审查 commit(1d6e1369b3)上用变异 probe 复现(对 workflow YAML 做临时变异,每次运行后即还原),再重跑同一变异确认修复后该变异会被捕获,以此验证修复。

发现处理

  • [rc:3796309079] R2-1——已解决。 复现:给 wipe 步骤加 env: GITHUB_WORKSPACE: '/tmp/somewhere-else',8 个 self-heal 测试全部保持绿。修复:前提测试现在断言 wipe.env?.GITHUB_WORKSPACE 为 undefined——wipe 前的 slice 止于 sink 之前一步,wipe 步骤自身的 env: 块现在也被密封。该变异现在会被捕获。
  • [rc:3796309099] R2-5——已解决。 复现:job 级 env: BASH_ENV 条目使整个套件保持全绿。修复:BASH_ENV 现在在所有层级被断言为 undefined——workflow 级 env:、job 级 env:、每个 wipe 前步骤,以及 wipe 步骤自身的块(即 slice 修复与 R2-1 修复之间缝隙处)。该变异现在会被捕获。
  • [rc:3796309115] R2-6——已解决。 前提注释已改写:不再把死通道声称为已密封(export 死于步骤进程边界;runner 会丢弃对 GITHUB_*/RUNNER_* 名称的 $GITHUB_ENV 写入),点名真正能传播的通道(包括 wipe 步骤自身在内的所有层级的声明式 env: 条目、BASH_ENV 启动文件指针、$GITHUB_PATH 提升、对非保护名的 $GITHUB_ENV 写入),并在注释中说明为何刻意不检查那两条死通道。
  • [rc:3796309122] R2-6 第 2 处——已解决。 复现了旧检查的两种失效形态:只读的 echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" 诊断会让套件变红(误报);wipe 前 run 块中的 export GITHUB_WORKSPACE=… 也会让测试变红——而该写法根本无法传播(零真阳性信号)。GITHUB_WORKSPACE= 包含性检查已删除;其覆盖面由 env 块断言加重定向后的 $GITHUB_ENV run-block 检查(env-file 通道)承接,后者今天为绿,且能捕获 wipe 前的 env-file 写入(如 echo "BASH_ENV=…" >> "$GITHUB_ENV",已用变异验证)。
  • [rc:3796309140] R2-8——已解决。 复现:wipe 前的 echo … >> "$GITHUB_PATH" 写入使套件保持全绿。修复:wipe 前循环中加入 expect(step.run ?? '').not.toContain('$GITHUB_PATH')——今天为绿,因为 workflow 唯一的 $GITHUB_PATH 写入在 wipe 之后的 Install capture tools。PATH 提升已在改写后的注释中列入已密封通道。该变异现在会被捕获。

测试由 keeps GITHUB_WORKSPACE runner-owned before the wipe 更名为 seals every override channel into the wipe step 以匹配扩大后的范围;无其他代码引用旧名。

审查 body 也已阅读:[rv:4951542859] 除行内发现外无其他内容;[rv:4953214060] 是关于该次审查运行自身覆盖率认证的说明(未向其提供 plan)——不含缺陷主张或可执行建议,因此无代码动作。

变更

scripts/tests/qwen-pr-review-workflow.test.js(+18/−8)。变异 probe 曾临时修改 .github/workflows/qwen-code-pr-review.yml,每次运行后均已还原;提交的 diff 不涉及该文件。

冲突说明

--conflict false——未执行任何合并。

验证

  • 被审查 commit 上的基线:npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js — 152 通过(152)
  • 修复前变异 probe(每次均已还原):wipe 步骤 env: GITHUB_WORKSPACE → 绿(确认缺口);job 级 env: BASH_ENV → 绿(确认缺口);wipe 前 $GITHUB_PATH 写入 → 绿(确认缺口);只读 echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" → 红(确认误报);export GITHUB_WORKSPACE=… → 红(确认死通道触发)
  • 修复后变异 probe(每次均已还原):wipe 步骤 env: GITHUB_WORKSPACE → 红(被捕获);job 级 env: BASH_ENV → 红(被捕获);wipe 前 $GITHUB_PATH 写入 → 红(被捕获);wipe 前 echo "BASH_ENV=…" >> "$GITHUB_ENV" → 红(被捕获);只读 echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE" → 绿(误报消除)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js(修复后)— 152 通过(152)
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js — 通过
  • npm run lint — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run build — 通过(exit 0)
  • 未改动 settings 源 → 无需 npm run generate:settings-schema。变更仅为 scripts/tests/ 下的测试;未涉及 bundled CLI 或集成测试 harness 的行为 → 无需集成测试。

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

Addresses the two doudouOUC findings on the simplified heal:

- The wipe now validates the filesystem OBJECT at $WS, not just the
  string: find -P does not descend a symlinked start, so a redirected
  workspace logged 'wiped for a clean retry' while deleting nothing,
  and the secret-bearing review step would then run through the
  redirection. Refuse loud on a symlink or non-directory — POSIX-only,
  no false-positive surface (a legitimate workspace is always a
  runner-created plain directory), and it pins the only sudo-escalated
  wipe in the pool to a validated target.
- The clean-wipe silence branch was unpinned: the reviewer's minimal
  mutant (dropping the if/fi pair) shipped an empty-list survivor
  warning on every heal with the suite green. The clean-wipe test now
  asserts the success annotation and the absence of the survivor
  warning; both mutants verified red.

@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.

Reviewed. Suggestions are inline.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查。 建议见行内评论。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

— qwen3.8-max via Qwen Code /review (v0.21.13)

Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread .github/workflows/qwen-code-pr-review.yml Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@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.

Reviewed — no blockers. Suggestions are inline.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 4, not a blocker) — recorded, not requested in this round:

  • .github/workflows/qwen-code-pr-review.yml:570 — [review] Trailing-slash spelling bypasses the new object guard
中文说明

已审查——无阻断问题。 建议见行内评论。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 4 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.21.13)

Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread .github/workflows/qwen-code-pr-review.yml Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 3/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 3/100 轮)。改动内容与我反驳保留之处如下:

Autofix review round — PR #9327

One commit this round: 95391df97ftest(ci): seal the wipe step's surviving override channels (1 file, +46/−21, test-only; the workflow itself is unchanged). No conflicts (--conflict false, no merge performed).

Round-1 findings (@doudouOUC) — fixed in earlier commits, re-verified this round

  • rc:3798137911 (object validation at the wipe target) — resolved. Already fixed in fcb121a434: the wipe refuses loud on [ -L "$WS" ] || [ ! -d "$WS" ] before either leg runs, and 'refuses a redirected workspace instead of silently wiping nothing' pins the symlink direction. Re-verified present and passing at HEAD.
  • rc:3798137922 (clean-wipe silence branch untested) — resolved. Already fixed in fcb121a434: the clean-wipe test captures runWipe stdout and asserts workspace wipe left survivors is absent. Re-verified present and passing at HEAD.

Round-3/4 findings (automated reviewer) — all addressed in this round

Every claim below was reproduced on the current code before implementing, and each fix was mutant-verified (mutant applied to the workflow, suite turned red, workflow restored).

  • R3-1 (rc:3798763865, rc:3799375140) — braced expansions slip the seal. Reproduced: '${GITHUB_ENV}'.includes('$GITHUB_ENV') is false (a { sits between $ and the name). The two not.toContain checks are now one regex, /\$\{?GITHUB_(ENV|PATH)\b/, matching both the bare and the braced spelling. Mutant: a pre-wipe step writing >> "${GITHUB_ENV}" → seal red.
  • R3-2 (rc:3798763875, rc:3799375158) — named pins cannot enumerate the declarative-env: surface. Reproduced pre-fix: workflow-scope PATH: '/tmp/poison-probe' kept the old suite green (153/153). The seal now class-scans the three scopes that propagate into the wipe step (workflow env:, review-pr job env:, wipe step env:) for GITHUB_WORKSPACE|PATH|BASH_ENV|CDPATH|ENV plus the LD_ and BASH_FUNC_ prefixes. Two notes: (1) the suggested single anchored regex /^(…|LD_|BASH_FUNC_|…)$/ does not match prefixed names — verified LD_PRELOAD fails it — so the fix splits exact names from prefix classes; (2) the former two-name pins on pre-wipe step-local env: blocks were dropped in the same rewrite, because step-local env dies with its step and is not a channel into the wipe (the run-text scan still covers writes made by those steps).
  • R3-3 (rc:3798763879, rc:3799375162) — the pinned comment claimed the :? abort is the wipe's only deliberate nonzero exit while this PR's plain-directory guard adds a second. Reworded to name both exits; the continue-on-error: undefined assertion covers them both unchanged.
  • R3-4 (rc:3798763885, rc:3799375167) — the [ ! -d ] disjunct had no test (the symlink test short-circuits at [ -L ]). Reproduced pre-fix: the disjunct-drop mutant survived 153/153. Added 'refuses a non-directory workspace instead of wiping nothing' (file-valued workspace → refusal throws, file survives); the disjunct-drop mutant is now red while the symlink test stays green.
  • R3-5 (rc:3798763892, rc:3799375171) — the comment's stated runner mechanism was wrong (the runner does not drop $GITHUB_ENV writes of GITHUB_* names; its blocklist is NODE_OPTIONS only). Rewritten to the accurate shape: $GITHUB_ENV writes of runtime-context names (e.g. GITHUB_WORKSPACE) are overwritten when the runner re-applies its runtime environment at step setup. No assertion logic depended on the wrong wording.
  • R3-6 (rc:3798763896) — a uses: step has no run text, so its runtime core.addPath / core.exportVariable writes were invisible to the seal. Every pre-wipe uses: step is now pinned to the SHA-fixed checkout (the only pre-wipe action at HEAD; the same SHA is already pinned elsewhere in this suite). Mutant: inserting an actions/setup-node@v4 step ahead of the wipe → seal red.

Not actionable this round

  • Author disposition replies rc:3798293433, rc:3798293808, rc:3798294243, rc:3798294504, rc:3798294872, rc:3798295261, rc:3798295644, rc:3798296026 — these are earlier-round replies describing fixes; their claims were checked against the current code (guard, seal, and silence assertion all present; the comment-accuracy claim is now fully correct after the R3-5 reword). No reply or code action required.
  • Review bodies rv:4953803375, rv:4954522717, rv:4955225111 — their findings are tracked through the inline comments above.
  • The round-4 review's deferred note ("Trailing-slash spelling bypasses the new object guard") is explicitly recorded by the reviewer as not requested in this round — no action taken; it remains on the reviewer's record.

Verification

Commands actually run this round, in order:

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js — 154/154 passed (153 pre-existing + 1 new), re-run green on the committed tree
  • Pre-fix mutant reproduction (old suite): workflow-scope PATH poison → 153/153 green (mutant survives); [ ! -d ] disjunct drop → 153/153 green (mutant survives); '${GITHUB_ENV}'.includes('$GITHUB_ENV') node probe → false
  • Post-fix mutant battery (each mutant applied to the workflow, suite run, workflow restored byte-identical): braced ${GITHUB_ENV} write → red (expected … not to match /\$\{?GITHUB_(ENV|PATH)\b/); workflow-scope PATH → red (expected [ 'PATH' ] to deeply equal []); [ ! -d ] drop → red (expected [Function] to throw an error); unplanned uses: step → red (expected 'actions/setup-node@v4' to be 'actions/checkout@df4cb…')
  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0, no problems)
  • npm run test:scripts — 54/54 files, 1313 passed | 16 skipped, exit 0. Two initial failures were both proven unrelated to this change: install-script.test.js failed identically on the base tree (missing packages/audio-capture/dist build output in this checkout) and cleared after npm run build; verify-capture.test.js was a transient parallel-run flake — it passes in isolation both with and without this change and passed in the base full run
  • npx prettier --check on the changed file — clean
中文说明

Autofix 审查轮次 — PR #9327

本轮一个 commit:95391df97ftest(ci): seal the wipe step's surviving override channels(1 个文件,+46/−21,纯测试改动;workflow 本身未变)。无冲突(--conflict false,未执行合并)。

第 1 轮发现(@doudouOUC)——已在先前 commit 修复,本轮复核

  • rc:3798137911(wipe 目标的对象校验)——已解决。fcb121a434 已修复:wipe 在两条分支运行前以 [ -L "$WS" ] || [ ! -d "$WS" ] 响亮拒绝,且 'refuses a redirected workspace instead of silently wiping nothing' 钉住了符号链接方向。已在 HEAD 复核存在且通过。
  • rc:3798137922(干净 wipe 的静默分支无测试)——已解决。fcb121a434 已修复:干净 wipe 测试捕获 runWipe 的 stdout 并断言不含 workspace wipe left survivors。已在 HEAD 复核存在且通过。

第 3/4 轮发现(自动审查器)——本轮全部处理

以下每项都在实施前于当前代码上复现,且每个修复都经过变异验证(变异施加到 workflow → 套件变红 → workflow 逐字节还原)。

  • R3-1(rc:3798763865、rc:3799375140)——花括号展开形式漏过密封。复现:'${GITHUB_ENV}'.includes('$GITHUB_ENV')false$ 与名称之间隔着 {)。两处 not.toContain 合并为一个正则 /\$\{?GITHUB_(ENV|PATH)\b/,同时匹配裸写法和花括号写法。变异:wipe 前步骤写 >> "${GITHUB_ENV}" → 密封变红。
  • R3-2(rc:3798763875、rc:3799375158)——按名称钉住无法穷举声明式 env: 的表面。修复前复现:workflow 层 PATH: '/tmp/poison-probe' 下旧套件保持绿色(153/153)。密封现在对三个会传播进 wipe 步骤的作用域(workflow env:review-pr job env:、wipe 步骤自身 env:)按类扫描:GITHUB_WORKSPACE|PATH|BASH_ENV|CDPATH|ENVLD_BASH_FUNC_ 前缀。两点说明:(1) 建议中的单一锚定正则 /^(…|LD_|BASH_FUNC_|…)$/ 匹配不到带前缀的名称——已验证 LD_PRELOAD 不匹配——因此修复把精确名与前缀类分开写;(2) 同一重写中删除了原先对 wipe 前各步骤步骤级 env: 块的两名钉住,因为步骤级 env 随步骤结束而消亡,不是进入 wipe 的通道(这些步骤内的写入仍由 run 文本扫描覆盖)。
  • R3-3(rc:3798763879、rc:3799375162)——被钉住的注释声称 :? 中止是 wipe 步骤唯一的有意非零退出,而本 PR 的普通目录守卫新增了第二个。改写注释以同时点名两个退出;continue-on-error: undefined 断言对两者仍然成立,未改动。
  • R3-4(rc:3798763885、rc:3799375167)——[ ! -d ] 分支没有测试(符号链接测试在 [ -L ] 处短路)。修复前复现:删除该分支的变异体在 153/153 下存活。新增 'refuses a non-directory workspace instead of wiping nothing'(文件值 workspace → 拒绝并抛出,文件幸存);删除分支的变异体现在变红,符号链接测试保持绿色。
  • R3-5(rc:3798763892、rc:3799375171)——注释陈述的 runner 机制有误(runner 并不会丢弃 GITHUB_* 名称的 $GITHUB_ENV 写入;其黑名单只有 NODE_OPTIONS)。改写为准确表述:运行时上下文名称(如 GITHUB_WORKSPACE)的 $GITHUB_ENV 写入会在 runner 于步骤启动时重新应用其运行时环境时被覆写。断言逻辑不依赖这段错误表述。
  • R3-6(rc:3798763896)——uses: 步骤没有 run 文本,其运行时 core.addPath / core.exportVariable 写入对密封不可见。现在 wipe 前的每个 uses: 步骤都被钉住为 SHA 固定的 checkout(HEAD 上 wipe 前唯一的 action;同一 SHA 已在本套件其他位置钉住)。变异:在 wipe 前插入 actions/setup-node@v4 步骤 → 密封变红。

本轮不处理

  • 作者处置回复 rc:3798293433、rc:3798293808、rc:3798294243、rc:3798294504、rc:3798294872、rc:3798295261、rc:3798295644、rc:3798296026——这些是先前轮次描述修复的回复;其声明已对照当前代码核对(守卫、密封、静默断言均在;注释准确性声明在 R3-5 改写后完全正确)。无需回复或代码动作。
  • 审查正文 rv:4953803375、rv:4954522717、rv:4955225111——其发现均通过上方行内评论跟踪。
  • 第 4 轮审查中延后的记录("Trailing-slash spelling bypasses the new object guard")被审查者明确标记为本轮不要求修改——未采取行动,仍留在审查者的记录上。

验证

本轮实际执行的命令,按顺序:

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js — 154/154 通过(153 个既有 + 1 个新增),在提交后的树上复跑仍为绿色
  • 修复前变异复现(旧套件):workflow 层 PATH 投毒 → 153/153 绿色(变异体存活);删除 [ ! -d ] 分支 → 153/153 绿色(变异体存活);'${GITHUB_ENV}'.includes('$GITHUB_ENV') node 探针 → false
  • 修复后变异组(每个变异施加到 workflow、跑套件、再逐字节还原 workflow):花括号 ${GITHUB_ENV} 写入 → 红(expected … not to match /\$\{?GITHUB_(ENV|PATH)\b/);workflow 层 PATH → 红(expected [ 'PATH' ] to deeply equal []);删除 [ ! -d ] → 红(expected [Function] to throw an error);计划外 uses: 步骤 → 红(expected 'actions/setup-node@v4' to be 'actions/checkout@df4cb…'
  • npm run build — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run lint — 通过(exit 0,无问题)
  • npm run test:scripts — 54/54 文件,1313 通过 | 16 跳过,exit 0。最初的两个失败均已证明与本次改动无关:install-script.test.js 在基线树上以完全相同的方式失败(本 checkout 缺少 packages/audio-capture/dist 构建产物),并在 npm run build 后转绿;verify-capture.test.js 是并行运行下的瞬时抖动——在带与不带本改动的情况下单独运行均通过,且在基线全量运行中通过
  • npx prettier --check 作用于被改文件 — 干净

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 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.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: the executable-script lint — qwen review script-lint produced no report.

Not explored to full depth (tool budget reached): "You are review agent 6b — Agent 6b: Undirected audit — 3…": None. I read the full diff, examined both the old and new versions of the workflow file and test file, verified the continue-on-error wiring on the first chec…; "You are review agent 6c — Agent 6c: Undirected audit —…": none (within the ~36-call budget).; "You are review agent 6a — Agent 6a: Undirected audit —…": None. All checks completed within budget..

Not reviewed: verification and reverse audit — neither the verifier nor the reverse auditor was launched with a prompt this skill builds — the posted findings were ruled on, and the misses the rest of the review left were hunted, if at all, without the briefs this skill certifies against.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:the executable-script lint — qwen review script-lint produced no report。

未探索到全部深度(达到工具调用预算):"You are review agent 6b — Agent 6b: Undirected audit — 3…"None. I read the full diff, examined both the old and new versions of the workflow file and test file, verified the continue-on-error wiring on the first chec…"You are review agent 6c — Agent 6c: Undirected audit —…"none (within the ~36-call budget)."You are review agent 6a — Agent 6a: Undirected audit —…"None. All checks completed within budget.

未审查:验证与反向审计——验证 agent 与反向审计 agent 都没有用本 skill 构建的 prompt 启动——发布的发现即便被裁定过、评审其余部分遗漏的问题即便被搜寻过,也都缺失了本 skill 用以认证的 brief。

— qwen3.8-max via Qwen Code /review (v0.21.10)

Comment thread .github/workflows/qwen-code-pr-review.yml Outdated
Comment thread scripts/tests/qwen-pr-review-workflow.test.js
Comment thread scripts/tests/qwen-pr-review-workflow.test.js
Comment thread scripts/tests/qwen-pr-review-workflow.test.js Outdated
Comment thread .github/workflows/qwen-code-pr-review.yml Outdated

@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.

PR head 已漂移

审查锁定的 head SHA 为 1b33a9abf8fa9199d376c10ff98084dd9268ccd6,当前 PR head 已变为 95391df97f8f2317f4418ac515fa39cbb111d50d。原 inline 评论可能已失效,以下仅保留审查汇总。

审查汇总(deepseek-v4-flash)

PR #9327#9220 引入的 checkout 自愈步骤从约 60 行守卫层 + 13 个测试收缩为约 22 行 wipe-and-retry 核心 + 7 个测试,净 −294 行。

结论:无阻塞问题,但识别出 5 条改进建议。

主要发现:

  1. qwen-code-pr-review.yml:562 — 新守卫未检查 $WS 是否为系统根目录(//usr 等)。runner 配置错误时可能通过 symlink/目录检查并进入 sudo -n find wipe。
  2. qwen-pr-review-workflow.test.js:2810[ ! -d "$WS" ] 守卫分支(路径不存在)缺少专属测试,仅测试了 symlink 分支。
  3. qwen-pr-review-workflow.test.js:2758 — “could not wipe the workspace” else 分支消息未断言,消息漂移无法被现有测试捕获。
  4. qwen-pr-review-workflow.test.js:2847 — seal 测试只扫描 step.run 文本中的 $GITHUB_ENV/$GITHUB_PATH,未检查 uses: action 步骤;当前无风险但建议文档化。
  5. qwen-code-pr-review.yml:568 — 非 sudo 的 find 命令使用 2>/dev/null 静默丢弃错误信息,不利于调试。

总体判断:删除守卫层的威胁模型论据成立;保留的测试仍能覆盖核心事故场景。

@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.

Reviewed — no blockers. Suggestions are inline.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 5, not a blocker) — recorded, not requested in this round:

  • .github/workflows/qwen-code-pr-review.yml:581 — [probe] Survivor warning dropped the entry count while keeping the 500-char truncation — a truncated list presents itself as complete (unchanged since round 4; deferred under the convergence p…
中文说明

已审查——无阻断问题。 建议见行内评论。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 5 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.21.13)

Comment thread scripts/tests/qwen-pr-review-workflow.test.js
Addresses the open review findings on the simplified heal:

- The seal's premise covered declarative env, $GITHUB_ENV/$GITHUB_PATH
  run writes, and the pre-wipe action set, but three channels passed it
  unchecked: a wipe-step `shell:` or workflow/job `defaults:` wrapper
  re-targets the environment at exec time; SHELLOPTS rides the same
  bash-startup family as BASH_ENV/ENV yet sat outside the dangerous
  name class; and ACTIONS_ALLOW_UNSECURE_COMMANDS re-enables the legacy
  ::set-env:: / ::add-path:: spellings the run-text scan did not match.
  Each channel was reproduced green against the old seal (mutant probe)
  and now turns it red.
- The both-legs-fail test now also pins the else-branch "could not
  wipe" warning, and a dedicated test pins the `[ ! -d ]` refusal for a
  nonexistent workspace — the plain-file test alone still passes a
  guard mutated to `[ -f ]`.
- The non-sudo wipe leg keeps its stderr: the 2>/dev/null discarded
  exactly the diagnostics oncall needs when the wipe fails, and the
  sudo leg already ran unsuppressed.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 4/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 4/100 轮)。改动内容与我反驳保留之处如下:

Autofix round summary — PR #9327

Implemented 4 of the 6 inline findings and declined 2 with recorded evidence. No conflict resolution was needed (--conflict false, no merge performed). One commit landed: 20e220da6e.

Findings

Implemented

  • [rc:3800643392] (R5-1: three channels pass the seal unchecked) — implemented as suggested, after reproducing every channel first. Mutant probes against the pre-change seal: injecting SHELLOPTS: noexec into workflow env, a shell: 'env GITHUB_WORKSPACE=/victim bash {0}' wrapper on the wipe step, or ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' into workflow env each left the seal test green (gap reproduced). The fix then:

    • pins the shell selection: wipe.shell, workflow-level defaults.run.shell, and job-level defaults.run.shell must all be undefined;
    • adds SHELLOPTS and ACTIONS_ALLOW_UNSECURE_COMMANDS to the dangerous-env name class;
    • extends the pre-wipe run-text scan to also reject the legacy ::set-env:: / ::add-path:: command spellings.

    Post-fix mutant verification: each of the three injections, plus a ::add-path:: echo planted in a pre-wipe run block, now fails the seal test (red); all mutants were reverted and the unmutated tree stays green. The seal comment's channel enumeration was updated to match. The two structural alternatives (rescinding the exhaustiveness claim, absolute-path find/rm) were not taken: the tripwire is this PR's documented safety story, and closing the demonstrated channels costs no production surface.

  • [rc:3799686313] (else-branch warning unpinned) — the both-legs-fail test now asserts could not wipe the workspace, pinning the else branch's message against drift.

  • [rc:3799686310] (no dedicated test for a nonexistent workspace) — added refuses a nonexistent workspace instead of exiting 0 unwiped. The [ ! -d ] disjunct was already partially pinned by the plain-file test; the new test closes the remaining mutation class — a guard weakened to [ -f ] still refuses a plain file but lets a missing path through, after which both wipe legs fail on the absent start point and the step exits 0 unwiped into a retry that fails again.

  • [rc:3799686332] (2>/dev/null swallows find errors) — removed the suppression from the non-sudo find. The else branch fires exactly when that stderr carries the diagnostic, the sudo leg already ran unsuppressed, and the pool idiom's other source (serve-ab.yml) does not suppress either.

Declined (with evidence)

  • [rc:3799686304] (system-root denylist / restore the RUNNER_WORKSPACE allowlist) — declined: conflicts with the PR's direction, and the proposed guard would not close the scenario it names.

    1. The workflow triggers on pull_request_target, so the workflow YAML — the only declarative env channel — always comes from the base branch. PR authors cannot influence GITHUB_WORKSPACE here, and the seal test (extended this round) pins every maintainer-editable override channel.
    2. The wipe step runs between a failed base checkout and its retry, before any PR content is fetched, so its environment holds no PR-derived data.
    3. GITHUB_WORKSPACE and RUNNER_WORKSPACE are both computed by actions/runner from the same work-directory layout. Restoring the allowlist would compare two values from the same source: an actor able to point one at a system root can point both at any path that is not enumerated, and a partial denylist only relocates the catastrophic target.
    4. A denylist cannot enumerate the dangerous roots — exactly why the old code paired it with an allowlist, strip loops, realpath canonicalization, and 13 tests pinning their spelling variants. Reintroducing it restores that accretion without defending against the actor the scenario requires (runner-host-level control of the workspace layout).

    The threat model was accepted by two later reviews of this exact code (deepseek-v4-flash round and qwen3.8-max round 5, both reporting no blockers).

  • [rc:3799686315] (seal's env/path scan ignores uses: steps) — declined: already covered. The seal pins every pre-wipe uses: step to the exact actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 SHA (expect(step.uses).toBe(...)), which is the inspection for this channel — a runtime core.addPath / core.exportVariable write can only reach the wipe step through a SHA-pinned action's code — and the seal comment documents exactly that ("and the pre-wipe action set, because a uses: step's runtime core.addPath / core.exportVariable writes have no run text to scan"). The proposed alternative (assert every pre-wipe uses is undefined) is unsatisfiable: the heal chain's own checkout is a uses: step.

Conflict notes

None — --conflict false; origin/main was not merged.

Verification

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js (baseline, before changes) — passed, 154 tests
  • Mutant probes against the pre-change seal test — each of SHELLOPTS: noexec (workflow env), shell: 'env GITHUB_WORKSPACE=/victim bash {0}' (wipe step), and ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' (workflow env) left the seal test green, reproducing the reported gaps
  • The same three mutants plus a ::add-path:: echo planted in a pre-wipe run block, run against the fixed seal — all four now fail the seal test; mutants reverted after each probe
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js (after changes, and again on the committed tree) — passed, 155 tests
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js — passed
  • npm run test:scripts (full scripts suite) — 53/54 files passed; two unrelated environment-specific failures, each verified in isolation:
    • install-script.test.js failed on a missing packages/audio-capture/dist build artifact; npm run build:ts -w @qwen-code/audio-capture produced it, and the file then passed standalone (105 tests)
    • verify-capture.test.js failed intermittently on a pixel-rendering assertion under the full parallel suite; it passes standalone (23 tests)
中文说明

Autofix 轮次总结 — PR #9327

本轮实现了 6 条行内发现中的 4 条,另有 2 条以记录在案的理由拒绝。无需冲突处理(--conflict false,未执行合并)。提交一个 commit:20e220da6e

发现处理

已实现

  • [rc:3800643392](R5-1:三条通道绕过密封测试)—— 按建议实现,且先逐条复现。对修改前的密封测试注入变异探针:在 workflow env 注入 SHELLOPTS: noexec、在 wipe 步骤注入 shell: 'env GITHUB_WORKSPACE=/victim bash {0}'、在 workflow env 注入 ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true',密封测试均保持绿色(缺口复现成功)。随后修复:

    • 钉住 shell 选择:wipe.shell、workflow 级 defaults.run.shell、job 级 defaults.run.shell 均必须为 undefined;
    • SHELLOPTSACTIONS_ALLOW_UNSECURE_COMMANDS 加入危险 env 名称类;
    • 扩展 wipe 之前 run 文本扫描,同时拒绝遗留的 ::set-env:: / ::add-path:: 命令写法。

    修复后的变异验证:上述三种注入,外加植入 wipe 前 run 块的一条 ::add-path:: echo,全部使密封测试变红;每个探针用后即还原,未变异的树保持绿色。密封测试注释中的通道枚举已同步更新。两个结构性替代方案(收回注释中的穷尽性声明、find/rm 改用绝对路径)未采纳:绊线测试正是本 PR 书面化的安全论证,且封住已实证的通道不需要任何生产代码面。

  • [rc:3799686313](else 分支告警未钉住)—— 双腿均失败的测试现在额外断言 could not wipe the workspace,将该 else 分支的消息钉住,防止漂移。

  • [rc:3799686310](路径不存在场景无专属测试)—— 新增 refuses a nonexistent workspace instead of exiting 0 unwiped[ ! -d ] 分支此前已被纯文件测试部分钉住;新测试封住剩余的变异类——守卫若被弱化为 [ -f ],纯文件仍会被拒绝,但缺失路径会放行,随后两条 wipe 腿都因起点不存在而失败,步骤以 0 退出、未 wipe 就进入注定再次失败的重试。

  • [rc:3799686332]2>/dev/null 吞掉 find 错误)—— 移除非 sudo find 上的该重定向。else 分支恰恰在这些 stderr 携带诊断信息时触发,sudo 腿本就未做抑制,且该池惯用法的另一出处(serve-ab.yml)同样没有抑制。

已拒绝(附证据)

  • [rc:3799686304](系统根目录 denylist / 恢复 RUNNER_WORKSPACE allowlist)—— 拒绝:与 PR 方向冲突,且所提议的守卫并不能关闭其所述场景。

    1. 该 workflow 由 pull_request_target 触发,workflow YAML(唯一的声明式 env 通道)始终来自 base 分支。PR 作者无法影响此处的 GITHUB_WORKSPACE,而密封测试(本轮已扩展)钉住了所有维护者可编辑的覆盖通道。
    2. wipe 步骤运行于 base checkout 失败之后、重试之前,此时尚未拉取任何 PR 内容,其环境中不含任何来自 PR 的数据。
    3. GITHUB_WORKSPACERUNNER_WORKSPACE 都由 actions/runner 从同一 work 目录布局计算得出。恢复 allowlist 只是比较同一来源的两个值:能把其中一个指向系统根目录的行为者,同样能把两者指向任意未被枚举的路径;部分 denylist 只会转移灾难性目标的位置。
    4. denylist 无法枚举完危险根目录——这正是旧代码将其与 allowlist、去尾斜杠循环、realpath 规范化以及 13 个钉住各种拼写变体的测试配套使用的原因。重新引入会恢复全部这些累积,却无法防御该场景所需的行为者(对 runner 主机层面 workspace 布局的控制)。

    该威胁模型已在针对同一代码的两次后续审查中被接受(deepseek-v4-flash 轮与 qwen3.8-max 第 5 轮均报告无阻断问题)。

  • [rc:3799686315](密封的 env/path 扫描忽略 uses: 步骤)—— 拒绝:现有密封已覆盖。测试将 wipe 之前的每个 uses: 步骤钉死为精确的 actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 SHA(expect(step.uses).toBe(...)),这正是针对该通道的检查——运行期的 core.addPath / core.exportVariable 写入只能通过被 SHA 钉死的 action 代码到达 wipe 步骤——密封注释也明确说明了这一点("and the pre-wipe action set, because a uses: step's runtime core.addPath / core.exportVariable writes have no run text to scan")。所提替代方案(断言 wipe 之前每个步骤的 uses 均为 undefined)不可满足:自愈链自身的 checkout 就是一个 uses: 步骤。

冲突说明

无 —— --conflict false;未合并 origin/main

验证

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js(改动前基线)—— 通过,154 个测试
  • 对修改前密封测试的变异探针 —— workflow env 注入 SHELLOPTS: noexec、wipe 步骤注入 shell: 'env GITHUB_WORKSPACE=/victim bash {0}'、workflow env 注入 ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true',密封测试均保持绿色,复现了所报告的缺口
  • 同样三个变异外加植入 wipe 前 run 块的一条 ::add-path:: echo,对修复后的密封运行 —— 四者全部使密封测试失败;每个探针用后即还原
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js(改动后,以及提交后的树上再次运行)—— 通过,155 个测试
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js —— 通过
  • npm run test:scripts(scripts 全量套件)—— 53/54 个文件通过;两个与本改动无关的环境相关失败,均已单独验证:
    • install-script.test.js 因缺少构建产物 packages/audio-capture/dist 而失败;执行 npm run build:ts -w @qwen-code/audio-capture 生成后,该文件单独运行通过(105 个测试)
    • verify-capture.test.js 在全量并行套件下间歇性地在像素渲染断言上失败;单独运行通过(23 个测试)

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

@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.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 6, not a blocker) — recorded, not requested in this round:

  • .github/workflows/qwen-code-pr-review.yml:555 (+3 locations) — [probe] pool-wipe siblings (qwen-triage.yml before/after external code, serve-ab.yml) lack the object check this diff adds and names as one idiom
  • scripts/tests/qwen-pr-review-workflow.test.js:2861 — [review] R5-1 premise-seal exhaustiveness claim still stands: round-5 entrances fixed at this head, new ${{ }} interpolation channel demonstrated this round
中文说明

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 6 轮,非阻断)——已记录,本轮不要求修改:共 2 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.21.13)

Comment thread .github/workflows/qwen-code-pr-review.yml Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@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.

Partially reviewed — gaps disclosed.

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 10.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 7, not a blocker) — recorded, not requested in this round:

  • scripts/tests/qwen-pr-review-workflow.test.js:2861 — [probe] R5-1 class (round 5, still standing): premise-seal exhaustiveness claim unsatisfiable — round-7 entrances probe-verified: indirect $(printenv GITHUB_PATH)/${!v} spellings; NODE_OP…
  • scripts/tests/qwen-pr-review-workflow.test.js:2899 — [probe] RA4-1: seal's ::set-env:: leg is dead — regex requires '::set-env::' but the only valid syntax is '::set-env name=VAR::'; fix /::(set-env|add-path)\b/ (probe flips green→red)
  • scripts/tests/qwen-pr-review-workflow.test.js:2886 — [probe] RA5-1: seal's dangerousEnv scan never inspects pre-wipe steps' own step-level env blocks — step-local BASH_ENV executes planted code whose $GITHUB_PATH write persists (probe-verif…
中文说明

仅完成部分审查,审查缺口已披露。

未审查:反向审计——在 10 轮的反审轮数上限内未收敛。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 7 轮,非阻断)——已记录,本轮不要求修改:共 3 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.21.13)

Comment thread .github/workflows/qwen-code-pr-review.yml Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 5/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 5/100 轮)。改动内容与我反驳保留之处如下:

Address-review summary — PR #9327

Feedback triage

Finding Severity Disposition
[rc:3801262709] R6-1 — wipe object check only inspects the FINAL path component; a symlinked INTERMEDIATE component escapes it Critical Fixed
[rc:3803198945] R6-1 (re-probed at b5104303, still standing) Critical Fixed (same root cause, same change)

Both inline Criticals describe the same defect: the replacement guard [ -L "$WS" ] || [ ! -d "$WS" ] lstats only the final path component, so a workspace whose parent (or any intermediate component) is a symlink passes the guard, and find … -exec rm -rf {} + then deletes content outside the runner workspace through the redirection before the secret-bearing Run review step proceeds. The removed realpath+allowlist guard refused this shape; the replacement logged success.

Reproduction (before fixing)

I reproduced the defect on the current head with a standalone probe that runs the REAL extracted wipe script (bash -e -o pipefail) against a redirected fixture (the parent of GITHUB_WORKSPACE replaced with a symlink to a target containing a same-named workspace + a victim file):

WS=.../qwen-code/qwen-code   (parent is a symlink -> attacker target)
EXIT CODE 0
stdout: ::warning::first checkout failed; wiped the workspace for a clean retry
VICTIM DELETED
DEFECT REPRODUCED: guard passed, wipe deleted content outside the runner workspace

I also added the regression test first and confirmed it FAILED on the unfixed code (1 failed | 11 passed), proving the test pins a real defect rather than an already-green path.

Fix

Minimal, root-cause, exactly the reviewer's suggested change: validate the resolved location, not just the last component. A runner-created workspace has no symlink components at all, so requiring realpath to resolve to the path itself costs nothing and closes the intermediate-component escape.

if [ "$(realpath -- "$WS")" != "$WS" ] || [ -L "$WS" ] || [ ! -d "$WS" ]; then
  echo "::error::workspace is not a plain directory or resolves through symlinks: $WS"
  exit 1
fi
  • Guard now re-resolves $WS via realpath and refuses any path that does not resolve to itself, alongside the existing -L / -d checks.
  • Added a regression test refuses a workspace redirected through an intermediate symlink (the deleted allowlist-escape test had no replacement; this is the intermediate-component shape).
  • Canonicalized the fixture roots with realpathSync so fixtures hold regardless of a symlinked host tmpdir, matching the suite's existing host-independence discipline.
  • Updated the in-script comment to state why the resolved-path check is required (intermediate symlink escapes -L/-d).

Post-fix probe + tests

EXIT CODE 1
stdout: ::error::workspace is not a plain directory or resolves through symlinks: .../qwen-code/qwen-code
VICTIM SURVIVES
GUARD HOLDS: redirection refused loud, victim untouched

The full checkout self-heal suite and the entire touched test file pass, confirming the legitimate plain-directory wipe still succeeds (exit 0) while the redirection is refused (exit 1).

Notes

  • No merge was performed (--conflict false).
  • This round implemented 1 distinct finding (2 duplicate Critical inline comments). No remaining findings were deferred to a follow-up issue, and none required a maintainer decision.

Verification

Commands actually run (results):

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js (touched) — 156 passed (1 file)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js -t "checkout self-heal" (touched, focused) — 12 passed / 0 failed after fix; 1 failed (the new regression test) before the fix, proving it pins the defect
  • Reproduction probe (extracted wipe script, redirected fixture) — pre-fix: exit 0 + VICTIM DELETED (defect); post-fix: exit 1 + VICTIM SURVIVES (fixed)
  • npx prettier --check on both touched files — clean
  • npx eslint scripts/tests/qwen-pr-review-workflow.test.js — clean

No settings source changed, so npm run generate:settings-schema was not required. No bundled-CLI/integration behavior was touched, so no integration run was required.

中文说明

处理评审总结 — PR #9327

反馈分类

发现 严重级别 处理
[rc:3801262709] R6-1 — wipe 对象检查只检查路径的最后一个分量;符号链接的中间分量可以绕过 Critical 已修复
[rc:3803198945] R6-1(在 b5104303 重新 probe,仍然成立) Critical 已修复(同一根因,同一改动)

两条 inline Critical 描述的是同一个缺陷:替换后的守卫 [ -L "$WS" ] || [ ! -d "$WS" ] 只对路径最后一个分量做 lstat,因此当 workspace 的父目录(或任一中间分量)是符号链接时仍能通过守卫,随后 find … -exec rm -rf {} + 会穿过重定向删除 runner workspace 之外的内容,之后携带密钥的 Run review 步骤照常执行。被删除的 realpath+白名单守卫对这种形态会响亮拒绝,而替换后的脚本却记录成功。

复现(修复前)

我在当前 head 上用一个独立 probe 复现了该缺陷:该 probe 运行真实提取出的 wipe 脚本(bash -e -o pipefail),作用于一个重定向 fixture(把 GITHUB_WORKSPACE 的父目录替换为指向某个目标的符号链接,该目标内含同名 workspace 与一个受害文件):

WS=.../qwen-code/qwen-code   (父目录是符号链接 -> 攻击目标)
EXIT CODE 0
stdout: ::warning::first checkout failed; wiped the workspace for a clean retry
VICTIM DELETED
DEFECT REPRODUCED: guard passed, wipe deleted content outside the runner workspace

我还先添加了回归测试并确认它在未修复代码上失败(1 failed | 11 passed),证明该测试确实钉住了一个真实缺陷,而不是一条本来就绿的路径。

修复

最小化、根因修复,与评审者建议完全一致:校验解析后的位置,而非仅最后一个分量。runner 创建的 workspace 完全不含符号链接分量,因此要求 realpath 解析结果等于路径本身毫无代价,却堵住了中间分量逃逸。

if [ "$(realpath -- "$WS")" != "$WS" ] || [ -L "$WS" ] || [ ! -d "$WS" ]; then
  echo "::error::workspace is not a plain directory or resolves through symlinks: $WS"
  exit 1
fi
  • 守卫现在通过 realpath 重新解析 $WS,拒绝任何无法解析到自身的路径,与既有的 -L / -d 检查并列。
  • 新增回归测试 refuses a workspace redirected through an intermediate symlink(被删除的 allowlist-escape 测试此前没有替代;这正是中间分量形态)。
  • realpathSync 对 fixture 根目录做规范化,使 fixture 不受宿主 tmpdir 是否为符号链接的影响,与该测试套件既有的宿主无关性纪律一致。
  • 更新脚本内注释,说明为何需要解析路径检查(中间符号链接会绕过 -L/-d)。

修复后的 probe + 测试

EXIT CODE 1
stdout: ::error::workspace is not a plain directory or resolves through symlinks: .../qwen-code/qwen-code
VICTIM SURVIVES
GUARD HOLDS: redirection refused loud, victim untouched

完整的 checkout self-heal 套件以及整个被改动测试文件全部通过,确认合法纯目录的 wipe 仍成功(exit 0),而重定向被拒绝(exit 1)。

说明

  • 未做 merge(--conflict false)。
  • 本轮实现了 1 个独立发现(2 条重复的 Critical inline 评论)。没有把任何剩余发现延后到后续 issue,也没有需要维护者决策的事项。

验证

实际运行的命令(结果):

  • npm run build — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run lint — 通过(exit 0)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js(被改动)— 156 通过(1 个文件)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js -t "checkout self-heal"(被改动,聚焦)— 修复后 12 通过 / 0 失败;修复前 1 失败(即新回归测试),证明它钉住了缺陷
  • 复现 probe(提取的 wipe 脚本 + 重定向 fixture)— 修复前:exit 0 且 VICTIM DELETED(缺陷);修复后:exit 1 且 VICTIM SURVIVES(已修复)
  • 对两个被改动文件运行 npx prettier --check — 干净
  • npx eslint scripts/tests/qwen-pr-review-workflow.test.js — 干净

未改动任何 settings 源文件,因此无需运行 npm run generate:settings-schema。未触及任何需打包 CLI / 集成行为,因此无需集成测试。

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully. The review pipeline failed before a review could be posted. A transient error is retried automatically; if you are seeing this, retry with @qwen-code /review. See workflow logs.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [review-pr] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [review-pr] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@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.

No blocking issues. LGTM! ✅

Not explored to full depth (tool budget reached): "agent reverse-audit (round 4)": locating the runner's exact github-context→step-process-env translation site that decides whether a $GITHUB_ENV write of GITHUB_WORKSPACE survives into the ne….

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 8, not a blocker) — recorded, not requested in this round:

  • .github/workflows/qwen-code-pr-review.yml:573 — [review] wipe guard now exists as four divergent copies across the pool; manual porting has a documented miss (#9265) — port the containment guard to the siblings or extract a shared wipe scri…
  • scripts/tests/qwen-pr-review-workflow.test.js:2884 — [probe] nonexistent-workspace test comment misattributes the refusing disjunct — realpath fails first for the deep-missing fixture; the claimed [ ! -d ]→[ -f ] mutation is not caught by t…
  • scripts/tests/qwen-pr-review-workflow.test.js:2936 — [probe] R5-1 class (round 5, still standing): round-8 entrances probe-verified — seal scan misses indirect GITHUB_ENV/GITHUB_PATH writes ($(printenv), ${!v}, backticks, script delegation)…
中文说明

无阻断问题。LGTM!✅

未探索到全部深度(达到工具调用预算):"agent reverse-audit (round 4)"locating the runner's exact github-context→step-process-env translation site that decides whether a $GITHUB_ENV write of GITHUB_WORKSPACE survives into the ne…

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 8 轮,非阻断)——已记录,本轮不要求修改:共 3 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.21.13)

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round: no action

Critical-only mode is active for PR #9327 (5 change-producing rounds are complete in this counting window). Every actionable section for this round is empty:

  • Reviews: none
  • Inline comments: none
  • Issue-level comments: none
  • Failed checks: none
  • Still-red checks: none

The only newer feedback is a non-Critical automated-reviewer PR comment, which the workflow's deterministic brake excluded from this round and deferred for human follow-up. Per the Critical-only rules, no code changes were made, no threads were resolved, and no comment replies were written for deferred items.

No commits were made this round; the PR head remains at b7a549e724.

中文说明

PR #9327 已进入 Critical-only 模式(本计数窗口内已完成 5 个产生改动的轮次)。本轮所有可执行区域均为空:

  • Reviews:
  • Inline comments:
  • Issue-level comments:
  • 失败的检查:
  • 持续失败的检查:

本轮唯一更新的反馈是一条来自自动审查器的非 Critical PR 评论,已被工作流的确定性制动机制从本轮排除,延后留待人工跟进。按照 Critical-only 规则,本轮未做任何代码改动、未解析任何线程、也未对延后条目撰写评论回复。

本轮未产生任何提交;PR 分支头仍为 b7a549e724

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete. The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

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


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

@yiliang114 yiliang114 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.

Approved. The R6-1 Critical (wipe guard only inspects the final path component) is addressed at the head: the guard now validates realpath -- "$WS" against $WS plus the -L/-d checks, matching the suggested fix exactly. CI green on the head (Test, secret scan, CVE audit, Classify PR). The remaining open threads are Suggestion-level (test-pin coverage, comment accuracy) and non-blocking.

@wenshao
wenshao added this pull request to the merge queue Aug 19, 2026
Merged via the queue into QwenLM:main with commit bc2d205 Aug 19, 2026
57 checks passed

@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.

Approved. CI-infrastructure-only change (2 files, +158/-298); reviewed at b7a549e7245f491a8bda7fd4b6c4214d13b05a39 against base d02e252d41.

Verified by execution, not by reading

  • Ran the suite in an isolated detached worktree at the head: npx vitest run --config ./scripts/tests/vitest.config.ts qwen-pr-review-workflow.test.js155 passed, 1 failed (156).
  • The single failure is fallback comment resilience (PR #8894 incident class) > repairs a single unwritable directory instead of failing fast. I re-ran that same test on the base d02e252d41 and it fails identically there. So it is pre-existing and untouched by this diff, exactly as the PR body discloses — not a regression introduced here.

Guard ordering traced literally at the reviewed commit

WS="${GITHUB_WORKSPACE:?}" (yml 571) runs first, then the refusal at yml 572-575 — [ "$(realpath -- "$WS")" != "$WS" ] || [ -L "$WS" ] || [ ! -d "$WS" ]::error:: + exit 1 — lands before both wipe legs and before the sudo -n leg (yml 576). A workspace redirected through a symlinked intermediate component, a non-directory, or a nonexistent path therefore cannot reach the destructive command, and the sudo leg (the pool's only root-deletion power) only ever operates on a validated plain directory. The step carries no continue-on-error, so both deliberate nonzero exits fail the job loud rather than degrading to a log annotation.

The claimed-surviving behaviors are pinned by tests that actually executed

The pool wipe idiom including hidden entries, the sudo fallback leg with its exact argv, the never-fail exit contract with survivors named in the warning, the identical retry checkout (retry.uses/retry.with compared field-for-field against the first), and the continue-on-error invariants across all three steps — each has a passing test at this commit. seals every override channel into the wipe step is the load-bearing one: with the allowlist gone it enforces the PR's threat-model premise inside the workflow file, checking dangerous env: entries by name class rather than by enumeration, both bare and braced $GITHUB_ENV/$GITHUB_PATH spellings, the legacy ::set-env::/::add-path:: forms, the pre-wipe uses: set, and the shell selection. That is the right shape for this — it closes the channel a string guard inside the script could never reach.

One correction to the PR description (non-blocking, no behavior impact)

The stated test counts are stale relative to the head — they describe an earlier commit, before the review rounds added tests back. Measured at b7a549e7: the suite goes 157 → 156 (not 157 → 151) and the checkout self-heal block goes 13 → 12 (not "now 7 tests"). Net −294 lines is still accurate. Worth correcting so the next reader of this description is not misled about how much test coverage was dropped.

On the removed denylist/allowlist

I did not re-open this. It is a deliberate, argued scope decision already carried in the open threads, and the seal test enforces the premise it rests on. Recording the residual only for the record: the premise is enforced by a test, not by the script, so if that seal is ever weakened, a mangled GITHUB_WORKSPACE becomes reachable again (realpath -- / resolves to itself, so a bare / would pass the object check). The PR body's own note — that a guard belongs back the moment a step that can write the runner env file appears — is the correct trigger condition, and the seal test is what will detect it.

CI: 16 success, 50 skipped, 0 failures. No blockers from me.

中文说明

已批准。纯 CI 基础设施改动(2 个文件,+158/−298);审查基于 b7a549e7245f491a8bda7fd4b6c4214d13b05a39,基线 d02e252d41

执行验证(非仅阅读)

  • 在头提交的隔离 detached worktree 中运行测试套件:155 通过,1 失败(共 156)
  • 唯一失败项为 repairs a single unwritable directory instead of failing fast。我在基线 d02e252d41 上单独重跑该测试,同样失败。因此这是既有失败、与本 diff 无关,与 PR 描述的说明一致,并非本次引入的回归。

守卫顺序(逐行核对)

WS="${GITHUB_WORKSPACE:?}"(yml 571)先执行,随后 yml 572-575 的拒绝分支 —— [ "$(realpath -- "$WS")" != "$WS" ] || [ -L "$WS" ] || [ ! -d "$WS" ]::error:: + exit 1 —— 位于两条 wipe 分支与 sudo -n 分支(yml 576)之前。因此经中间符号链接重定向的 workspace、非目录、不存在的路径都无法触达破坏性命令,sudo 分支(池上唯一的 root 删除权限)只会作用于已校验的普通目录。该步骤没有 continue-on-error,两个故意的非零退出都会让 job 响亮失败。

PR 声称保留的行为均由实际执行通过的测试钉住

含隐藏条目的池 wipe 惯用法、带精确 argv 的 sudo 兜底分支、点名残留项的永不失败退出契约、逐字段比对的一致 retry checkout、三个步骤的 continue-on-error 不变式,在该提交上都有通过的测试。其中 seals every override channel into the wipe step 是承重项:在 allowlist 移除后,它把 PR 的威胁模型前提固化在 workflow 文件内部,按名称类而非枚举检查危险 env: 条目,覆盖 $GITHUB_ENV/$GITHUB_PATH 的裸写与花括号写法、legacy ::set-env::/::add-path::、wipe 前的 uses: 集合以及 shell 选择。这个形状是对的——它封住了脚本内字符串守卫根本触达不到的通道。

对 PR 描述的一处更正(非阻断,不影响行为)

描述中的测试数量相对头提交已过期,反映的是 review 轮次补回测试之前的某个更早提交。在 b7a549e7 上实测:套件总数为 157 → 156(非 157 → 151),checkout self-heal 块为 13 → 12(非"现在 7 个测试")。净 −294 行仍然准确。建议修正,以免后续读者误判被删掉的测试覆盖量。

关于被移除的 denylist/allowlist

我没有重新开启这个议题。这是已在现有讨论线程中充分论证过的有意范围决策,且 seal 测试守住了它所依赖的前提。仅记录残余风险:该前提由测试而非脚本强制,因此一旦该 seal 被削弱,畸变的 GITHUB_WORKSPACE 会重新变得可达(realpath -- / 解析为自身,裸 / 能通过对象检查)。PR 描述自己给出的触发条件——一旦出现能写 runner env 文件的步骤就应把守卫加回——是正确的判断标准,而 seal 测试正是发现它的手段。

CI:16 成功,50 跳过,0 失败。我这边无阻断问题。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.14.

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+)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants