-
Notifications
You must be signed in to change notification settings - Fork 3k
fix(review): screen content filters before the probe tree's restore too (#9558) #9741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
971494d
a25e8e6
1fe2fae
49ba19a
c06aab3
4c5bff7
c959a08
c137f03
deba877
8cfb0ab
5258b5e
c9cec1e
eb6a46b
1567ea0
7e65377
ad017a8
526575b
832ad51
776e147
377ec3a
4c4eca3
90e1494
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,6 +56,8 @@ import { writeStdoutLine, writeStderrLine } from '../../utils/stdioHelpers.js'; | |
| import { baseWorktreePath } from './lib/paths.js'; | ||
| import { | ||
| discardWorktree, | ||
| INERT_GIT_ARGS, | ||
| localFilterRefusal, | ||
| sanitizedGitEnv, | ||
| worktreeCreateFailureDetail, | ||
| type SweepResult, | ||
|
|
@@ -260,12 +262,44 @@ export function runBaseTree(args: BaseTreeArgs): BaseTreeReport { | |
|
|
||
| // The parameter re-narrows: TS narrowing does not cross function scopes. | ||
| function buildBaseTree(baseSha: string): BaseTreeReport { | ||
| // The creation checkout rewrites every file the base commit carries, which | ||
| // EXECUTES a planted filter — screen it the way the probe tree's creation | ||
| // is screened. The refusal reads as an unavailable A/B (infrastructure), | ||
| // never as a finding against the PR. | ||
| const filterRefusal = localFilterRefusal( | ||
| worktree, | ||
| "the base tree's creation checkout", | ||
| ); | ||
|
Comment on lines
+269
to
+272
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R3-3: Check-then-use race at this call site: the screen reads the common-dir config here, then Failure path: during review of a malicious PR, probes start after fetch-pr's screened creation checkout; while a benign shard builds the base tree, the malicious probe watches the public lock dir and writes Witness (race probe at HEAD, unmodified PR code, concurrent writer process): Re-run 中文说明该调用点存在"先检查后使用"竞态:屏蔽在此读取 common dir 配置,随后 失败路径:审查恶意 PR 时,探针在 fetch-pr 已屏蔽的创建 checkout 之后启动;良性分片构建 base 树期间,恶意探针监视公开的锁目录,在旧 base 树目录消失(清扫完成——在本屏蔽读取之后)的瞬间向 见证(在 HEAD 上用未改动的 PR 代码做竞态探针,并发写者进程):竞态 6/6: 在 — qwen3.8-max via Qwen Code /review (v0.22.0)
Comment on lines
+269
to
+272
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R3-4 (same defect as the fetch-pr.ts comment): the base tree's creation checkout below runs through the local 中文说明R3-4(与 fetch-pr.ts 评论同一缺陷):下方 base 树的创建 checkout 经本地 — qwen3.8-max via Qwen Code /review (v0.22.0) |
||
| if (filterRefusal) return unavailable(filterRefusal); | ||
| let sweep: SweepResult | undefined; | ||
| try { | ||
| // Clear a stale base tree left by a crashed run — it would fail `add`. Its | ||
| // stderr is kept, because it is usually what explains that failure. | ||
| sweep = discardWorktree(worktree, tree); | ||
| git(worktree, 'worktree', 'add', '--detach', tree, baseSha); | ||
| // Re-screen beside the add, after the sweep: this is the only screened | ||
| // checkout that overlaps LIVE probes — the lock excludes other base-tree | ||
| // builders, not shards running attacker code, and the sweep's completion | ||
| // is the public signal a watcher plants on. A filter landing between the | ||
| // screen above and the add below executed in the creation checkout the | ||
| // screen certified clean (measured: 6/6 race iterations pwned); the | ||
| // re-screen narrows that window to the gap between itself and the add. | ||
| const rescreenRefusal = localFilterRefusal( | ||
| worktree, | ||
| "the base tree's creation checkout", | ||
| ); | ||
| if (rescreenRefusal) return unavailable(rescreenRefusal); | ||
| // INERT_GIT_ARGS: the screen reads filters only, while `worktree add` | ||
| // also fires `post-checkout` from the shared common hooks dir and runs | ||
| // a repo-local `core.fsmonitor` — both plantable, both measured live. | ||
| git( | ||
| worktree, | ||
| ...INERT_GIT_ARGS, | ||
| 'worktree', | ||
|
Comment on lines
+294
to
+297
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R11-3: Still stands from round 11 (witness upgraded this round). base-tree's git helpers ( A probe shard does one mkfifo+rename over a baseSha loose object — outside the screen's candidate set, which reads config/info files only; both screens pass, then Witness (this round, probe through the real Fix: bound the helper (or at least the creation/sweep/fast-path spawns) with a checkout-sized ceiling plus killSignal: 'SIGKILL'; the existing catch already converts the kill into 中文说明自第 11 轮起仍然存在(本轮见证升级)。base-tree 的 git 助手(base-tree.ts:99 的 探针分片对 baseSha 松散对象做一次 mkfifo+rename——在屏幕候选集之外(屏幕只读 config/info 文件);两个屏幕都通过,随后 见证(本轮,通过真实 修复:给助手(至少创建/清扫/快路径 spawn)加 checkout 量级的上限 + SIGKILL;请附带 FIFO 松散对象的测试与突变检查。 — qwen3.8-max via Qwen Code /review (v0.22.2)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deferred to the next round (budget-warning round). Fix stands: bound base-tree’s git helpers with a checkout-sized ceiling plus 中文说明顺延到下一轮(预算警告轮)。修复不变:给 base-tree 的 git 助手加 checkout 量级上限与
Comment on lines
+295
to
+297
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R11-3: Still stands at round 15 (from round 11; witness upgraded in round 12, re-traced this round). base-tree's git helpers ( 中文说明R11-3:第 15 轮仍然存在(第 11 轮提出;第 12 轮见证升级,本轮复核)。base-tree 的 git 助手( — qwen3.8-max via Qwen Code /review (v0.22.2)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deferred to the next round (budget-warning round). Fix stands: bound base-tree’s git helpers with a checkout-sized ceiling plus 中文说明顺延到下一轮(预算警告轮)。修复不变:给 base-tree 的 git 助手加 checkout 量级上限与 |
||
| 'add', | ||
|
Comment on lines
+294
to
+298
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R11-3: Still stands from round 11 (base-tree.ts is interaction-only this round; the helpers are unchanged). base-tree's git helpers (gitOut at base-tree.ts:99 and git at :112) carry no timeout/killSignal, and the reuse fast path's gitOut(tree, 'rev-parse', 'HEAD') (~:184) runs BEFORE any screen — a FIFO at /config hangs the process instead of producing the refusal the screen exists for. The creation spawn anchored here (which this diff edited to add INERT_GIT_ARGS) stays on the timeout-less helper, and discardWorktree's worktree remove/unlock spawns between screen1 and screen2 share the shape — an incomplete closure of the unbounded-spawn class this same diff documents ('a screen spawn must still END against a config that blocks in open()'). Failure scenario: A probe (or a prior run's residue — the common dir is never wiped) mkfifos /config; any base-tree run — including the reuse fast path, which has no screen ahead of it at all — blocks in open() on the first config-reading spawn, permanently, with no refusal path; the event loop is blocked so no in-process bound can fire. Witness: Round-11 trace stands; code unchanged at this commit (base-tree.ts:99-110 spawnSync carries only cwd/encoding/env). Suggested fix: Give base-tree's git/gitOut helpers timeout: SCREEN_SPAWN_TIMEOUT_MS, killSignal: 'SIGKILL'; the existing unavailable(...) machinery already converts throws into named refusals. 中文说明第 11 轮提出、仍然成立(base-tree.ts 本轮仅为交互文件,辅助函数未变)。base-tree 的 git 辅助(:99 的 gitOut 与 :112 的 git)不带 timeout/killSignal,而复用快速路径的 gitOut(tree, 'rev-parse', 'HEAD')(~:184)在任何 screen 之前运行——/config 的 FIFO 让进程挂起,而不是产生 screen 本要给出的拒绝。此处锚定的创建 spawn(本 diff 刚加了 INERT_GIT_ARGS)仍跑在无超时的辅助上,screen1 与 screen2 之间 discardWorktree 的 worktree remove/unlock spawn 同形——本 diff 自己文档化的无界 spawn 类别("screen spawn 面对阻塞在 open() 的配置也必须能结束")的不完整闭合。 **失败路径:**探针(或前次运行的残留——common dir 从不清理)把 /config 换成 FIFO;任何 base-tree 运行——包括前面根本没有 screen 的复用快速路径——在第一个读配置的 spawn 上永久阻塞于 open(),无拒绝路径;事件循环被阻塞,进程内界无法触发。 **修复建议:**给 base-tree 的 git/gitOut 辅助加 timeout: SCREEN_SPAWN_TIMEOUT_MS, killSignal: 'SIGKILL';现有 unavailable(...) 机制已把抛错转为命名拒绝。 — qwen3.8-max via Qwen Code /review (v0.22.0)
Comment on lines
+295
to
+298
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R11-3: Still stands at round 16 (from round 11; witness upgraded in round 12, re-traced in round 15). base-tree's git helpers (gitOut :99, git :112) carry no timeout/killSignal; the reuse fast path's rev-parse runs BEFORE any screen, the creation worktree add this diff edited to add INERT_GIT_ARGS stays on the timeout-less helper, and discardWorktree's remove/unlock spawns between screen1 and screen2 share the shape — an incomplete closure of the unbounded-spawn class this same diff documents. Failure scenario: Round-12 probe through real runBaseTree: FIFO'd baseSha loose object → never returned, watchdog SIGKILL at 25s; flip with timeout+SIGKILL → returned after 5092ms available:false ETIMEDOUT. Helpers unchanged at this commit. Witness: round-12 probe through real runBaseTree (quoted in the round-15 re-post): FIFO arm never returned until the 25s watchdog kill; bounded flip returned in 5092ms with available:false. Suggested fix: Bound the helpers (at least the creation/sweep/fast-path spawns) with a checkout-sized ceiling plus killSignal: 'SIGKILL'; the existing catch converts the kill into unavailable(...). Fix witness: please land this with the pinning test — A base-tree.test.ts case FIFO'ing one of baseSha's loose objects must assert a bounded available === false; remove the timeout and the test hangs. 中文说明R11-3:第 16 轮仍然存在(第 11 轮提出;第 12 轮见证升级)。base-tree 的 git 助手无 timeout/killSignal;复用快路径的 rev-parse 先于屏蔽,创建 worktree add 仍在无超时助手上,screen1/screen2 之间的 discardWorktree spawn 同形。第 12 轮探针:FIFO 化松散对象 → 25s 看门狗杀;加超时翻转臂 5092ms 返回 available:false。 — qwen3.8-max via Qwen Code /review (v0.22.2) |
||
| '--detach', | ||
| tree, | ||
| baseSha, | ||
| ); | ||
|
Comment on lines
+294
to
+302
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R11-3: base-tree's git helpers (gitOut ~line 100 and git ~line 113) carry no timeout/killSignal, and the reuse fast path's gitOut(tree, 'rev-parse', 'HEAD') (~line 184) runs BEFORE any screen — a FIFO at /config hangs the process instead of producing the refusal the screen exists for. The creation spawn this diff edits (~here, adding INERT_GIT_ARGS) stays on the timeout-less helper, and discardWorktree's worktree remove/unlock spawns between screen1 and screen2 share the shape — an incomplete closure of the unbounded-spawn class this same diff documents ('a screen spawn must still END against a config that blocks in open()'). Witness: Failure path: shard A builds the base tree (marker written); a concurrent writer mkfifo+renames the common config; shard B's base-tree call reaches the fast path and blocks forever in open() — no refusal note, because the hang precedes every screen. Fix: give both helpers timeout + killSignal: 'SIGKILL' (SCREEN_SPAWN_TIMEOUT_MS for the reads, a larger constant for the checkout/add); the fast path's try/catch already falls through to the rebuild path, whose opening screen then refuses fail-closed. 中文说明R11-6:base-tree 的两个 git 辅助函数(gitOut 约第 100 行、git 约第 113 行)不带 timeout/killSignal,而复用快路径的 gitOut(tree, 'rev-parse', 'HEAD')(约第 184 行)在任何 screen 之前运行——/config 是 FIFO 时进程直接挂起,而不是得到 screen 本应给出的拒绝。本 diff 编辑的创建 spawn(此处,加入 INERT_GIT_ARGS)仍然用无 timeout 的辅助函数,screen1 与 screen2 之间 discardWorktree 的 worktree remove/unlock spawn 同形——这是同一 diff 所记录的无界 spawn 类别的一次不完整闭合。见证:在 common config 为 FIFO 的仓库链接 worktree 中, — qwen3.8-max via Qwen Code /review (v0.22.0)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still open — deferred to the next round. This round was a same-run verification repair: the previous commit was rejected because unrelated full-suite tests failed under CI load, and the round's single commit fixes exactly that rejection (see the round summary). No review-pipeline code changed, so this finding's fix stays queued for the next round's batch. 中文说明仍然打开——顺延至下一轮。本轮是同轮验证修复:上一个提交因与本次改动无关的全套件测试在 CI 负载下失败而被门禁拒绝,本轮的单一提交精确修复该拒绝(见轮次总结)。review 管线代码未变动,该发现的修复继续排入下一轮批次。
Comment on lines
+294
to
+302
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R11-3: Still stands from round 11 (the helpers are unchanged this round; verified at this commit). base-tree's git helpers ( Failure: a FIFO at Fix: give the base-tree helpers 中文说明自第 11 轮起仍然存在(辅助函数本轮未改动;已在本提交上核实)。base-tree 的 git 辅助函数(:99 的 失败场景: 修复:给 base-tree 辅助函数加上 — qwen3.8-max via Qwen Code /review (v0.22.0)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deferred to the next round (budget-warning round). Fix stands: bound base-tree’s git helpers with a checkout-sized ceiling plus 中文说明顺延到下一轮(预算警告轮)。修复不变:给 base-tree 的 git 助手加 checkout 量级上限与 |
||
| } catch (e) { | ||
| return unavailable( | ||
| worktreeCreateFailureDetail('base', e, String(sweep?.stderr ?? '')), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Critical] R3-1 (same defect as the fetch-pr.ts comment): the base tree's creation checkout —
git(worktree, 'worktree', 'add', '--detach', tree, baseSha)below — firespost-checkoutfrom the shared common hooks dir, which the new screen cannot see (it matches onlyfilter.*keys) and this spawn does not disable. Witness and full trace are on the R3-1 comment at fetch-pr.ts:979: a planted common-dir post-checkout FIRED on theworktree addshape (git 2.43) and was suppressed by-c core.hooksPath=/dev/null/no-hooks. Mirror ALL of INERT_GIT_ARGS (hooksPath AND the empty fsmonitor override, per R3-1/R3-4) on this spawn — the localgit()helper needs the overrides at the call site or as a parameter.中文说明
R3-1(与 fetch-pr.ts 评论同一缺陷):base 树的创建 checkout——下方的
git(worktree, 'worktree', 'add', '--detach', tree, baseSha)——会从共享的 common 钩子目录触发post-checkout,新屏蔽看不见它(只匹配filter.*键),该 spawn 也没有禁用钩子。见证与完整追踪见 fetch-pr.ts:979 的 R3-1 评论:植入的 common dir post-checkout 在worktree add形态上触发(git 2.43),被-c core.hooksPath=/dev/null/no-hooks抑制。请把完整的 INERT_GIT_ARGS(hooksPath 与空 fsmonitor 覆盖,见 R3-1/R3-4)同步到该 spawn——本地git()辅助函数需要在调用点或以参数形式带上这些覆盖。— qwen3.8-max via Qwen Code /review (v0.22.0)