Skip to content

feat(browser): add per-start (unauthenticated) proxy server support - #3420

Open
cofyc wants to merge 1 commit into
makecindy:mainfrom
cofyc:feat/browser-proxy-server
Open

feat(browser): add per-start (unauthenticated) proxy server support#3420
cofyc wants to merge 1 commit into
makecindy:mainfrom
cofyc:feat/browser-proxy-server

Conversation

@cofyc

@cofyc cofyc commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

这次改了什么

摘要

为 Cindy Browser 的 start 操作增加可选的 proxyServer,让调用方可以按次选择直连或免密代理出口,同时保留现有安全自动化接口。

范围:仅支持免密代理。 带用户名/密码的 proxyServer 会在解析边界被直接拒绝
(authenticated proxies are not supported)。这是实测后的有意取舍——在 connectOverCDP
架构下,唯一能应答代理挑战的凭据通道会把凭据一并发给任意返回 WWW-Authenticate 的站点
(实测 origin 读到明文凭据),而 allowlist 内的页面内容本就不可信。四条候选方案的实测结论
见评论区;要支持认证代理需要改为由 runtime 自行 launch 浏览器,建议单独一轮。

代理配置由 Desktop 的外置浏览器适配层持有并串行切换:相同路由重复启动保持幂等,路由变化会先停止再重启;代理解析、连接或启动失败时不会回退直连。由于不接受凭据,代理凭据不可能进入 Chrome 参数、工具结果、状态、日志或错误文本。

代理启动额外带 --webrtc-ip-handling-policy=disable_non_proxied_udp,避免页面用 WebRTC 绕过代理暴露本机真实 IP。CDP 守卫身份跟随本次 launch 的真实 profile / 端口(含 Cindy-real 与迁出 18800 的情况)。

变更类型

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

