Repository navigation
fix(web-shell): scope artifact actions to owning workspace - #8510
Conversation
Verification reportVerified head: Failure-first evidenceThe original ownership probes failed 3 cases while 29 passed: an ownerless artifact tab read the primary sentinel, a secondary artifact download never called the qualified secondary client, and a secondary durable-task list omitted its The follow-up visual regression was independently reproduced with real Playwright Chromium. Both dark and light scenarios failed at Automated checks at this head
The package-wide format check still reports only five unchanged baseline files: One intermediate full-suite run produced 10 Production two-workspace validationThe built CLI/Web Shell was run with two registered local workspaces containing the same relative sentinel path but different contents.
Visual evidenceAfter the fix, Playwright generated genuine 1366×768 dark and light screenshots. I inspected both images: the right panel renders the full 中文验证报告验证报告验证 head: 失败优先证据最初的所有权探针有 3 个失败、29 个通过:缺少所有者的产物标签错误读取主工作区 sentinel;次工作区产物下载没有调用带工作区限定的次工作区客户端;次工作区持久化任务列表遗漏 后续视觉回归已使用真实 Playwright Chromium 独立复现。深色和浅色场景都在 当前 head 的自动化检查
包级完整格式检查仍只报告 5 个未修改的历史文件: 有一次中间的完整测试出现 10 个 生产双工作区验证构建后的 CLI/Web Shell 使用两个已注册本地工作区运行;两个工作区包含相同相对 sentinel 路径但内容不同。
视觉证据修复后,Playwright 生成了真实的 1366×768 深色和浅色截图。我已检查两张图片:右侧面板完整显示 |
|
@qwen-code /triage |
doudouOUC
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
中文说明
已审查。 建议见行内评论。
— qwen3.7-max via Qwen Code /review (v0.21.4)
Review follow-up verification reportVerified head: Failure-first evidenceThe Critical loading bug was independently reproduced on the reviewed head for all three mutation paths: save, enable/disable, and delete. In each case, a mutation superseded an in-flight reload through the shared request counter and left the panel permanently rendering Review fixes
Automated verificationThe full App run emits existing test-harness 中文验证报告审查跟进验证报告验证 head: 失败优先证据在被审查的 head 上,已分别复现 Critical Loading 问题的 3 条变更路径:保存、启用/禁用、删除。每种情况下,变更操作都会通过共享 request 计数器使进行中的 reload 失效,并让面板永久显示 审查修复
自动化验证完整 App 测试会输出已有测试夹具的 |
|
@qwen-code /takeover |
|
🤝 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 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。本 PR 来自 fork,首轮处理将由下一次定时扫描执行(通常几分钟内)。移除 |
|
🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下: Address-review summary — PR #8510 (round 2)Commit: Triage gate: PR body template (stage 1a, CHANGES_REQUESTED)The triage review asks to restructure the PR body around the repository template ( Round-2 findings
Round-1 findings (re-verified, already fixed by earlier commits)All eleven round-1 inline findings were re-verified against this head and remain resolved by
VerificationCommands actually run this round (all at the final working tree, before the commit; the repository's pre-commit hook also passed during the commit):
中文说明审查处理总结 — PR #8510(第 2 轮)提交: Triage 门禁:PR 正文模板(stage 1a,CHANGES_REQUESTED)Triage 审查要求按仓库模板重组 PR 正文( 第 2 轮发现
第 1 轮发现(重新验证,已由早前提交修复)全部 11 条第 1 轮行内发现已在当前 head 重新验证,确认仍由
验证本轮实际运行的命令(均在最终工作树上、提交前执行;提交时仓库 pre-commit 钩子也已通过):
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/模型 |
|
🤖 AutoFix ran out of time before finishing (timeout (1080000ms)) (attempt 2/100) — it will retry on the next scan. What I found before stopping: See the Qwen Autofix agent step logs for model/tool output. Run log: https://github.com/QwenLM/qwen-code/actions/runs/30978469269 🧠 Handled by Qwen Code · model/模型 |
|
🤖 AutoFix ran out of time before finishing (timeout (1080000ms)) (attempt 3/100) — it will retry on the next scan. What I found before stopping: See the Qwen Autofix agent step logs for model/tool output. Run log: https://github.com/QwenLM/qwen-code/actions/runs/30992285682 🧠 Handled by Qwen Code · model/模型 |
|
🤖 AutoFix stopped: this counting window now contains 3 time-budget exhaustions (pushed rounds in between included; this round itself may have failed differently). That is 3 full agent runs that pushed nothing. A human should split or reduce the PR (or raise the agent time budget AND its step backstop together), then comment What I found before stopping: See the Qwen Autofix agent step logs for model/tool output. Run log: https://github.com/QwenLM/qwen-code/actions/runs/30992591926 🧠 Handled by Qwen Code · model/模型 |
|
⏸️ Takeover paused: this PR reached its round cap (100/100). Comment 中文说明⏸️ 托管已暂停:本 PR 达到轮次上限(100/100)。评论 |
|
@qwen-code /triage |
Independent local verification (real two-workspace daemon + real browser)I rebuilt this scenario locally instead of re-reading the tests: a real Harness (click to expand)
1. The vulnerability is real, and the fix closes it
Note the card in both runs reads Control: on PR head, a primary-workspace session still uses the unqualified 2. The StrictMode follow-up is load-bearing (and effective)
3. Finding — fail-closed also removes preview/download in untrusted workspaces
This is not limited to multi-workspace setups: a single-workspace daemon also advertises the array, so an ordinary untrusted single-workspace deployment loses artifact/review/file previews entirely (verified: One more wrinkle: Suggestion (either is fine, but please pick one before merge):
Severity: medium — 4. Ownership lossWith the secondary artifact tab open on PR head, I restarted the daemon without the secondary workspace. No request was retried against the primary route (the recorded network log contains no unqualified 5. Gates I ran on PR head
6. Smaller notes
VerdictThe core security fix is real and verified end-to-end against a real daemon: opening or downloading a secondary-workspace artifact no longer reads the primary repository. Item 3 (untrusted workspaces losing preview/download, with a misleading message) is what I'd like resolved or explicitly accepted before merge; 6.1 is a cheap robustness win. Everything else looks good. Not verified here: the durable scheduled-task 中文版独立本地验证(真实双工作区 daemon + 真实浏览器)我没有只复核测试,而是在本地重建了这个场景:一个注册了两个工作区的真实 验证环境(点击展开)
1. 漏洞真实存在,修复确实闭合了它
注意两次运行卡片都显示 对照:在 PR head 上,主工作区会话仍走非限定的 2. StrictMode 跟进提交是必要且有效的
3. 发现 —— fail-closed 同时移除了未受信任工作区的预览/下载
这不限于多工作区场景:单工作区 daemon 同样会公告该数组,因此普通的未受信任单工作区部署会完全失去产物/审查/文件预览(已验证: 还有一点: 建议(二选一,但希望合并前明确其一):
严重程度:中 —— 4. 所有权丢失在 PR head 上保持次工作区产物标签页打开,然后不带次工作区重启 daemon。没有任何请求回退重试主工作区路由(重启后的网络记录中没有非限定 5. 我在 PR head 上跑过的检查
6. 其他小问题
结论核心安全修复真实有效,并已针对真实 daemon 端到端验证:打开或下载次工作区产物不再读取主仓库文件。第 3 点(未受信任工作区失去预览/下载,且文案有误导)希望在合并前解决或明确接受;6.1 是低成本的健壮性改进。其余部分看起来没问题。 本次未验证:持久化定时任务的 |




What this PR does
This PR binds artifact previews, downloads, code-review reports, file reviews, and durable scheduled-task actions to the registered workspace that produced each turn output. It carries immutable workspace identity (
workspaceCwdand, when advertised,workspaceId) through primary chat, split panes, nested subagents, and side tasks; secondary file access uses the workspace-qualified daemon client, and scheduled-task operations always use the owning workspace ID.The owner is resolved against the daemon's current capabilities and fails closed after removal, trust loss, duplicate identity, replacement, or remove-and-re-add. A stable authority token preserves valid in-flight work across semantically equivalent capability refreshes and React StrictMode effect replay without allowing an old request to regain access after its owner was revoked.
Why it's needed
Turn outputs from a secondary workspace previously retained or reused primary-workspace action objects. When two repositories had the same relative artifact path, opening or downloading the secondary output could read the primary repository's file, and durable task controls could target the wrong workspace. Passing live actions through nested panes also allowed stale authority to survive workspace removal or runtime replacement.
The first ownership fix exposed a React StrictMode edge case in the repository's real visual scenario: effect cleanup briefly revoked a still-valid owner, so the code-review artifact panel rendered “Workspace artifact owner is no longer available.” The authority-token lifecycle fixes that regression while retaining the original fail-closed security boundary.
Reviewer Test Plan
How to verify
npm test,npm run build,npm run typecheck,npm run lint, andnpm run test:e2e:visuals -- --grep "code review artifact"frompackages/web-shell.Evidence (Before & After)
Before the ownership change, the failure-first route probes produced 3 failures and 29 passes: secondary artifact/file reads and scheduled-task mutations reached primary actions. Before the StrictMode follow-up, the real Playwright visual scenario failed in both dark and light themes at
screenshots.spec.ts:848; the panel showed “Unable to display code review — Workspace artifact owner is no longer available.” The same failure was reproduced locally and in visual workflow run 30879548937.After the change, the focused ownership suites pass 413/413, the complete Web Shell suite passes 2,780/2,780, and the StrictMode visual scenario passes 2/2 with real Chromium screenshots in dark and light themes. The generated local screenshots were visually inspected and show the complete “Authoritative verdict” panel; this environment has no authenticated interactive browser available for uploading those local PNGs, so the repository's visual-preview workflow is the shareable image source for this head.
Production two-workspace validation used primary workspace ID
35f375e336aa5962and secondary workspace ID2162ccb7ea97c9ec. The same relative sentinel path returned distinct SHA-256 values (818d5f…b9127primary,0e9fac…4a12secondary), and file, byte-range, and scheduled-task CRUD requests all used the expected owner route.Tested on
Environment (optional)
macOS arm64; repository Node/npm toolchain; Playwright Chromium 149. Linux behavior is additionally covered by the repository's Ubuntu CI, but was not counted as a local test.
Risk & Scope
TurnOutputOpenRequestwith a retainedworkspaceActionsobject should passworkspaceCwdand, for registered workspaces,workspaceIdinstead. Normal Web Shell consumers require no migration.Linked Issues
Fixes #8494
中文说明
本 PR 做了什么
本 PR 将产物预览、下载、代码审查报告、文件审查和持久化定时任务操作绑定到实际生成对应 turn output 的已注册工作区。它在主聊天、分屏、嵌套子代理和 side task 之间传递不可变的工作区身份(
workspaceCwd,以及 daemon 已公告时的workspaceId);次工作区文件访问使用带工作区限定的 daemon 客户端,定时任务操作始终使用所有者工作区 ID。所有者会依据 daemon 当前 capabilities 重新解析;工作区被移除、失去信任、出现重复身份、被替换,或被移除后重新加入时均会 fail closed。稳定的 authority token 允许语义等价的 capabilities 刷新和 React StrictMode effect 重放期间的合法进行中操作继续完成,同时禁止旧请求在其所有者被撤销后重新获得访问权。
为什么需要它
来自次工作区的 turn output 以前会保留或复用主工作区 action 对象。当两个仓库拥有相同的相对产物路径时,打开或下载次工作区输出可能读取主仓库文件,持久化任务控件也可能操作错误的工作区。在嵌套面板间传递实时 action 还会使过期权限在工作区移除或运行时替换后继续存活。
第一版所有权修复暴露了仓库真实视觉场景中的 React StrictMode 边界情况:effect cleanup 会短暂撤销仍然有效的所有者,使代码审查产物面板显示“Workspace artifact owner is no longer available”。authority-token 生命周期修复了该回归,同时保留原有的 fail-closed 安全边界。
审查者测试计划
如何验证
packages/web-shell目录运行npm test、npm run build、npm run typecheck、npm run lint和npm run test:e2e:visuals -- --grep "code review artifact"。证据(修复前后)
所有权修复前,failure-first 路由探针结果为 3 个失败、29 个通过:次工作区产物/文件读取和定时任务修改会命中主工作区 action。StrictMode 跟进修复前,真实 Playwright 视觉场景的深色和浅色主题都在
screenshots.spec.ts:848失败;面板显示“Unable to display code review — Workspace artifact owner is no longer available”。同一失败已在本地和视觉工作流运行 30879548937中复现。修复后,所有权聚焦测试 413/413 通过,Web Shell 完整测试 2,780/2,780 通过,StrictMode 视觉场景使用真实 Chromium 在深色和浅色主题下 2/2 通过。本地生成的截图已目视检查,完整显示“Authoritative verdict”面板;当前环境没有可用于上传本地 PNG 的已认证交互式浏览器,因此此 head 的可共享图片来源是仓库视觉预览工作流。
生产双工作区验证使用主工作区 ID
35f375e336aa5962和次工作区 ID2162ccb7ea97c9ec。同一相对 sentinel 路径返回不同的 SHA-256(主工作区818d5f…b9127,次工作区0e9fac…4a12),文件、字节区间和定时任务 CRUD 请求均使用预期的所有者路由。测试平台
环境(可选)
macOS arm64;仓库规定的 Node/npm 工具链;Playwright Chromium 149。仓库 Ubuntu CI 也覆盖 Linux 行为,但未计为本地测试。
风险与范围
TurnOutputOpenRequest且保留workspaceActions对象的宿主集成,应改为传递workspaceCwd,并为已注册工作区传递workspaceId。普通 Web Shell 使用方无需迁移。关联 Issue
Fixes #8494