Skip to content

fix(desktop): 按 owner 隔离 main-view 和 settings WebView - #3414

Open
fmfsaisai wants to merge 4 commits into
mainfrom
cindy/webview-guest-cleanup-20260825
Open

fix(desktop): 按 owner 隔离 main-view 和 settings WebView#3414
fmfsaisai wants to merge 4 commits into
mainfrom
cindy/webview-guest-cleanup-20260825

Conversation

@fmfsaisai

@fmfsaisai fmfsaisai commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

这次改了什么

摘要

旧 PR #3370 的方案扩大到了账号与协议时序,因此已关闭。本 PR 按收窄后的目标重做,清理 main-view/settings WebView 与独立 Ghost panel 在 data owner 变化后可能残留的 guest session、DOM 与本地状态。

具体包括:

  • Main 根据当前 mode + dataOwnerId 派生非持久 owner partition,并覆盖 Renderer 提交的 partition claim。协议注册复用同一个 owner 快照;owner 切换完成后,旧 Session 新进入的 cindy-ghost:// 请求会在 URL 路由、body 读取和业务 provider 之前返回 403。
  • main-view 复用既有 owner key 重挂;settings WebView、截图快照和高度缓存按 owner 隔离。
  • attach 时捕获 owner,旧 guest 的手势、导航、预览查询和外链确认在 owner 变化后失效。
  • 新 owner sandbox Session 明确拒绝权限请求、下载和直接网络访问;隐藏逻辑 sandbox 使用同一 owner partition。
  • modedataOwnerId 真变化时同步销毁 visible、hidden、prewarmed 独立 Ghost panel 窗口;保留 detached 偏好、把打开状态置为关闭,不在新 owner 下自动恢复,用户下次主动打开时创建新 Session。
  • 为 lifecycle 单测隔离 owner 持久化与进程锁依赖,不删除或弱化既有断言。

变更类型

  • feat 新功能
  • fix 缺陷修复
  • refactor / perf 重构或性能优化
  • docs / test / chore 文档、测试或工程维护
  • 其他:

范围

  • 关联 Issue / 需求:替代已关闭的 fix(desktop): 按 owner 隔离插件 WebView partition #3370
  • 本 PR 包含:Main owner partition、main-view/settings owner 重挂与缓存分桶、stale guest continuation 防线、sandbox Session fail-closed,以及 owner 真变化时关闭独立 Ghost panel。
  • 明确不包含:切换前已进入 handler 的 host-side protocol 请求 abort/drain;OAuth;账号切换、refresh/retry/invalidate 时序;独立 panel 自动恢复或状态按 owner 分桶;完整跨 owner host-side 隔离。
  • 用户可见变化:data owner 变化后 main-view/settings 会使用新的 WebView guest,不再复用上一 owner 的 session、DOM、截图或测量高度;已打开或预热的独立 Ghost panel 会关闭,用户再次主动打开后使用当前 owner 的新 Session。
  • 是否存在 breaking change:无。未修改 manifest、批准状态、安装布局、凭证或偏好 schema;存量插件无需重装、重新批准或重新配置。

UI 变化

不涉及视觉样式、布局、文案或动效变化;只调整 WebView owner 生命周期。继续沿用 docs/design-rules/DESIGN.md 的 Light/Dark 双模式与语义 token 约束,未新增颜色或单主题分支。

  • 引用的设计规范:docs/design-rules/DESIGN.md 双模式交付要求;本 PR 无视觉改动。

怎么验证的

自动验证

pnpm test:unit:related
结果:通过,apps/desktop related tests 全绿。

pnpm --filter desktop run --if-present typecheck
结果:通过。

pnpm exec vitest run --pool=threads --maxWorkers=1 <10 个 WebView/owner 相关测试文件>
结果:10 files / 139 tests 全部通过。

pnpm exec vitest run --pool=threads --maxWorkers=1 src/main/cindy-brain/runtime/__tests__/electronSandboxAdapter.ownerPartition.test.ts src/main/__tests__/webview-security.test.ts
结果:2 files / 50 tests 全部通过;覆盖 stale Session 新请求 403、请求 body/provider 未触发、同 owner generation 继续可用、当前 owner 静态/能力请求正常,以及切换前已进入 handler 的请求不被取消。