范围

  • 关联 Issue / 需求:无
  • 本 PR 包含:
    • browser MCP schema 与中立请求契约支持 start.proxyServer(免密 URL)
    • 统一的代理 URL 校验、规范化和脱敏;带 userinfo 的 URL 在解析边界拒绝
    • 外置 Chrome 的直连/免密代理生命周期切换与并发串行化
    • 启动期 PAC allowlist 下限(含 dnsResolve 私网闸门,覆盖 WSS / pre-attach)
    • 安全的运行状态和启动结果代理信息(无凭据)
    • 内置 WebView 后端明确拒绝不支持的代理启动
    • 聚焦的 runtime、MCP、Desktop 测试与工作流文档
  • 明确不包含:
    • 认证代理(HTTP/SOCKS userinfo、CDP Fetch.authRequired、Playwright setHTTPCredentials
    • 账号、代理库存或凭据管理
    • 替代 Cindy Browser 的自动化实现
    • 对现有 SSRF 策略的放宽
  • 用户可见变化:Agent 可用 { "action": "start", "proxyServer": "http://host:port" } 启动外置 Cindy Browser;带凭据的 URL 会被拒绝。startstatus 返回脱敏后的有效代理模式。
  • 是否存在 breaking change:无

UI 变化

不涉及。

  • 引用的设计规范:不涉及

怎么验证的

自动验证

pnpm --filter @cindy/browser-control-runtime build
结果:通过

pnpm --filter @cindy/browser-control-runtime test
结果:通过

pnpm --filter @cindy/mcps build
结果:通过

pnpm --filter @cindy/mcps test
结果:通过

pnpm --filter @cindy/browser-control-runtime run --if-present typecheck
pnpm --filter @cindy/mcps run --if-present typecheck
pnpm --filter desktop run --if-present typecheck
结果:通过

pnpm check:dco
结果:通过

GitHub CI(HEAD d53e4a6ea):Linux / Windows unit、DCO、verify 全绿。

手工验证

已验证构建后的 MCP schema 能暴露 proxyServer 字段。未使用生产代理或凭据。

真实端到端验证(已执行,免密代理)

已用真实 Chrome 151 + 本地免密 CONNECT 代理执行端到端验证(macOS,--headless=new,独立 CDP 端口,未触碰本机既有受管浏览器)。

场景 结果
allowlist 内 HTTPS(免密代理) ✅ 通过代理成功,代理日志出现 CONNECT
非 allowlist 主机 ✅ 拒绝:requires an explicit public-hostname allowlist
明文 HTTP ✅ 拒绝:proxied browser navigation requires HTTPS
带凭据的 proxyServer ✅ 拒绝:authenticated proxies are not supported
直连回退 ✅ 未发生
stop stopped: true,路由回到 unknown

缺陷(已修,与认证无关): per-start allowlist 曾把浏览器自己的 loopback CDP 端点拦掉,每次导航都以 browser endpoint blocked by policy 失败。已修(一次性豁免同时满足两个字段),并补回归测试。

验证边界:仅 macOS + Chrome 151 + --headless=new

未执行的验证

  • 认证代理:不在本 PR 范围。曾实测 Playwright context.setHTTPCredentials 能应答 407,但会把代理凭据交给 allowlist 内任意 WWW-Authenticate 站点,该方案已撤回,不得当作现网结论。
  • Playwright 断线重连后的行为(仅代码路径推断)。
  • Windows / Linux 实机代理出口。

风险

风险分类

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

影响与回滚

  • 影响范围:Desktop 外置受管 Chrome 的启动与免密代理出口;内置 WebView 保持原行为,并在收到 proxyServer 时明确拒绝。本 PR 不接受、不存储、不转发代理凭据——带 userinfo 的 URL 在解析边界失败,因此也不会进入 Chrome 参数、Cindy 持久配置、会话数据库或 renderer/device-link。
  • 回滚 / 降级方式:回退本 PR 即恢复原有仅直连启动行为。调用方不传 proxyServer 时仍显式使用 --no-proxy-server
  • 跨平台差异:实现复用 Chromium 启动参数与 PAC;自动测试已覆盖适配层行为,真实代理出口仅在 macOS + Chrome 151 验证过。

提交前检查

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

远程与手机版适配结论

  • SSH 远程工作区:本 PR 不改变远程 agent 或 MCP 暴露。cindy_browser 的外置受管浏览器仍由本机 Desktop host 启动,不读取 workdir 文件;现有远程 Codex 不提供本地 lizi MCP 工具,因此无需 remote-file-service 或 cc-manager 适配。
  • 设备互联远程控制:本 PR 未新增 IPC channel 或 push topic,继续复用现有 Agent 事件和交互通道;不接受代理凭据,因此无需修改 device-link allowlist。
  • 手机版:本 PR 是 Agent 工具接口和被控 Desktop 的浏览器进程能力,不新增客户端 UI。Mobile 继续作为 device-link 控制端查看任务;实际代理启动与出口验证发生在被控 Desktop,因此无需 Mobile 代码改动。

@cofyc
cofyc requested a review from a team as a code owner August 25, 2026 15:12
@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown

Greptile Summary

此 PR 为 Cindy Browser 的单次 start 请求增加可选代理路由,并补充代理解析、凭据脱敏、认证处理和外置 Chrome 生命周期切换。启动期间自动附加页面的认证失败仍存在与成功提交竞争的问题。

  • 扩展 browser runtime 与 MCP 请求契约以支持 proxyServer
  • 在 Desktop 外置 Chrome 后端中串行管理直连、代理切换及停止验证
  • 通过 CDP Fetch 处理 HTTP 代理认证,并在跨进程及持久化边界脱敏凭据
  • WebView 后端明确拒绝不支持的代理启动

Confidence Score: 4/5

此 PR 暂不适合合并,因为启动期间的页面认证失败仍可能在代理路由已被报告成功后才阻断该路由。

自动附加页面事件通过未等待的异步处理运行,而后端在认证协调器启动返回后只检查一次阻断状态,因此失败事件可以越过该检查并让 start 提前成功。

Files Needing Attention: apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts, apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts

Important Files Changed

Filename Overview
apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts 新增 CDP 代理认证与失败关闭逻辑,但自动附加事件未纳入启动等待链。
apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts 新增按路由管理的 Chrome 生命周期和阻断状态;启动提交仍依赖一次可能过早的阻断检查。
packages/browser-control-runtime/src/proxy.ts 集中实现代理 URL 解析、规范化、路由键和脱敏支持。
apps/desktop/src/main/messagePersistBroadcaster.ts 在持久化及非可信边界前对 browser 代理凭据进行脱敏。

Sequence Diagram

sequenceDiagram
    participant B as ExternalChromeBackend
    participant C as ProxyAuthCoordinator
    participant P as Chrome 页面
    B->>C: start()
    C->>C: Target.setAutoAttach
    P-->>C: Target.attachedToTarget
    C-->>C: void handleEvent()
    C-->>B: start() 返回
    B->>B: "检查 routeBlocked=false"
    B-->>B: 提交代理路由并返回成功
    C->>P: Fetch.enable
    P-->>C: 失败
    C->>B: onFailure(),阻断路由
Loading
Prompt To Fix All With AI
### Issue 1
apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts:336
**启动认证失败晚于路由提交**

当带凭据的代理启动期间自动附加新页面且该页面的 `Fetch.enable` 失败时,这里的 `handleEvent` 未被等待,`coordinator.start()` 因此可以先返回,后端随即提交代理路由并让 `start` 返回成功。异步失败随后才阻断路由,导致普通浏览器调用返回 `BROWSER_RUNTIME_UNAVAILABLE`,而 `status` 将刚报告可用的代理改为未知状态。

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (4): Last reviewed commit: "[browser] Add per-start proxy server sup..." | Re-trigger Greptile

@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: 1bb41e6022

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/lizi-mcps/src/browser/tools.ts Outdated
@cofyc
cofyc force-pushed the feat/browser-proxy-server branch from 1bb41e6 to 849754c Compare August 25, 2026 15:37
@cofyc

cofyc commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts Outdated

@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: 849754c994

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts Outdated
Comment thread packages/lizi-mcps/src/browser/tools.ts Outdated
@MagicLizi MagicLizi added touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) labels Aug 25, 2026
@cofyc
cofyc force-pushed the feat/browser-proxy-server branch from 849754c to 4102dd2 Compare August 25, 2026 16:04
@MagicLizi

Copy link
Copy Markdown
Contributor

