Skip to content

fix(desktop): allow trusted response copy - #8587

Closed
EthDing wants to merge 1 commit into
QwenLM:mainfrom
EthDing:fix/desktop-copy-response
Closed

fix(desktop): allow trusted response copy#8587
EthDing wants to merge 1 commit into
QwenLM:mainfrom
EthDing:fix/desktop-copy-response

Conversation

@EthDing

@EthDing EthDing commented Aug 5, 2026

Copy link
Copy Markdown

What this PR does

Allows the Desktop app renderer to request clipboard-sanitized-write from the default Electron session while keeping clipboard reads and unrelated permissions denied. The grant is limited to a registered workspace window, its top-level frame, and the trusted packaged or configured Vite renderer origin. Failed response-copy attempts now show a localized failure state on the copy action instead of failing only in the console.

Why it is needed

The response copy button calls navigator.clipboard.writeText(), but the default-session handlers currently deny every non-voice permission. Chromium therefore rejects the clipboard write before the response reaches the system clipboard.

Reviewer Test Plan

How to verify

  1. On Qwen Code Desktop for Windows, open a conversation containing an assistant response.
  2. Click the copy action below the response and paste into a text editor. Confirm the complete response is pasted and the action briefly shows the copied state.
  3. Deny or stub the Clipboard API and confirm the action briefly shows the localized copy-failed state.
  4. Run the focused policy and copy tests:
    • cd packages/desktop/apps/electron && bun test src/main/__tests__/default-session-permissions.test.ts
    • cd packages/desktop/packages/ui && bun test src/components/chat/__tests__/copy-response.test.ts

The policy tests confirm that clipboard read, subframes, unregistered windows, external origins, mismatched dev origins, and unrelated permissions remain denied.

Evidence (Before & After)

Before: clicking the response copy action leaves the Windows clipboard unchanged because clipboard-sanitized-write is denied; failures are console-only.

After: the trusted top-level Desktop renderer can write the complete response, and a rejected write produces a visible localized failure state. Runtime Windows verification is still requested because this environment only provided Linux desktop access.

Tested on

OS Status
🍏 macOS ⚠️ not tested
🪟 Windows ⚠️ not tested
🐧 Linux ✅ unit/type/build tested

Environment (optional)

Ubuntu 26.04. Verified 9 permission-policy tests and 2 copy-behavior tests, Electron and shared UI TypeScript checks, Electron main-process bundling, renderer production build, and git diff --check. A live Linux Clipboard API probe was inconclusive because the automated Electron document could not acquire desktop focus.

Risk & Scope

  • Main risk or tradeoff: Clipboard write is newly available to the trusted main renderer; the policy deliberately requires the registered top-level app frame and trusted renderer URL.
  • Not validated / out of scope: Live Windows Electron verification; clipboard read; the ACP /copy command.
  • Breaking changes / migration notes: None.

Linked Issues

Fixes #8538

中文说明

本 PR 做了什么

允许 Desktop 应用 renderer 向 Electron 默认会话请求 clipboard-sanitized-write,同时继续拒绝剪贴板读取和其他无关权限。该授权仅适用于已登记工作区窗口的顶层 frame,以及可信的打包页面或已配置的 Vite renderer 来源。回复复制失败时,复制操作现在会显示本地化失败状态,而不再只在控制台中静默失败。

为什么需要

回复复制按钮调用 navigator.clipboard.writeText(),但默认会话权限处理器目前拒绝所有非语音权限,因此 Chromium 会在内容写入系统剪贴板前拒绝请求。

审阅者测试计划

如何验证

  1. 在 Windows 的 Qwen Code Desktop 中打开一段包含助手回复的对话。
  2. 点击回复下方的复制操作并粘贴到文本编辑器,确认完整回复可以粘贴,且操作短暂显示已复制状态。
  3. 拒绝或 stub Clipboard API,确认操作短暂显示本地化的复制失败状态。
  4. 运行针对性的权限策略测试和复制测试:
    • cd packages/desktop/apps/electron && bun test src/main/__tests__/default-session-permissions.test.ts
    • cd packages/desktop/packages/ui && bun test src/components/chat/__tests__/copy-response.test.ts