pnpm exec vitest run --pool=threads --maxWorkers=1 src/main/ghost-panel-window/__tests__/controller.test.ts src/main/__tests__/appSessionBoundary.test.ts src/main/__tests__/sessionRuntimeControlWiring.test.ts
结果:3 files / 62 tests 全部通过;覆盖 owner 真变化 hook、same-owner generation 不触发、visible/hidden/prewarmed 独立窗口销毁、detached 保留、reconcile 不自动恢复,以及用户主动打开后创建新 slot。

pnpm exec eslint <16 个本次实现与测试文件>
结果:通过。

pnpm exec eslint apps/desktop/src/main/cindy-brain/runtime/electronSandboxAdapter.ts apps/desktop/src/main/cindy-brain/runtime/__tests__/electronSandboxAdapter.ownerPartition.test.ts
结果:P0 修复涉及的 2 个文件通过。

pnpm exec eslint src/main/ghost-panel-window/__tests__/controller.test.ts src/main/__tests__/sessionRuntimeControlWiring.test.ts
结果:P2 新增/修改测试通过;生产文件已执行 eslint --fix。latest main 的 bootstrap/controller 全文件检查仍会报告 8 个既有 unused import/variable,不是本次新增。

git diff --check
结果:通过。

pnpm check:dco
结果:通过,真实范围 3 个功能提交均签名,1 个同步 main 的 merge commit 按检查器豁免且同样带 Signed-off-by;author/committer 一致。

本地还额外运行了完整 pnpm test:unit。它在当前 macOS 环境中未全绿:codexExecFunctionAdapter.e2e.test.ts 第 329 行期望 completed commandExecution,实际 completed items 只有 userMessageagentMessage。该失败已在完全干净的最新 origin/main 8c53ec069 和原始 #3256 合并提交 bffe68140 上同样复现,不是本 PR 引入。GitHub CI 仍会在 Linux/Windows 运行完整单测;这里不声称完整 test:unit 通过。

手工验证

Tester 已对同步前的同一收窄 diff 完成真实 Electron 回归:

  • 冷启动 1 次。
  • WebView attach 9 次。
  • FAIL=0
  • 当前范围 BLOCKED=0

已用普通 merge 同步到 origin/main c0810adc3,无冲突;本次还新增了独立 panel 关闭行为,因此没有伪称同步或 P2 修复后重新跑过该 E2E。

未执行的验证

  • 未在同步 latest main 及加入独立 panel 关闭行为后重复执行真实 Electron E2E;原因见上。
  • 未做 Light/Dark 实机目检;本 PR 无视觉样式改动。

风险

风险分类

  • 无已知风险
  • SQLite / migration
  • system prompt
  • 协议兼容
  • 权限 / 安全 / 用户数据
  • 存量插件兼容(批准状态 / 指纹 / manifest 校验 / 安装布局 / 包格式)
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:

影响与回滚

  • 影响范围:Desktop 插件 main-view/settings WebView 的 owner partition、attach、旧 guest continuation,以及 data owner 真变化时独立 Ghost panel 的关闭。
  • 存量插件影响:无。已装、已批准、已启用插件继续使用,且无需重装、重批或重配。
  • 已知边界:旧 v1 无 owner settings 快照不再读取,但不会在本 PR 中主动擦除旧 localStorage 字节;本 PR 会拒绝 owner 切换完成后新进入旧 Session handler 的请求,但不取消或排空切换前已经进入 handler 的请求。独立 panel 只关闭且不自动恢复,也不把窗口状态按 owner 分桶。
  • 回滚 / 降级方式:回滚本提交可恢复原 WebView partition 与缓存行为,不涉及数据 migration。
  • 合并硬门:本 PR 命中插件基座白名单确认门,必须由指定放行人明确 Approve;自动化 review 不能替代该批准。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s,见 DCO
  • UI 改动已在「UI 变化」注明引用的设计规范(不涉及 UI 则跳过)
  • 未提交凭证、令牌或授权文件
  • 已补充必要文档
  • 已确认测试结果或说明未执行原因