这条 PR 给 Browser start 加了按次 proxyServer,属于产品能力与核心路径上的大改动,先走维护者确认,暂不合并。

请维护者在本 PR 上 Approve;如果要改,请 Request Changes,作者改完后再 Approve。讨论 issue:#3425

@MagicLizi MagicLizi added the awaiting-discussion 等待维护者讨论(review-pr) label Aug 25, 2026
@cofyc

cofyc commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts Outdated

@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: 4102dd2463

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts Outdated
@cofyc
cofyc force-pushed the feat/browser-proxy-server branch from 4102dd2 to b9940ab Compare August 25, 2026 16:29
@cofyc

cofyc commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts Outdated

@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: b9940ab1b4

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts Outdated
Comment thread packages/browser-control-runtime/src/proxy.ts Outdated
@cofyc
cofyc force-pushed the feat/browser-proxy-server branch from b9940ab to 55f7e62 Compare August 25, 2026 16:55
@cofyc

cofyc commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@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: 55f7e62667

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/maker-ipc/register.ts Outdated
Comment thread packages/lizi-mcps/src/browser/tools.ts Outdated
@MagicLizi MagicLizi added the touches:large-diff 改动量较大(review-pr 自动维护,仅展示) label Aug 25, 2026
@cofyc
cofyc force-pushed the feat/browser-proxy-server branch from 55f7e62 to fbb5b9c Compare August 25, 2026 18:25
@cofyc

cofyc commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@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: fbb5b9c2e3

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/messagePersistBroadcaster.ts Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

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

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

@cofyc
cofyc force-pushed the feat/browser-proxy-server branch from fbb5b9c to 5e6d0e1 Compare August 25, 2026 18:49
@MagicLizi

Copy link
Copy Markdown
Contributor

