Repository navigation
fix(browser): Windows API 浏览器结构兼容加固与可验证恢复 - #2378
BigPizzaV3 merged 3 commits into
Conversation
|
感谢这个改动,也感谢你在描述里主动说明「验收版本基于 技术增量是真实存在的(下面 2.5 列的三点 main 确实没有),但当前提交相对 main 是一次替换式改动而不是叠加式改动,会把 main 刚建立的降级通道收窄回 fail-closed。建议要求修改后再合。 一、与 main
|
| 输入 | main 路径 | 本 PR 路径 |
|---|---|---|
重命名 sendSessionRequest 参数及全部引用 |
接受 | 接受(AST 归一化确实生效) |
方法体内加一句 this.metrics=(this.metrics||0)+1; |
接受 | 拒绝 |
"getUserTabs" → "getUserTabs2" |
接受 | 拒绝 |
方法改名 sendSessionRequest → sendSessionRequest2 |
接受 | 拒绝 |
第一行说明你的 AST 校验确实做到了 main 做不到的绑定级校验——这是真增量,值得保留。后三行同时说明:「未知版本能不能用」被重新绑死在一张双元素哈希表上。 issue #2294 的病根(一次发版作废整张表)从原件层搬到了 AST 层。
1.4 版本下限检查被静默弱化
main 在未知路径要求 parsed.at_least(MIN_RUNTIME_VERSION)(0.0.11)。本 PR 的 detect 完全不解析 manifest 版本,只比对 layout 字段。虽然 ENTRY_SHA 实际形成了隐式下限,但性质不同(显式契约 vs 巧合),应显式补回。
二、确属增量的部分(应当保留,不要一起砍)
这三点 main 确实没有,不是重复:
- 组件级事务守卫升级:
detect对node.exe/node_repl.exe做 PE x64 头校验(pe_x64)、对package.json校验name/type/exports["./service"],并把现算哈希写进contract.files作为精确事务守卫。比 main 的「仅存在性+大小」强一个量级。 - schema-2 可重算恢复:
recovery_material对 schema 2 要求binding.replace(&original, control) == candidate——恢复时重算最小变换并要求逐字节相等,而非只比哈希。main 只有 schema 1。这是真正的抗篡改改进。 - 绑定级 AST 校验(见 1.3 第一行)。
净判断:增量存在,但被一个方向性回退抵消。 正确的合入形态是「保留这三点,去掉 1.2 / 1.3 的硬编码准入面」。
三、新增依赖:合规,但有两点要补
@babel/parser 与 @babel/traverse 我核对过:依赖树零膨胀——main 的 lock 里本来就有这两个(经 @vitejs/plugin-react → @babel/core 传递引入),版本恰好就是 7.29.3 / 7.29.0。本 PR 只是把传递依赖提升为直接 devDependency(188 → 188 packages,added/removed 均为空)。
写成精确版本而非 ^ 是正确的:inspect-service.mjs 里那些 AST 规范化哈希是对 Babel 输出形状的承诺,Babel 变更节点结构时哈希会静默漂移。建议补一条注释说明这个耦合。
要补的两点:
assemble-native-browser-inspector.mjs没接进任何 CI workflow。仓库对 renderer-inject 有assemble --check约定,这里缺了。native-browser-contract.test.ts只校验.cjs头部含.mjs的 SHA256(弱防线,不验 bundle 内容)。建议把--check加进.github/workflows/pr-build.yml。esbuild是未声明的构建依赖。脚本从node_modulesrequireesbuild,而它只作为vite的传递依赖存在。vite 升版换掉 esbuild、或 npm 不做 hoist 时,构建脚本会静默失效。建议显式声明。
另外 package-lock.json 里根 version 从 1.3.0 改成 1.5.0——那是 main 自身的 lock 漂移被顺手补上,不是本 PR 引入的。建议拆成独立 commit,可减小 rebase 冲突面。
四、实跑验证
我在独立 worktree(/tmp/pr2378wt)实测:
| 项目 | 你声称 | 实测 |
|---|---|---|
cargo test -p codex-plus-core |
1708 passed / 0 failed / 8 ignored | 1383 passed / 0 failed / 6 ignored |
npm test |
316 passed | 315 pass / 0 fail / 1 skip |
npx tsc --noEmit |
通过 | 通过 |
assemble-native-browser-inspector.mjs --check |
通过 | 通过 |
1708 vs 1383 是口径差异(你应是 workspace 口径,我只跑 -p codex-plus-core),不是虚报;你「ignored 不计为通过」的表述是诚实的。
但有一个实质问题:被 skip 的那个测试 real local service fixtures retain their structural contract 需要 CPP_BROWSER_SERVICE_FIXTURES 环境变量,CI 不设。而你描述里最有价值的负例(真实 0.0.11/0.0.24/0.0.27 服务识别、歧义、遮蔽、契约漂移)全部集中在这个被 skip 的测试里——也就是说「真实版本负例通过」在 CI 上不可复现。
同样,Rust 侧 structural_fixture_transaction_recovery_and_component_drift 需要私有 fixture,CI 上永远 skip。结果:structural::detect 这条全新代码路径在 CI 上零覆盖。 建议用合成 runtime(tempfile + 假 PE + 假 package.json + specimen 服务)在 #[cfg(test)] 里直接调 detect。
五、安全审查:声称基本属实
逐项核对 native_browser_contract.rs:94-116:CREATE_NO_WINDOW、.env_clear()(仅回填 SystemRoot,这是必要的)、--no-addons、--max-old-space-size=256、20 秒截止(try_wait 轮询 + ensure!)、stdin writer 独立线程——全部落实。
写盘路径质量很高:write_new 用 create_new(true) + sync_all();已存在则逐字节比对、外部改动直接拒绝;pin_parents 在 Windows 上用禁 DELETE 的 share mode + OPEN_REPARSE_POINT 防 TOCTOU 重解析点替换;schema-2 恢复不执行 Node(纯计算)。
worker 身份认证 / 伪造官方登录:独立确认没有触碰。 我 grep 了新增面里的 apikey / auth / login / token / credential,命中全落在 Babel 的 MIT 许可证文本里;require-identification.mjs 与 main 逐字节相同。你的声明属实。
两点建议写进文档:
detect对node.exe只验 PE 头、不验哈希。所以「AST 校验能防住恶意 runtime」要打折:攻击者若能同时控制cua-repl.mjs(受ENTRY_SHA保护)则防得住,若只能替换node.exe则防不住——因为 helper 是用runtime.join("bin/node.exe")解释执行的。这是本方案最深的信任根,建议显式写出。run_child超时路径上的writer.join()隐含依赖 EPIPE 返回(实践中成立,但属隐含保证),建议改为先kill再关 stdin,或用有界等待。
六、必须修改的点
- 删除
ENTRY_SHA硬哈希准入(:5、:201-206),改为结构不变量:入口文件存在 +parse成功 + 导出签名形状匹配,与 main 的CUA_ENTRY结构检查对齐。现算哈希保留作事务守卫(这个用法是对的),但不得作为准入条件。 PROTOCOL_SHAPES降级为「已知良好快路径」而非唯一准入,否则与 main 的adaptive降级语义直接冲突。- 修复
Structural通道被旁路(native_browser.rs:684-687):让detect成为for_manifest未知分支的加固而不是替代。 - 补回运行时版本下限检查,
detect里显式解析 manifest 版本。 assemble-native-browser-inspector.mjs --check接入 CI。- 显式声明
esbuild到 devDependencies。 - 给
detect补 CI 可跑的测试(合成 runtime,不依赖私有 fixture)。 - 拆分
package-lock.json的版本号修正为独立 commit。 - 文档补三处边界:
node.exe只验 PE 头是信任根;文档里「不依赖外部 parser 包」的表述需与实际 devDependency 一致;schema-2 的向前兼容风险。
七、与 #2309 / #2313 的合并顺序
你们三个 PR 都动 native_browser.rs 且都不含 04ab6290:
#2309: merge-base 693c8486,不含 04ab6290
#2313: 同上
#2378: merge-base 09a9f1c,不含 04ab6290
相对 main,#2309 / #2313 的 diff 显示 native_browser.rs -770 / -767 行、native_browser_connection.rs -387 行——它们在整体回退 main 的 native-browser 工作(基线落后所致,非本意)。
谁先合都会互相覆盖,必须先 rebase。 建议顺序:
- 先合 fix(browser): Windows API 浏览器结构兼容加固与可验证恢复 #2378 的 rebase 版(三者中唯一主动承认需协调、且技术增量最实),但先按第六节去掉硬编码准入面;
#2309/#2313在此之后 rebase,重新评估 native-browser 部分——大概率不该保留任何native_browser.rs改动,只留各自主功能;- 若 fix: 新版 Codex App 兼容适配(面板边界、顶部入口与注入卡顿缓解) #2309 / fix: make launch and restart lifecycle deterministic #2313 先合,
04ab6290与本 PR 的成果都会被静默回退。
另有一处静默丢失风险:apps/codex-plus-manager/src/native-browser-status.ts 本 PR 未改,但 main 刚在 a6e0d7a8 加了 browserRecognizedSuffix(区分「扩展未连上」vs「连上了但版本未登记」)。它不在本 PR 的改动文件列表里,所以 rebase 冲突不会提示——需要人工确认别丢掉。
当晚新提的 PR(@Yuimi-chaya,+1370/-16,11 文件),与已合入的 04ab629 改同一块 native_browser.rs。处置:要求修改。 三条经独立核实的阻断项: 1. FileCheck::Structural 降级通道被整体旁路——for_manifest 改收哈希字符串, 未知版本必然 Err,main 的结构降级分支在未知版本上不可达。 2. ENTRY_SHA 重新引入哈希白名单(无条件准入 cua-repl.mjs 入口), 复现 issue #2294 的病根;PROTOCOL_SHAPES 同理。 3. 运行时版本下限检查被静默弱化。 确属增量应保留:组件事务守卫、schema-2 可重算恢复、绑定级 AST 校验。 依赖合规(@babel 零膨胀,188→188),但构建 --check 未接 CI、esbuild 未显式声明。 实测 1383 passed / 315 pass,但最有价值的负例全在被 skip 的 fixture 测试里, detect 路径在 CI 上零覆盖。 安全:子进程隔离与写盘原子性落实,未触碰身份认证(已独立确认)。 合并顺序:与 #2309/#2313 三者都不含 04ab629,必须先 rebase。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
932abca to
d49bd54
Compare
|
已按补审意见整合到
最新本地结果:Rust workspace 1724 passed / 0 failed / 8 ignored;真实 0.0.27 临时事务 1 passed;真实三个版本原始服务定向 6 passed / 0 skipped;默认前端 336 passed / 0 failed / 1 skipped,该私有夹具跳过项已另行定向运行。TypeScript、Vite、两种组装检查和 diff 检查通过。原生服务没有执行,没有关闭、重启、替换或安装真实应用。 正文区分了旧 另外,第七节引用的 #2309 / #2313 旧基线已经过时:两者已分别更新到 |
|
首次新 CI 的三处失败已定位,均为 原 workflow 使用 已追加 在全新的隔离目录运行 |
|
已合并到 main(
合入时我做的两处处理一、与 #2313 的冲突(已解)。 两个 PR 都在 二、一处 git 不会报、编译才发现的语义冲突。 main 上的测试 这正是我每次合并后都要实跑测试的原因——文本冲突解决了不代表语义冲突解决了。 当前状态
两点建议后续跟进(不阻塞,已合入)
|
概要
Refs #2173, #2294
加固 Windows API 模式下原生 Edge / Chrome 请求标识兼容,在 main 的未知运行时结构通道上增加词法绑定检查、组件事务守卫和可重算恢复。当前 HEAD 为
cea82591,基于89615978,已包含04ab629和浏览器连接识别状态展示。兼容与修改范围
RuntimeContract::for_manifest、FileCheck::Structural、adaptive状态和 0.0.11 版本下限。已知 0.0.11 / 0.0.24 指纹继续作为快路径;未知运行时先经过上游结构检查,再解析实际回调绑定。runtime_archive_version/runtime_archive_name,没有 package 风格的name/version。现在兼容两种格式,校验归档版本与文件名一致性,并保留最低版本检查。@oai/cua-repl的词法绑定和 awaitedlaunch()签名。入口注释、格式及诊断变化不需要登记新哈希。恢复与检查器
CI 与依赖
assemble-native-browser-inspector.mjs --check,验证完整生成 bundle。npm ci安装锁定依赖。原来的npm install --package-lock=false会忽略传递依赖的精确版本,与完整 bundle 的可复现检查冲突,导致首次构建三平台均出现Inspector bundle drift;独立提交cea82591修正安装方式,保留严格检查。d49bd549,功能提交为7173788d。验证
cargo test --locked --offline --workspace -j 2 --no-fail-fast:1724 passed,0 failed,8 ignored,55 个结果组。npm ci --offline、完整 bundle 检查、336 项前端测试、TypeScript 与 Vite 构建再次通过;没有替换现有共享依赖目录。旧提交
932abca3曾完成 Windows Release / setup / ZIP 编译及用户异机验收;该历史结果不等于当前整合版本已真人验收。当前整合版本未执行真实应用安装、关闭、重启或替换,未重新生成发布安装包;新 CI、当前版本真人验收和 macOS 运行验证仍需分别确认。使用边界
实验选项默认关闭;不伪造官方登录,不修改 worker 认证,不绕过站点限制或原生操作审批,不分发原生运行时。Mac 浏览器适配与独立解锁器未修改。
旧版 Codex++ / 独立解锁器 v0.1.0 不理解 schema 2,降级前须用兼容版本还原。后续 helper 或插入格式变化须保留或版本化 schema-2 重算算法,以免旧日志无法恢复。
扩展可能保留请求标识状态,还原服务不等于清除该状态;
prepared不等于浏览器首次使用已验收。