Signed-off-by: fmfsaisai <fmfsaisai@gmail.com>
@fmfsaisai
fmfsaisai requested a review from a team as a code owner August 25, 2026 13:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b746f44bc9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/desktop/src/main/cindy-brain/runtime/electronSandboxAdapter.ts Outdated
@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 将 main-view 与 settings WebView 的 Electron Session、Renderer 生命周期及本地缓存按 data owner 隔离,并在 owner 切换后阻止旧 guest 的后续操作。

  • Main 进程根据权威 owner 快照生成非持久 partition,并覆盖 Renderer 提交的 partition claim。
  • owner-scoped Session 默认拒绝权限、下载和直接网络访问,旧 Session 的新协议请求返回 403。
  • settings WebView、截图快照及高度缓存按 owner 分桶,owner 变化时强制重挂。
  • 外链、预览、手势和导航操作在异步副作用前重新校验 attach 时捕获的 owner。
  • owner commit 时关闭独立插件面板窗口,避免旧窗口跨 owner 保留。

Confidence Score: 5/5

当前证据表明本 PR 可以安全合并,未发现仍需阻止合并的具体故障。

未发现仍然存在的阻塞性故障。

Important Files Changed

Filename Overview
apps/desktop/src/main/cindy-brain/ghostWebviewPartition.ts 新增 Main 权威的 owner-scoped partition 派生与 Renderer claim 解析,非法或无 owner 状态均 fail-closed。
apps/desktop/src/main/cindy-brain/runtime/electronSandboxAdapter.ts 将协议注册绑定到 owner partition,并对失效 owner、权限、下载和直接网络访问实施拒绝策略。
apps/desktop/src/main/webview-security.ts attach 时覆盖实际 Electron partition,捕获 owner,并为旧 guest 的手势和导航安装失效检查。
apps/desktop/src/renderer/cindy-brain/GhostSettingsWebview.tsx settings WebView 按 owner 重挂,并使截图与高度状态使用 owner 作用域且阻止卸载后的异步写入。
apps/desktop/src/renderer/cindy-brain/ghostSettingsSnapshot.ts settings 快照升级为 owner 分桶的 v2 key,并停止读取旧的无 owner 快照。
apps/desktop/src/main/cindy-brain/ghostExternalLinkNavigation.ts 外链确认和打开操作在各异步边界前后验证捕获的 owner,避免旧 guest 在切换后继续执行。
apps/desktop/src/main/cindy-brain/ghostPreviewNavigation.ts 预览查询在 provider 调用前后验证 owner 与 WebContents 状态,避免旧结果推送给新 owner。
apps/desktop/src/main/ghost-panel-window/controller.ts owner commit 时销毁独立插件窗口并清除 lastOpen,同时保留 detached 偏好。

Sequence Diagram

sequenceDiagram
  participant R as Renderer
  participant M as Electron Main
  participant S as Owner Session
  participant G as WebView Guest
  R->>M: 提交 ghost partition claim
  M->>M: 读取当前 mode + dataOwnerId
  M->>S: 创建或复用 owner-scoped partition
  M->>M: 覆盖 Renderer partition claim
  M->>G: 核准 attach 并捕获 owner
  G->>S: 请求 cindy-ghost:// 资源
  S->>S: 校验当前 owner 与协议作用域
  alt owner 仍有效
    S-->>G: 返回插件资源
  else owner 已变化
    S-->>G: 403
    M->>G: 拒绝旧 guest 导航及异步副作用
  end
Loading

Reviews (3): Last reviewed commit: "fix(desktop): close Ghost panels on owne..." | Re-trigger Greptile

@MagicLizi

Copy link
Copy Markdown
Contributor