权限策略测试确认剪贴板读取、子 frame、未登记窗口、外部来源、不匹配的开发来源和其他权限仍被拒绝。

Before 与 After 证据

Before:由于 clipboard-sanitized-write 被拒绝,点击回复复制操作后 Windows 剪贴板保持不变;失败只写入控制台。

After:可信的顶层 Desktop renderer 可以写入完整回复;写入被拒绝时会显示用户可见的本地化失败状态。由于当前环境仅提供 Linux 桌面,仍请审阅者补充 Windows 运行验证。

测试平台

OS 状态
🍏 macOS ⚠️ 未测试
🪟 Windows ⚠️ 未测试
🐧 Linux ✅ 单元、类型和构建验证

环境

Ubuntu 26.04。已验证 9 项权限策略测试、2 项复制行为测试、Electron 与共享 UI TypeScript 检查、Electron 主进程打包、renderer 生产构建和 git diff --check。Linux 上的实时 Clipboard API 探测因自动化 Electron document 无法取得桌面焦点而无法得出结论。

风险与范围

  • 主要风险或取舍:可信主 renderer 新增剪贴板写入能力;策略明确要求已登记的顶层应用 frame 和可信 renderer URL。
  • 未验证或范围外:真实 Windows Electron 验证、剪贴板读取、ACP /copy 命令。
  • 破坏性变更或迁移说明:无。

关联 Issue

Fixes #8538

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Qwen Triage finished — CI landed green on 3e2fa43 and the deferred approval was posted. finalize run

Qwen Triage 已完成 —— 3e2fa43 的 CI 全绿,延迟审批已提交。查看 finalize 运行

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed bug with solid evidence — #8538 reports the Desktop response copy button silently doing nothing on Windows (clipboard unchanged, reproduced across restarts), and the /copy command is not available in Desktop/ACP mode as a workaround. The root cause claim checks out in code: VOICE_PERMISSIONS = new Set(['media', 'audioCapture']), and the default-session request/check handlers deny every permission outside that set — so Chromium rejects navigator.clipboard.writeText() before it reaches the system clipboard.

Direction: aligned — copying an assistant response is a baseline expectation, and clipboard-copy reliability is a recurring fix area in peer agents' changelogs (multiple /copy / copy-on-select clipboard fixes in the claude-code CHANGELOG).

Size: no core paths touched (packages/desktop only). 88 production lines (24 permission policy + 21 handler wiring + 32 TurnCard + 11 copy helper) and 75 test lines — well below every threshold.

Approach: the scope feels right. The fix lands at the root cause (the session permission gate) rather than at one button — this also repairs the ~10 other navigator.clipboard.writeText call sites in the desktop UI that fail for the same reason, while the visible failure-state work stays limited to the TurnCard copy action that #8538 reported. Granting only clipboard-sanitized-write, only for the registered workspace window + top-level frame + the existing isTrustedRendererFrameUrl trust guard (the same one that gates the voice token), keeps clipboard reads and all other permissions denied. Reusing the existing toast.copyFailed i18n key avoids new translation surface.

Risk: no high-risk path matches; no elevated risk signals.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测到的 bug,证据充分 —— #8538 报告 Desktop 回复复制按钮在 Windows 上静默无效(剪贴板不变,重启后仍可复现),且 Desktop/ACP 模式下无法用 /copy 命令替代。根因说法已在代码中核实:VOICE_PERMISSIONS = new Set(['media', 'audioCapture']),默认会话的 request/check 处理器拒绝该集合之外的所有权限,因此 Chromium 在内容到达系统剪贴板之前就拒绝了 navigator.clipboard.writeText()

方向:对齐 —— 复制助手回复是基本预期;剪贴板复制可靠性也是同类产品 changelog 中的常见修复项(claude-code CHANGELOG 中有多条 /copy / copy-on-select 剪贴板修复)。

规模:未触及核心路径(仅 packages/desktop)。88 行生产代码(权限策略 24 + 处理器接线 21 + TurnCard 32 + 复制辅助函数 11)与 75 行测试 —— 远低于所有阈值。

方案:范围合理。修复落在根因(会话权限门)而不是单个按钮 —— 这同时修复了 desktop UI 中约 10 处因同样原因失效的 navigator.clipboard.writeText 调用点;而可见的失败状态改动只限于 #8538 报告的 TurnCard 复制操作。仅授予 clipboard-sanitized-write,且仅限已登记的工作区窗口 + 顶层 frame + 复用现有的 isTrustedRendererFrameUrl 信任守卫(与 voice token 所用的同一个);剪贴板读取和其他权限仍全部拒绝。失败文案复用现有 toast.copyFailed i18n 键,无新增翻译。

风险:高风险路径检测无命中;无升级风险信号。

进入代码审查 🔍

Qwen Code · qwen3.8-max

Reviewed at 3e2fa43e7c682fa56904f2a5b80ff0093776c757 · re-run with @qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

I wrote down my independent proposal before reading the diff — a narrow clipboard-sanitized-write grant scoped to the registered workspace window + main frame + trusted renderer origin, reusing the existing voice-feature trust helper, plus a visible failure state and policy tests. The PR does exactly that, and does it cleanly.

Things I verified against the base tree (not taken from the PR description):

  • Root cause confirmed: VOICE_PERMISSIONS = new Set(['media', 'audioCapture']) and both default-session handlers deny everything else, so navigator.clipboard.writeText() was rejected before reaching the OS clipboard.
  • Trust logic is reused, not duplicated: isTrustedRendererFrameUrl (voice/frame-trust.ts) is the documented trust guard with its own test coverage, already used in index.ts with process.env.VITE_DEV_SERVER_URL — the PR mirrors that exact pattern.
  • Both handlers patched: the grant is wired into setPermissionRequestHandler and setPermissionCheckHandler — both are needed (writeText triggers a permission request; navigator.permissions.query goes through the check handler).
  • The grant is tightly scoped: clipboard-sanitized-write only (reads stay denied), main frame only, registered workspace window only, trusted origin only (file:// packaged or the configured Vite dev origin). That is the same trust posture the voice token gate already accepts — consistent, not a widening.
  • UI side: copied: boolean becomes a three-state copyStatus, both copy-action render sites are updated, XCircle was already imported, and toast.copyFailed already exists in all seven locale files — the "localized failure state" claim checks out with zero new i18n surface.
  • Quiet bonus: the session-level fix also repairs the ~10 other navigator.clipboard.writeText call sites in the desktop UI (code blocks, table export, terminal copy, …) that were failing for the same root cause.

No blockers found.

Testing — the PR's own CI, via API

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

Check Conclusion
Classify PR ✅ success
Desktop Shell (ubuntu-22.04) ✅ 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,失败项排在最前。

Reading this table needs two caveats, both verified in the workflow files:

  • The green Desktop Shell check is not signal for this PR. That job compiles and tests the Tauri crate in packages/desktop-shell; this PR changes the Electron app in packages/desktop, a different package the job's path filter never matches.
  • The pending ubuntu suite does not run this PR's new tests. packages/desktop is excluded from the root npm workspace ("!packages/desktop"), the root ESLint ignores packages/desktop/**, and the only desktop-specific step there (check:desktop-isolation) is a dependency-boundary check this PR doesn't touch. The macOS/Windows test legs are skipped for fork PRs.

Net: no CI job executes the 9 permission-policy + 2 copy tests this PR adds. The author reports they pass on Linux — that is the author's claim, not independently re-run here, and this environment does not run PR-derived code. Even if the whole table lands green, the suite will not have exercised the change.

Sandboxed verification would settle part of this: a maintainer-sponsored @qwen-code /verify (the author has read-only access, so the run carries the pre-execution risk screen and workspace wipe — read its report with the same skepticism as the fork's own logs) can prove A/B that the new permission policy is load-bearing against the base build. But the end-to-end claim — Chromium actually granting the write and the text landing in the system clipboard — needs a real Desktop app run on Windows, the platform where #8538 was reported; no automated lane here can drive that. Whoever merges should walk the PR's own test plan first.

中文说明

代码审查

在看 diff 之前我先写下了自己的独立方案:将 clipboard-sanitized-write 窄授权限定为已登记的工作区窗口 + 顶层 frame + 可信 renderer 来源,复用 voice 功能已有的信任辅助函数,并补充可见失败状态与策略测试。PR 的实现与此完全一致,而且干净。

以下是在基线代码树中亲自核实过的(不是照抄 PR 描述):

  • 根因确认VOICE_PERMISSIONS = new Set(['media', 'audioCapture']),默认会话的两个处理器拒绝其余所有权限,因此 navigator.clipboard.writeText() 在到达系统剪贴板之前就被拒绝。
  • 信任逻辑是复用而非复制isTrustedRendererFrameUrl(voice/frame-trust.ts)是有独立测试覆盖的既有信任守卫,index.ts 已用 process.env.VITE_DEV_SERVER_URL 配合使用——PR 沿用了完全相同的模式。
  • 两个处理器都接入了:授权同时接入 setPermissionRequestHandlersetPermissionCheckHandler——两者都需要(writeText 触发权限请求,navigator.permissions.query 走 check 处理器)。
  • 授权范围收得很紧:仅 clipboard-sanitized-write(读取仍被拒绝)、仅顶层 frame、仅已登记工作区窗口、仅可信来源(打包 file:// 或已配置的 Vite dev origin)。这与 voice token 门已有的信任姿态一致——不是放宽。
  • UI 侧copied: boolean 变为三态 copyStatus,两处复制操作渲染点都已更新;XCircle 已在导入中,toast.copyFailed 已存在于全部 7 个语言文件——"本地化失败状态"属实,且零新增 i18n。
  • 附带收益:会话级修复同时修复了 desktop UI 中约 10 处因同一根因失效的 navigator.clipboard.writeText 调用点(代码块、表格导出、终端复制等)。

未发现阻塞问题。

测试证据

CI 表格见上(finalize 任务会在 CI 结束后原地更新)。两点必须说明(均已核对 workflow 文件):

  • 绿色的 Desktop Shell 检查对本 PR 不是信号:该任务编译测试的是 packages/desktop-shell 的 Tauri crate;本 PR 修改的是 packages/desktop 的 Electron 应用,不在该任务的路径过滤范围内。
  • 待定格的 ubuntu 套件不会运行本 PR 新增的测试packages/desktop 被排除在根 npm workspace 之外("!packages/desktop"),根 ESLint 忽略 packages/desktop/**,其中唯一的 desktop 相关步骤(check:desktop-isolation)是依赖边界检查,本 PR 未触及。macOS/Windows 测试腿对 fork PR 跳过。

结论:没有任何 CI 任务会执行本 PR 新增的 9 项权限策略测试 + 2 项复制测试。 作者报告这些测试在 Linux 上通过——这是作者自述,本审查未独立复跑(此环境不执行 PR 代码)。即使表格全绿,套件也并未真正验证该改动。

沙盒验证可以解决其中一部分:维护者可以发起 @qwen-code /verify 赞助运行(作者仅有只读权限,该运行带执行前风险筛查与工作区清理——请对其报告保持与 fork CI 日志同等的审慎),A/B 证明新权限策略相对基线是承重的。但端到端结论——Chromium 实际放行写入、文本真正进入系统剪贴板——需要在 #8538 报告的 Windows 上真实运行 Desktop 应用,这里没有任何自动化通道可以做到。合入前请先按 PR 自带的测试计划走一遍。

Qwen Code · qwen3.8-max

Reviewed at 3e2fa43e7c682fa56904f2a5b80ff0093776c757 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — a clean, minimal fix for a real reproduced bug; my two reservations are about the verification infrastructure around it, not about the code.

This is the PR I would have written for #8538. Before reading the diff I'd sketched the same shape: grant clipboard-sanitized-write narrowly — registered workspace window, main frame, trusted renderer origin — reuse the existing trust guard instead of inventing a new one, and surface the failure instead of logging it. The implementation matches that baseline point for point, and the root cause it claims checked out in the base tree (VOICE_PERMISSIONS admits only media/audioCapture; everything else is denied in both handlers). Every line in the diff serves the stated goal — no drive-by edits, no scope creep — and the failure state lands without a single new i18n key or import. Six months from now this reads like the obvious fix, which is the best thing a 163-line bugfix can be.

What keeps this at 4 rather than 5, named plainly:

  1. No CI job runs the tests this PR adds. packages/desktop sits outside the root npm workspace and root ESLint, and the green Desktop Shell check covers a different package. When the table below lands green, it will prove the surrounding repo is healthy — not that this change works. That's a standing repo gap, not this author's fault, but it means the merge decision leans on review + manual verification.
  2. Nobody has watched this work end-to-end on Windows yet — the platform the bug was reported on. The author was transparent about that (Linux-only environment). A maintainer should walk the PR's test plan before merging, and a sponsored @qwen-code /verify can add the A/B load-bearing proof in the meantime (details in my review comment above).

Verdict: approve. CI is still running on this commit, though, so approval is deferred until CI lands green on 3e2fa43e7c682fa56904f2a5b80ff0093776c757; the finalize job will post it then, pinned to that commit. If anything lands red, it will flag it instead.

中文说明

Confidence: 4/5 —— 对一个真实且可复现的 bug 来说,这是干净、最小的修复;两点保留意见针对的是它周围的验证基础设施,而不是代码本身。

这正是我为 #8538 会写出的 PR。读 diff 之前我勾勒过相同的方案:窄授权 clipboard-sanitized-write —— 已登记工作区窗口、顶层 frame、可信 renderer 来源 —— 复用既有信任守卫而不是新造一个,并把失败状态呈现给用户而不是只打日志。实现与该基线逐点吻合,其声称的根因也在基线代码树中核实成立(VOICE_PERMISSIONS 只放行 media/audioCapture,其余权限在两个处理器中都被拒绝)。diff 中每一行都服务于既定目标 —— 没有顺手改动,没有范围扩张 —— 失败状态的引入甚至没有新增任何 i18n 键或导入。半年后再看,这读起来就是显而易见的修复 —— 这是 163 行 bugfix 最好的状态。

为什么是 4 而不是 5,直说:

  1. 没有任何 CI 任务会运行本 PR 新增的测试。 packages/desktop 不在根 npm workspace 与根 ESLint 范围内,绿色的 Desktop Shell 检查覆盖的是另一个包。等 CI 表格全绿时,它证明的是周边仓库健康 —— 而不是这个改动有效。这是仓库既有的覆盖缺口,不是作者的问题,但意味着合入决定要依赖审查 + 人工验证。
  2. 还没有人在 Windows 上端到端看到它生效 —— 那正是 bug 上报的平台。作者对此是坦诚的(仅有 Linux 环境)。合入前请维护者按 PR 自带的测试计划走一遍;在此期间,赞助运行 @qwen-code /verify 可以补充 A/B 承重证明(详见上面的审查评论)。

结论:approve。但该 commit 的 CI 仍在运行,因此批准将推迟到 CI 在该 commit 上全绿之后;finalize 任务届时会提交绑定该 commit 的批准。若有检查变红,则会改为标记提示。

Qwen Code · qwen3.8-max

Reviewed at 3e2fa43e7c682fa56904f2a5b80ff0093776c757 · re-run with @qwen-code /triage

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship — CI landed green after the review. ✅

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

Comment on lines +476 to +478
if (canWriteClipboard(wc, permission, details)) {
callback(true)
return

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.

[Suggestion] The default-session handler wiring — both setPermissionRequestHandler and setPermissionCheckHandler delegating to canWriteClipboard before the non-voice deny path — has no test; only the extracted pure policy function canUseDefaultSessionClipboard is unit-tested. — Failure scenario: a future refactor that deletes or reorders either early return (or drops the check handler's while keeping the request handler's) lets clipboard-sanitized-write fall into the !VOICE_PERMISSIONS.has(permission) deny path — response copying silently fails on Windows again, the exact bug this PR fixes, while both new test files stay green.

Suggested fix: extract the handler decision logic into a testable form (mirroring the frame-trust extraction pattern) and test that a trusted workspace main frame is granted before the voice gate, that the check handler agrees, and that a non-workspace window is denied.

中文说明

默认会话处理器的接线部分——setPermissionRequestHandlersetPermissionCheckHandler 在非语音拒绝路径之前都委托给 canWriteClipboard——没有任何测试;目前只有被提取出来的纯策略函数 canUseDefaultSessionClipboard 有单元测试。失败场景:如果未来重构删除或调换了其中任一提前返回(或只保留了请求处理器的分支而删掉了检查处理器的),clipboard-sanitized-write 就会落入 !VOICE_PERMISSIONS.has(permission) 拒绝路径——回复复制会在 Windows 上再次静默失败(正是本 PR 修复的 bug),而两个新测试文件依然全绿。

建议修复:将处理器决策逻辑提取为可测试的形式(参照 frame-trust 的提取模式),并测试可信的工作区顶层 frame 在语音门之前被授权、检查处理器与请求处理器结论一致、未登记窗口被拒绝。

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

Comment on lines +476 to +478
if (canWriteClipboard(wc, permission, details)) {
callback(true)
return

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.

[Suggestion] The default-session scoping comment above these handlers ("Scope the grant to mic/media only — do NOT broaden the default session to every permission", lines 417-421) is now stale: this diff adds the clipboard-sanitized-write grant beneath it without updating it, so the only written statement of the default-session policy no longer matches the code. — Failure scenario: a maintainer auditing the handlers reads the stale comment and either concludes the clipboard grant is an unreviewed policy violation and removes it (re-breaking response copy), or treats the stale rule as authoritative and rejects a future narrow grant consistent with this precedent.

Suggested fix: update the comment alongside the grant — e.g. note that sanitized clipboard writes are likewise scoped to the trusted registered main-frame renderer (see canUseDefaultSessionClipboard) while every other default-session permission stays denied.

中文说明

这两个处理器上方的默认会话授权范围注释("Scope the grant to mic/media only — do NOT broaden the default session to every permission",第 417-421 行)现已过时:本 diff 在其下方新增了 clipboard-sanitized-write 授权却没有更新该注释,导致默认会话策略的唯一书面声明与代码不再一致。失败场景:维护者审计处理器时读到这条过时注释,要么认为剪贴板授权是未经审查的策略违规而将其移除(再次破坏回复复制),要么把过时的规则当作权威,拒绝未来与本先例一致的窄授权。

建议修复:在添加授权的同时更新注释——例如说明净化剪贴板写入同样限定于可信的已登记顶层 renderer frame(见 canUseDefaultSessionClipboard),其他所有默认会话权限仍保持拒绝。

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

});

it.each([
['clipboard reads', { permission: 'clipboard-read' }],

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.

[Suggestion] The rejection matrix never pins the distinction between clipboard-sanitized-write and the unsanitized clipboard-write, so any mutation broadening the permission comparison survives the suite. Probe-verified during this review: applying permission === 'clipboard-sanitized-write' || permission === 'clipboard-write' keeps 9/9 tests green while granting the raw write permission; adding the row below catches the mutation. — Failure scenario: a one-line broadening grants the renderer the raw, unsanitized pasteboard-write permission, and every current test still passes — the sanitized variant was chosen precisely to avoid that grant, but the suite does not encode it.

Suggested change
['clipboard reads', { permission: 'clipboard-read' }],
['clipboard reads', { permission: 'clipboard-read' }],
['unsanitized clipboard writes', { permission: 'clipboard-write' }],
中文说明

拒绝矩阵没有钉住 clipboard-sanitized-write 与未净化的 clipboard-write 之间的区别,因此任何放宽权限比较的变异都能通过整个测试套件。本次审查中已用探针验证:应用 permission === 'clipboard-sanitized-write' || permission === 'clipboard-write' 变异后,9/9 测试仍然全绿,但实际上已授予了原始写入权限;加上下面这一行即可捕获该变异。失败场景:一行放宽就会让 renderer 获得未净化的原始粘贴板写入权限,而现有测试全部通过——选择净化变体正是为了避免这种授权,但测试套件没有把它固定下来。

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

Comment on lines +1 to +2
import { describe, expect, it } from 'bun:test';
import { canUseDefaultSessionClipboard } from '../default-session-permissions';

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.

[Suggestion] This new test file is unreachable from every test command this repository runs: packages/desktop is excluded from the npm workspaces ("!packages/desktop" in the root package.json), and no CI workflow in this repo executes the desktop bun suite (verified at the base commit). The test passes when run manually, but nothing in this repo gates the change it covers (also applies to copy-response.test.ts). — Failure scenario: a future commit reverts or breaks the clipboard permission wiring, and response copy silently stops working again — every CI check on this repo stays green because none of them collects this test; it is gated only if the upstream openwork repo's CI happens to run it.

Suggested fix: if desktop validation intentionally lives in the upstream openwork repo, confirm its CI runs this suite; otherwise wire a desktop bun-test job into this repo's CI.

中文说明

这个新测试文件对本仓库运行的所有测试命令都不可达:packages/desktop 被排除在 npm workspaces 之外(根 package.json 中的 "!packages/desktop"),且本仓库没有任何 CI 工作流执行 desktop 的 bun 测试套件(已在 base 提交上核实)。手动运行该测试可以通过,但本仓库没有任何门禁覆盖它所保护的改动(同样适用于 copy-response.test.ts)。失败场景:未来某个提交还原或破坏了剪贴板权限接线,回复复制再次静默失效——本仓库的所有 CI 检查依然全绿,因为没有任何一个会收集这个测试;只有当上游 openwork 仓库的 CI 恰好运行它时才有门禁。

建议修复:如果 desktop 验证有意放在上游 openwork 仓库,请确认其 CI 会运行该套件;否则在本仓库 CI 中接入一个 desktop bun-test 任务。

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

Comment on lines +1 to +2
import { describe, expect, it, mock } from 'bun:test';
import { copyResponseText } from '../copy-response';

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.

[Suggestion] Same unreachability as the permission-policy test: this file sits outside every npm workspace and no CI workflow in this repo runs the desktop bun suite, so the copy-failure status path it covers has no gate in this repository's pipeline (also applies to default-session-permissions.test.ts). — Failure scenario: if copyResponseText regresses — e.g. a refactor rethrows clipboard errors instead of returning { status: 'failed' } — TurnCard's localized copy-failure state disappears and copy clicks surface unhandled rejections, while this repo's CI remains green because nothing here ever executes the test.

Suggested fix: confirm the desktop suite runs in the upstream openwork repo's CI, or add a desktop job here.

中文说明

与权限策略测试相同的不可达问题:该文件位于所有 npm workspaces 之外,本仓库没有任何 CI 工作流运行 desktop 的 bun 套件,因此它所覆盖的复制失败状态路径在本仓库流水线中没有门禁(同样适用于 default-session-permissions.test.ts)。失败场景:如果 copyResponseText 退化——例如重构后重新抛出剪贴板错误而不是返回 { status: 'failed' }——TurnCard 的本地化复制失败状态会消失,复制点击会出现未处理的 rejection,而本仓库 CI 依然全绿,因为这里没有任何环节执行该测试。

建议修复:确认上游 openwork 仓库的 CI 会运行 desktop 套件,或在本仓库添加 desktop 任务。

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

@yiliang114

Copy link
Copy Markdown
Collaborator

Thanks for the contribution, and apologies for the long wait. Closing because the Electron desktop app (packages/desktop) was removed in #9085, so this PR targets code that no longer exists.

The current desktop is a thin Tauri shell around Web Shell. Copy/clipboard behavior now lives in the Web Shell layer — see #9485 for the clipboard work there. If the trusted-response-copy problem still reproduces in the current desktop, please open a new issue against the Web Shell experience and we can re-target the fix.

@yiliang114 yiliang114 closed this Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

copy-response button

3 participants