@cofyc 👋 这个 PR 还有 5 条 review conversation 没 resolve(apps/desktop/src/main/mcp-integrations/browser-managed-config.ts / apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts / packages/browser-control-runtime/src/_generated/extension/src/browser/pw-tools-core.interactions.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

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

@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: 76fe6fe850

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@cofyc 👋 这个 PR 还有 5 条 review conversation 没 resolve(apps/desktop/src/main/mcp-integrations/browser-managed-config.ts / apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts / apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts / packages/browser-control-runtime/src/_generated/extension/src/browser/chrome.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

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

@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: a743fa8bc5

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts Outdated

@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: 0520943c62

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@cofyc 👋 这个 PR 还有 3 条 review conversation 没 resolve(apps/desktop/src/main/mcp-integrations/browser-managed-config.ts / apps/desktop/src/main/mcp-integrations/browser-backend/external-chrome-backend.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

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

@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: 3bcffcf58c

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +126 to +127
`--proxy-server=${proxyServer}`,
`--proxy-pac-url=data:application/x-ns-proxy-autoconfig;base64,${Buffer.from(pac, 'utf8').toString('base64')}`,

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 移除覆盖 PAC 策略的固定代理开关

在 Chromium 将命令行代理配置解析为单一模式的环境中,--proxy-server 的固定代理配置会优先于同时提供的 --proxy-pac-url,因此这里生成的 allowlist PAC 根本不会执行(参见 Chromium 的命令行代理配置文档)。这样在 CDP coordinator attach 之前,持久 profile 恢复的标签页和 service worker 可以访问任意主机;attach 之后,未被 Fetch 拦截的 WebSocket 也会绕过 allowlist。只传 PAC 已足以让 browser-proxy-mode.ts:13-17 判定为显式代理,应避免同时下发互斥的固定代理配置。

Useful? React with 👍 / 👎.

@MagicLizi

Copy link
Copy Markdown
Contributor

@cofyc 👋 这个 PR 目前与 main 有合并冲突,auto-review 因此暂时跳过、没法继续审查 / 合并。

请在本地 merge 最新的 origin/main 解决冲突后推送;冲突解除后,下一轮 auto-review 会自动重新处理这个 PR。

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 29, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T02:12:08.734495Z e9b5449 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 98a41406f0

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +181 to +183
cdpHttpUrl: 'http://127.0.0.1:18800',
managedUserDataDir: process.env.XDT_BROWSER_RUNTIME_DIR
? nodePath.join(process.env.XDT_BROWSER_RUNTIME_DIR, 'browser', MANAGED_PROFILE, 'user-data')

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 为活动 profile 传入真实 CDP 身份

当用户启用“使用我的浏览器登录态”时,运行时实际启动的是 Cindy-real,而且 pickManagedCdpPort() 会在 18800 被占用时选择 18801 等端口;这里却始终让协调器连接 18800 并按 Cindy/user-data 验证进程。因此端口发生迁移时每次代理启动都会在 Chrome 已启动后因无法连接守卫而失败;即使仍使用 18800,协调器断线后的 fresh-CDP/OS fail-closed 清理也会因 profile 身份不匹配而拒绝终止 Cindy-real,使现有页面在 Fetch 守卫消失后继续运行。应让这些值随本次 launch 的实际 profile 和 cdpPort 一起更新,而不是固定为隔离 profile 的身份。

Useful? React with 👍 / 👎.

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

独立审查(heavy,HEAD 98a41406)结论:代理路径上的 lifetime Fetch 门会被 Playwright page.route 挤掉,请修后再审。

  • packages/browser-control-runtime/src/_generated/extension/src/browser/pw-session.ts:1410 / apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.ts:600P1 Chromium 只把 Fetch 交给一个 client。本 PR 已在 MAINTAINING.md §4.1 写明 vendored connectOverCDP + page.route("**") 会抢走该 client。gotoPageWithNavigationGuard 仍在整段 goto 上装 page.route("**")unroute,等于在 Playwright session 上 Fetch.enable / Fetch.disable。coordinator 的 lifetime Fetch.enablehandleAuthRequests: this.hasCredentials)因此在第一次工具导航时被挤掉且不会再武装。之后该页不再跑请求级 HTTPS + allowlist + DNS(isBrowserProxyRequestUrlAllowedAsync 的 rebinding 半边),只剩 PAC 启动底线。PAC dnsResolve 只有 IPv4,allowlist 名字若有公网 A + 私网 AAAA、或之后 IPv6 rebind,不会按 proxy.ts / 注释声称的那样检查。请在 explicit-browser-proxy 模式不要用 Playwright page.route(只让 coordinator 当 Fetch client),或在 unroute 之后重新 Fetch.enable;并加一条组合测试:同一 Chrome 上同时跑 coordinator + gotoPageWithNavigationGuard,断言 goto 之后 requestPaused 仍会触发。

相关单测与 desktop typecheck 通过,security-scan 无新增依赖;不能抵消这条默认 navigate 路径上的策略空洞。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

审查未通过(P1×1)

P1 apps/desktop/src/main/mcp-integrations/browser.ts:181

Proxied start 的 CDP 身份写死为 isolated Cindy / 端口 18800,没有跟随 Cindy-real 或搬迁后的 CDP 端口。ExternalChromeBackendcdpHttpUrl: 'http://127.0.0.1:18800'browser/Cindy/user-data 构造;PAC/extraArgs 会经 applyManagedConfig 落到真实进程,但 Fetch 门、liveness、adopted-close 与 fail-closed 杀进程仍对着 18800 + isolated 目录。

两条产品已支持路径会错位:

  1. 「使用我的浏览器登录态」启动 Cindy-real(18800 占用时还会换端口),lifetime 闸门挂在错误 listener 上。
  2. 18800 已被占用时 coordinator.start('http://127.0.0.1:18800') 可能贴到残留 Chrome 并报告 proxied start 成功,真实窗口只剩 PAC;fail-closed kill 会因 user-data-dir 不匹配拒杀真进程。

请把当前活动 profile 的 CDP URL 和 browser/<activeProfile>/user-data 传入 coordinator;身份无法证明时 fail closed。补测:useRealProfile / pickManagedCdpPortExternalChromeBackend 共用同一 CDP URL 和 user-data-dir。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1×1(独立重审,HEAD 98a4140

  • [P1] apps/desktop/src/main/mcp-integrations/browser.ts:181ExternalChromeBackend 的 CDP 守卫身份写死 http://127.0.0.1:18800browser/Cindy/user-data。开启「使用我的浏览器登录态」时,runtime 实际启动的是 Cindy-real,且 readCopiedLoginsCdpPort 会把端口迁到 18801+。createManagedRuntime 虽把真实 cdpPort 写进 config,coordinator 的 start / 领养关闭 / fail-closed 杀进程仍走构造时那份固定身份(external-chrome-backend.ts 约 405、500、601 行;proxy-auth.tsisManagedChromeProcess 要求 user-data-dir 与 debug port 同时匹配)。结果:端口迁移后代理启动会在 Chrome 起来后因连不上守卫而失败;即便仍在 18800,断线清理也会因 profile 对不上而拒绝终止 Cindy-real,Fetch 守卫消失后页面继续跑。请让这些值随本次 launch 的实际 profile 与 cdpPort 更新。

未把 PAC 与 --proxy-server 并存写成 P1:当前 Chromium ApplyProxyMode 先匹配 --proxy-pac-url。请在修身份时顺手确认受管 Chrome 实机确实在执行 PAC allowlist。

@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: d53e4a6eac

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +544 to +545
} catch (err) {
if (popupError === undefined) popupError = err;

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 Close popups that fail policy validation

When an interaction-created popup navigates to a URL rejected by the proxy/SSRF policy, assertObservedDelayedNavigations reaches assertPageNavigationCompletedSafely, which only quarantines the target and explicitly does not close it, while this catch merely records the error. Because the popup is still within the normal validation budget, none of the overflow close/context/browser teardown runs; the listener then detaches and the denied popup remains alive and executing, especially dangerously in direct mode where there is no lifetime Fetch gate. Close each denied popup with bounded fail-closed teardown before surfacing its error.

Useful? React with 👍 / 👎.

Comment on lines +65 to +69
let parsed: URL;
try {
parsed = new URL(`https://${hostname}`);
} catch {
throw invalidProxy('allowed hostnames must be valid DNS names');

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 Reject malformed DNS labels before changing routes

When proxyAllowedHostnames contains a value such as example..com, _foo.example.com, or -foo.example.com, WHATWG URL preserves it and these checks accept it even though it is not a valid public host name. If an existing browser is running, the input therefore passes preflight and triggers a destructive route transition, after which Chrome starts successfully but PAC/DNS resolution for the malformed allowlist entry fails, leaving the reported-success proxy route unusable and the previous tabs lost. Fresh evidence beyond the earlier length-limit issue is that syntactically invalid labels still pass; validate every label's nonempty LDH form before route switching.

Useful? React with 👍 / 👎.

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1×2,当前 head 按免密代理实现,但描述和安全门证据还停在认证代理那一轮。

  • [P1] packages/browser-control-runtime/src/types.ts:101 — 摘要已写「仅免密、带 userinfo 会在解析边界拒绝」,parseBrowserProxyServer 也会对 username/password 抛 authenticated proxies are not supportedhasCredentials 因此恒为 false。但「范围」仍写「HTTP 代理认证的 CDP Fetch challenge 处理」;「真实端到端验证」仍把 Chrome 151 + Basic-auth CONNECT、context.setHTTPCredentials、allowlist 内 HTTPS(认证代理)写成当前已执行且仍成立;风险段仍写「代理凭据仅保存在浏览器生命周期状态」。types.ts:101 注释仍是 Credentials are accepted only in-memory by the host.,与实现相反。请把范围/e2e 表/风险改成「仅免密;认证 URL 被拒绝;未再跑认证出口」,并改掉过期注释。验证:对照 PR 正文与 parseBrowserProxyServer / hasCredentialshttp://user:pass@host:portstart 应得到解析错误。

  • [P1] packages/browser-control-runtime/src/_generated/extension/src/browser/pw-session.ts:1410 — 文档和 host 把 CDP Fetch 写成生命周期请求层终局门,但同一 target 上 vendored 导航仍 page.route("**"),非顶层/子 frame 文档请求走 continueRouteSafely,不做 allowlist/DNS。作者自己用 Chrome 151 证明过同一 target 的 Fetch 事件只投给一个 CDP client;host 协调器单测是直接投喂伪造事件,绕过双 client 竞争。请在 proxied 模式下不要再 page.route("**")(或 route handler 走同一套 isBrowserProxyRequestUrlAllowedAsync),并补真实双 CDP client 回归:先 coordinator.start,再 Playwright route/goto,断言 host 仍收到 requestPaused,或明确改文档为「PAC + 文档导航守卫,Fetch 非终局」。不要只用向协调器 inject 的单测当通过证据。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 × 1(不改不能合)

packages/browser-control-runtime/src/_generated/extension/src/browser/pw-session.ts:1410

本 PR 把 host 侧 CDP Fetch(proxy-auth.tsFetch.requestPausedisBrowserProxyRequestUrlAllowedAsync)写成请求级终局门:HTTPS + allowlist + DNS 答案校验。同一 target 上 gotoPageWithNavigationGuard 仍无条件 page.route("**")

Chrome 对同一 target 只把 Fetch 事件投给一个 CDP client(upstream/MAINTAINING.md §4.1 已用 Chrome 151 写明:Playwright page.route 会抢走该 client)。结果:

  • 第一次工具导航即可挤掉 coordinator 的 Fetch;unroute 后也没有再 Fetch.enable
  • route handler 对非顶层、非 subframe 文档请求直接 continueRouteSafely,不做 allowlist / DNS。
  • 之后该页只剩 PAC 启动底线。PAC dnsResolve 是 IPv4-only;字面 IPv6(非 ::1 / fe80: / v4-mapped)在 browser-managed-config.ts 的 PAC blocked()return false 不拦。allowlist 名若有公网 A + 私网 AAAA 或随后 IPv6 rebind,不会按 proxy.ts / 注释声称的那样检查。

现有 coordinator 单测是直接投喂伪造 requestPaused,本 diff 没有双 CDP client 回归。

请任选其一落地,并补真实双 client回归(先 coordinator.start,再 Playwright route/goto,断言 goto 之后 host 仍收到 requestPaused):

  1. proxied 模式不要再用 Playwright page.route,只让 coordinator 当 Fetch client;或
  2. route handler 走同一套 isBrowserProxyRequestUrlAllowedAsync,并在 unroute 后重新 Fetch.enable

不要只用向协调器 inject 的单测当通过证据。

@MagicLizi

Copy link
Copy Markdown
Contributor

@cofyc 👋 这个 PR 还有 4 条 review conversation 没 resolve(browser-managed-config.ts 的 --proxy-server 与 PAC 并存 / browser.ts 的 CDP 身份 / interactions 弹窗策略拒绝后未关闭 / proxy.ts 畸形 DNS label),auto-review 因此暂时跳过、没法继续审查 / 合并。

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

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

审查结论:Request Changes(P1×1)

  • [P1] packages/browser-control-runtime/src/proxy.ts:192 — parseBrowserProxyServer 在解析边界拒绝带 userinfo 的代理(authenticated proxies are not supported),摘要也已收窄为「仅免密代理」。但 PR 描述仍与 HEAD 相反:
    1. 「范围」仍写「HTTP 代理认证的 CDP Fetch challenge 处理」;
    2. 「真实端到端验证」仍写已用 Basic-auth CONNECT 代理,并给出「allowlist 内 HTTPS(认证代理)✅ 通过代理成功,代理日志出现带凭据的 CONNECT」;
    3. 「风险 / 影响范围」仍按「代理凭据仅保存在浏览器生命周期状态」叙述。

这违反 development-workflow.md:怎么验证的必须如实,description 必须与 diff 一致。审阅者会以为认证代理已可用,掩盖「认证通道会把凭据交给任意 WWW-Authenticate 站点」这一已回滚结论。

请按当前实现改正文:验证表改成免密 CONNECT 结果、删掉认证成功行,「范围」里的认证协调改成「请求层 CDP Fetch 门(无凭据)」,风险段不要再写会持有代理凭据。代码侧免密 fail-closed 本身没有 P0/P1。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1×1

  • [P1] packages/browser-control-runtime/src/proxy.ts:192 — HEAD 在解析边界拒绝带 userinfo 的代理(authenticated proxies are not supported),MCP start 同样走该解析。摘要已写明仅支持免密,但「范围」仍列出「HTTP 代理认证的 CDP Fetch challenge 处理」,「真实端到端验证」表仍写 allowlist 内 HTTPS(认证代理)成功且代理日志出现带凭据 CONNECT,风险段仍写代理凭据保存在浏览器生命周期 / CDP Fetch。按 Description 会以为认证代理已交付。请把范围、E2E 表、风险、关联需求全部改成与免密-only HEAD 一致,删除 setHTTPCredentials / 认证 CONNECT 成功表述。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

独立审查(head d53e4a6)发现 P1×2,请修完后再请维护者确认。

P1 packages/browser-control-runtime/src/types.ts:101 — PR 描述与 HEAD 不一致。代码已在 parse 边界拒绝带 userinfo 的代理(proxy.ts:192,authenticated proxies are not supported),摘要也写了仅免密代理;但「范围」仍列「HTTP 代理认证的 CDP Fetch challenge 处理」,「真实端到端验证」仍声称 Chrome 151 + Basic-auth CONNECT 成功、context.setHTTPCredentials、认证代理下 allowlist HTTPS 通过,「风险」仍写凭据保存在浏览器生命周期。types.ts:101 仍写 Credentials are accepted only in-memory by the host。审查者会以为认证代理已随本 PR 交付。请把范围 / 验证表 / 风险 / 类型注释改成与免密-only HEAD 一致;免密 Chrome e2e 若已跑请改表记录,未跑请写明未跑。

P1 packages/browser-control-runtime/src/_generated/extension/src/browser/pw-session.ts:1394 — gotoPageWithNavigationGuardpage.route("**") 再 unroute。Chrome 每个 target 只有一个 Fetch client;host proxy-auth.ts:600 对网络 target Fetch.enable 后靠 Fetch.requestPaused + isBrowserProxyRequestUrlAllowedAsync 做生命周期 HTTPS/allowlist/DNS 门。第一次工具 goto 会抢走该 client,unroute 不会让协调器重新 enable(enableFetch 见 session 已登记就 return)。之后只剩 PAC + 导航守卫,paused 请求上的 DNS/rebinding 检查停止。单测直接给协调器喂假 requestPaused,没有和 Playwright 竞争。请在代理启动路径不要 page.route,或 unroute 后重新 Fetch.enable,并补两条 client 竞态测试。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

审查结论:Request Changes(P1×2)

独立重审 HEAD d53e4a6eac0f7cf88f6a99d0fa4037b602bba23e。免密 fail-closed 本身没有 P0;下面两条挡住合并。

  • [P1] packages/browser-control-runtime/src/proxy.ts:192 — 代码在解析边界拒绝带 userinfo 的代理(authenticated proxies are not supported),摘要也已收窄为仅免密。但 PR 描述仍与 HEAD 相反:「范围」仍写「HTTP 代理认证的 CDP Fetch challenge 处理」;「真实端到端验证」仍写 Chrome 151 + Basic-auth CONNECT、context.setHTTPCredentials、allowlist 内 HTTPS(认证代理)成功且代理日志出现带凭据 CONNECT;「风险」仍写代理凭据保存在浏览器生命周期。packages/browser-control-runtime/src/types.ts:101 仍写 Credentials are accepted only in-memory by the host.。这违反 development-workflow.md:怎么验证的必须如实,Description 必须与 diff 一致。请把范围 / E2E 表 / 风险 / 类型注释改成免密-only;认证 E2E 若已作废请删或标明历史。验证:对照正文与 parseBrowserProxyServerhttp://user:pass@host:portstart 应得到解析错误。

  • [P1] packages/browser-control-runtime/src/_generated/extension/src/browser/pw-session.ts:1410gotoPageWithNavigationGuardpage.route("**") 再 unroute。Chrome 每个 target 只有一个 Fetch client;host proxy-auth.ts:600 对网络 target Fetch.enable 后靠 requestPaused + isBrowserProxyRequestUrlAllowedAsync 做生命周期 HTTPS/allowlist/DNS 门。第一次工具 goto 会抢走该 client,unroute 不会让协调器重新 enable。之后只剩 PAC + 导航守卫。单测直接给协调器喂假 requestPaused,没有和 Playwright 竞争。请在代理启动路径不要 page.route,或 unroute 后重新 Fetch.enable,并补双 client 竞态测试。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

独立审查(heavy)有 1 条 P1,请先改 Description 再提审。

P1 packages/browser-control-runtime/src/proxy.ts:192
当前 head 已在解析边界拒绝带 userinfo 的代理(authenticated proxies are not supported),摘要也写明「仅免密」。但 Description 仍把已回滚的认证代理设计写成当前事实:

  • 「本 PR 包含」仍列「HTTP 代理认证的 CDP Fetch challenge 处理」
  • 「真实端到端验证」仍把 Playwright context.setHTTPCredentials、认证 CONNECT 成功、凭据只在进程内存写成现网结论

作者评论已说明该方案会把代理凭据交给 allowlist 内任意 WWW-Authenticate 站点并已撤回。请按当前 head 重写范围与验证(免密 E2E、认证拒绝);未再跑的项放到「未执行的验证」。代码本身这次不要求改。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1

PR body(范围 / 怎么验证的 / 风险)

HEAD d53e4a6epackages/browser-control-runtime/src/proxy.ts:184-194 于解析边界拒绝一切 userinfo(authenticated proxies are not supported),生产路径不会再带凭据启动。摘要也写了「仅支持免密代理」。但同一份 Description 仍把「HTTP 代理认证的 CDP Fetch challenge 处理」列进范围;E2E 表仍写「allowlist 内 HTTPS(认证代理)✅ 通过代理成功,代理日志出现带凭据的 CONNECT」,并声称已修「认证代理此前完全不工作」;风险节仍写「代理凭据仅保存在浏览器生命周期状态」「原生 Agent transcript 可能记录原始输入;调用方应使用可轮换凭据」。这与 .github/PULL_REQUEST_TEMPLATE.mddocs/dev-rules/development-workflow.md「怎么验证的必须如实、没跑不许写已跑」以及「PR 描述与 diff 不符」不一致。影响:维护者会按仍支持认证代理来评估安全面,E2E 表也无法在当前 HEAD 复现。请把范围改成明确不包含认证代理;删掉或改写带凭据 CONNECT 的 E2E 与风险文案;契约注释 packages/browser-control-runtime/src/types.ts:101(「Credentials are accepted only in-memory」)一并改掉。验证:对照 body 与 parseBrowserProxyServer / MCP schema,确认不再出现「凭据进入生命周期 / 认证 CONNECT」表述。

P1

packages/browser-control-runtime/src/__tests__/interaction-proxy-policy.test.ts:533

同文件 :868。本 PR 自己的测试让该包 buildtsc --noEmit)失败:TS2345mockImplementation 回调签名对不上 NormalizedProcedure<() => Promise<undefined>>。PR 写「pnpm --filter @cindy/browser-control-runtime build 结果:通过」,本 worktree 复跑 EXIT=2。Vitest 仍能跑过,所以这是类型门而非运行时红线,但广告出来的验证命令是假的,且失败文件在本 diff 内。请改 mock 签名(无参或与 NormalizedProcedure 一致)后再跑同一条 build。验证:pnpm --filter @cindy/browser-control-runtime build EXIT=0。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

审查未通过(P1×1)。描述与当前 diff 不一致,请改描述后再请审。

  • [P1] PR body(「本 PR 包含」/「真实端到端验证」/「风险」)— 代码已在 parseBrowserProxyServer 对 userinfo 抛 authenticated proxies are not supported(head d53e4a6eac0f7cf88f6a99d0fa4037b602bba23e),但描述仍写:包含「HTTP 代理认证的 CDP Fetch challenge 处理」;Chrome 151 上认证代理已通过 Playwright context.setHTTPCredentials;风险节仍写凭据保存在浏览器生命周期、userinfo 跨边界脱敏。违反 docs/dev-rules/development-workflow.md:验证与范围必须如实。请按现行免密-only 范围改描述——删掉已回滚的认证 e2e 表与凭据生命周期表述;「本 PR 包含」改为 CDP Fetch 仅作请求层 allowlist/DNS 门(handleAuthRequests: false)。验证:对照 packages/browser-control-runtime/src/proxy.ts 的 userinfo 拒绝与 apps/desktop/src/main/mcp-integrations/browser-backend/proxy-auth.tshasCredentials

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Findings

  • [P1] packages/browser-control-runtime/src/proxy.ts:54 — parseAllowedProxyHostname / assertDnsNameWithinLimits 只拦长度,不拦空 label 与非法 LDH。example..com_foo.example.com-foo.example.com 都能过预检。已有浏览器在跑时,这会先停掉旧进程再按「成功」切 route,随后 PAC/DNS 匹配失败,旧标签页被丢掉。请在切 route 之前按非空 LDH label 拒绝,并补测试。

  • [P1] packages/browser-control-runtime/src/_generated/extension/src/browser/pw-tools-core.interactions.ts:537 — 交互创建的 popup 命中 proxy/SSRF 拒绝时,assertObservedDelayedNavigationsassertPageNavigationCompletedSafely 只 quarantine、明确不 close;这里的 catch 只记下 popupError。在预算内的拒绝弹窗不会走进 overflow close/teardown,listener detach 后页面仍在执行(direct 模式没有持续 Fetch 闸门时更危险)。请在上抛错误前对每个被拒绝的 popup 做有界 fail-closed close。

Codex 仍开着的 --proxy-server--proxy-pac-url 互斥问题本轮未独立核实(文档写了双 flag 是有意设计),先保持 thread,不作为本条打回依据。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

独立审查重核(head d53e4a6eac0f7cf88f6a99d0fa4037b602bba23e)仍有 2 条 P1,本轮不能合。Codex 未 resolve 的 PAC/--proxy-server thread 先保持,不作为本条打回依据。

  • [P1] packages/browser-control-runtime/src/proxy.ts:54parseAllowedProxyHostname / assertDnsNameWithinLimits 只拦长度,不拦空 label 与非法 LDH。new URL('https://example..com')_foo.example.com-foo.example.comhostname 原样保留且能过预检。已有浏览器在跑时,这会先停掉旧进程再按「成功」切 route,随后 PAC/DNS 匹配失败,旧标签页被丢掉。请在切 route 之前按非空 LDH label 拒绝,并补测试。

  • [P1] packages/browser-control-runtime/src/_generated/extension/src/browser/pw-tools-core.interactions.ts:544:交互创建的 popup 命中 proxy/SSRF 拒绝时,assertObservedDelayedNavigationsassertPageNavigationCompletedSafely 只 quarantine、注释写明 never closes(pw-session.ts:1318);这里的 catch 只记下 popupError。预算内被拒绝的弹窗不会走进 overflow close/teardown,listener detach 后页面仍在执行(direct 模式没有持续 Fetch 闸门时更危险)。请在上抛错误前对每个被拒绝的 popup 调用 closeBlockedNavigationTarget(或等价的有界 fail-closed close)。

请修完后在最新 head 上再请求审查。

Launch Chrome with a caller-selected proxy, a PAC allowlist floor (including
PAC dnsResolve for WSS/pre-attach), and a lifetime CDP request gate. Authenticated
proxies are rejected at parse time.

The CDP guard identity follows the live managed profile: Cindy-real and a
relocated CDP port are used for Fetch, liveness, and adopted-close instead of
the isolated 18800/Cindy defaults.

Signed-off-by: Yecheng Fu <yechengfu1987@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: e9b54498c4

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +559 to +563
await Promise.race([
closeBlockedNavigationTarget({
cdpUrl: opts.cdpUrl,
page: popupPage as Page,
}).catch(() => undefined),

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 在弹窗关闭超时后升级到宿主级清理

当策略拒绝的弹窗其 closeBlockedNavigationTarget() 拒绝或超过 2 秒未完成时,这个 Promise.race 会把失败/超时都当作成功继续;随后 popupIndex 已等于队列长度,因而不会进入 context/browser teardown,监听器却仍被移除,direct 模式下该弹窗可继续执行与联网。相对此前评论的新证据是新增的有界关闭只验证了调用发生,测试也仅断言调用与 listener 移除,并未验证关闭完成;应把未确认关闭的情况升级到整 context/browser 及宿主可验证的 teardown。

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

Useful? React with 👍 / 👎.

@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: e9b54498c4

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +564 to +568
new Promise<void>((resolve) => {
const timer = setTimeout(resolve, POPUP_CHAIN_CLOSE_BUDGET_MS);
(timer as unknown as { unref?: () => void }).unref?.();
}),
]);

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 在弹窗关闭超时后升级到整浏览器隔离

当一个未触发 overflow 的弹窗因策略校验失败、且 closeBlockedNavigationTarget() 超过两秒仍未完成时,这个 timer 会让 Promise.race 按成功完成继续执行;随后 popupIndex 已经前进,后面的 overflow teardown 分支不会运行,最终抛出的仍是普通导航拒绝,也不会触发 Desktop 对 could not be torn down 的进程级清理。相对此前“关闭被拒弹窗”的评论,新证据是新增的有界关闭仍未区分“确已关闭”和“计时器先完成”,因此 direct 模式下被拒弹窗仍可在监听器移除后继续执行和联网。

Useful? React with 👍 / 👎.

}),
]);
}
if (!browserClosed) {

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 让宿主验证 browser.close 后的进程退出

当 overflow 清理走到 browser.close() 且该调用返回、但 Chrome 进程尚未真正退出或仍有页面存活时,browserClosed 会被置为 true,这里便跳过唯一会生成 could not be torn down 信号的分支;Desktop 因而不会执行其已验证的进程 teardown。相对此前浏览器关闭验证线程,新证据是当前相邻注释已经明确承认 resolved close() 只证明调用返回,却仍把该结果当作完成隔离并立即移除监听器。

Useful? React with 👍 / 👎.

@MagicLizi

Copy link
Copy Markdown
Contributor

@cofyc 👋 这个 PR 目前与 main 有合并冲突,auto-review 因此暂时跳过、没法继续审查 / 合并。

请在本地 merge 最新的 origin/main 解决冲突后推送;冲突解除后,下一轮 auto-review 会自动重新处理这个 PR。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:conflict 与目标分支有冲突(review-pr 自动维护,仅展示) touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:large-diff 改动量较大(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.

4 participants