@fmfsaisai 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/main/cindy-brain/runtime/electronSandboxAdapter.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@MagicLizi MagicLizi added touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:plugin-base 改动碰到插件基座(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:security 改动碰到安全边界(review-pr 自动维护,仅展示) awaiting-discussion 等待维护者讨论(review-pr) labels Aug 25, 2026
@MagicLizi

Copy link
Copy Markdown
Contributor

这个 PR 改到了 Ghost WebView 的 owner 隔离,同时碰到产品 UI、安全敏感路径和插件基座,已进入维护者确认。

请维护者直接在本 PR 上 Approve;若要改,Request Changes 即可,作者改完后再 Approve。讨论记录在 #3415

@MagicLizi

Copy link
Copy Markdown
Contributor

命中 UI 路径(apps/desktop/src/renderer/cindy-brain/GhostSettingsWebview.tsx / apps/desktop/src/renderer/cindy-brain/ghostPanels.tsx / apps/desktop/src/renderer/cindy-brain/ghostSettingsSnapshot.ts)但 description 未附界面效果证据——建议补充改动后效果:截图/录屏,或改动后界面的 HTML 页面(```html 代码块、.html 附件或在线预览链接),便于确认界面符合 DESIGN.md 设计规范

Signed-off-by: fmfsaisai <fmfsaisai@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63e482169a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// owner B 提交后,owner A 的旧 guest 仍可能短暂存活并新发请求。
// 在 URL 路由、body 读取和任何 provider 调用前拒绝旧 Session;已经
// 进入 handler 的请求不在这里取消或排空。
if (!isGhostProtocolOwnerActive(owner)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 在异步协议操作后重新校验 owner

当前校验只发生在进入 protocol handler 时;如果 A 的 /secrets/oauth/connections 请求先通过这里,随后在 readBodyText()、GH CLI 探测、OAuth 流程或确认弹窗的 await 期间切换到 B,后续 storeGhostSecret 等调用会按全局当前 owner 解析并读写 B 的存储。与已有评论所述“切换后新发请求”不同,新的证据是这里明确允许已进入 handler 的请求继续执行,而这些端点存在跨 owner 切换窗口的异步副作用;应在每个异步继续点及最终读写前重验捕获的 owner,或把捕获的 owner 显式传入存储层。

AGENTS.md reference: AGENTS.md:L30-L31

Useful? React with 👍 / 👎.

Comment on lines +192 to +193
params.partition = resolved.partition;
webPreferences.partition = resolved.partition;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 切换 owner 时重建独立插件面板

把 guest 固定到 attach 时的 owner partition 后,已打开或隐藏复用的独立插件面板在账号切换时不会自动获得新分区:轻量 ghost-panel-window-entry.tsx 没有 AuthProvider,而 GhostPanelWindowsController.reconcile() 对 B 中仍存在且可分离的同 id 插件直接保留原 BrowserWindow。因此旧 guest 会继续绑定 A,新的协议守卫持续返回 403,面板直到用户合并、重新分离或重启应用前都不可用;owner commit 时应通过现有 controller 销毁并按新 owner 重建这些窗口。

AGENTS.md reference: AGENTS.md:L32-L35

Useful? React with 👍 / 👎.

…leanup-20260825

Signed-off-by: fmfsaisai <fmfsaisai@gmail.com>
Signed-off-by: fmfsaisai <fmfsaisai@gmail.com>
@MagicLizi MagicLizi added status:awaiting-bot-review 等外部审查机器人表态(review-pr 自动维护,仅展示) and removed awaiting-discussion 等待维护者讨论(review-pr) labels Aug 25, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6de8282808

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const { windows } = this.deps.settings.read();
this.destroyAllWindows();
for (const [ghostId, entry] of Object.entries(windows)) {
if (entry.lastOpen) this.deps.settings.patchEntry(ghostId, { lastOpen: false });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 切换 owner 时同步清除 detached 状态

当 A 有一个已抽离面板且 B 也安装了同 id 插件时,这里销毁窗口后只把 lastOpen 改为 false,却保留了进程级共享的 detached: true;B 的 reconcile() 会因插件仍可抽离而保留该条目,LayoutRoot 又会持续过滤所有 detached 面板。仓库搜索显示重新设为 detached 的唯一入口位于已经被隐藏的 GhostPanel 内,因此 B 既看不到停靠面板,也没有独立窗口或恢复入口,只能重启客户端;owner 切换时应同时清除 detached,或为新 owner 重建可访问的窗口状态。

Useful? React with 👍 / 👎.

@MagicLizi

Copy link
Copy Markdown
Contributor

@fmfsaisai 👋 这个 PR 还有 3 条 review conversation 没 resolve(apps/desktop/src/main/cindy-brain/runtime/electronSandboxAdapter.ts / apps/desktop/src/main/webview-security.ts / apps/desktop/src/main/ghost-panel-window/controller.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

@MagicLizi MagicLizi removed the status:awaiting-bot-review 等外部审查机器人表态(review-pr 自动维护,仅展示) label Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:plugin-base 改动碰到插件基座(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:security 改动碰到安全边界(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants