Skip to content

fix(pi): 解压后校验共享 GPT 请求的模型授权 - #7821

Merged
MagicLizi merged 2 commits into
makecindy:mainfrom
zqchris:share-pi-gpt-runtime
Oct 29, 2026
Merged

MagicLizi merged 2 commits into
makecindy:mainfrom
zqchris:share-pi-gpt-runtime

Conversation

@zqchris

@zqchris zqchris commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

这次改了什么

摘要

远程或分享使用 Pi + ChatGPT 订阅时,Pi 原生适配器发送 zstd JSON,通用代理此时只能提供 parsedBody = undefined。模型授权检查把尚未解压的请求当成空模型,导致已授权请求返回 model '' is not available from the provider shared with you 或 This model is not available for this remote task.;同账号供应商组内远程执行也受影响。

对已认证的原生 ChatGPT zstd 请求,改由原生 handler 解压后核对目录里的精确模型及实时授权,再取得上游凭证;鉴权后复查模型与 Fast 权限,再生成最终请求体;若重新压缩发生异步等待,发送前继续复查,关闭 Fast 时强制使用普通速度。保留原始窗口型号作授权依据,未知、空模型、未授权型号和在途撤回仍拒绝。本机普通请求保留既有行为。

变更类型

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

范围

  • 关联 Issue / 需求:远程、供应商分享与组内电脑使用 Pi + GPT 时误报模型不可用。
  • 本 PR 包含:压缩原生请求的校验顺序、解压后的精确模型授权、在途撤回检查、定向回归与真实 Pi/代理 E2E。
  • 明确不包含:模型列表、权限存储、IPC 协议、供应商组调度、服务端、引擎能力或上游账号准入策略。
  • 用户可见变化:已授权的远程 Pi + GPT 请求不再因压缩而被误读成空模型。
  • 是否存在 breaking change:无;现有授权与错误码保持兼容,无数据迁移。

UI 变化

不涉及。

  • 引用的设计规范:不涉及;无 renderer、布局、样式或 UI 文案改动。

怎么验证的

自动验证

  • 初版定向验证:claudeProxyGuestRoute.test.ts + piNativeSubscriptionForwarding.test.ts,99 项通过,8.05 秒;最初新增的 6 项回归在修复前均失败。
  • 本轮 Fast 时序修复:pnpm --dir apps/desktop exec vitest run src/main/maker-host/__tests__/piNativeSubscriptionForwarding.test.ts --maxWorkers=1,73 项通过,7.43 秒。新增的凭证读取 / 最终授权检查 × 明文 / zstd 共 4 项先在旧代码复现仍发送 priority,修复后均改为 default;既有字节保留、编码次数、改写期间 Fast 收紧和 owner 边界回归继续通过。
  • pnpm --dir apps/desktop exec vitest run src/main/maker-host/__tests__/piSharedSubscription.e2e.test.ts --maxWorkers=1:真实 Pi 1.0.2 + 真实回环代理,guest / owner 2 项通过;本轮重新实跑为 7.15 秒。临时还原生产代码后,两项精确复现上述错误;恢复修复后均通过。
  • TypeScript API 使用 Desktop 实际 tsconfig,对 5 个改动文件作语法与语义检查:0 diagnostics。这是改动文件定向检查,不是全包 typecheck。
  • pnpm check:test-hygiene、git diff --check、pnpm check:dco:通过。

测试价值与 tier:

  • claudeProxyGuestRoute.test.ts(unit,单独运行 3.70 秒):真实路由 transform 入口,最小输入是已认证、已授权的 Pi zstd 请求及未解析的 body。补齐此前只用明文 JSON 的路由覆盖,断言能进入原生解码 handler;原有拒绝错误令牌、跨供应商及不透明请求的断言保留。
  • piNativeSubscriptionForwarding.test.ts(unit,本轮单独运行 7.43 秒):真实原生 handler 入口,guest / owner × 明文 / zstd,检查精确授权、独立 [1m]、未知/空模型、撤回与鉴权期间释放绑定,拒绝时不发上游请求。旧计量测试补齐真实目录成员,保留流与计量断言。新增异步鉴权和最终授权期间关闭 Fast 的最小竞态输入,断言实际出站字节降为普通速度且不重复解码。文件收集需约 5–6 秒(已有宿主模块依赖),用例本身约 1 秒,不新增逐用例模块重载或真实等待。
  • piSharedSubscription.e2e.test.ts(e2e,本轮单独运行 7.15 秒,其中用例 0.86 秒):真实 Pi 原生客户端 → 真实代理解析 → 生产路由 transform → 生产 native handler;仅账号状态与云端响应使用 fixture。修复前的最小失败输入是一个已授权 ChatGPT 模型的原生压缩请求。验证收到回复、原始 zstd 编码与 wire ID,并验证撤回后上游调用数不再增加。复用现有 maker-host E2E tier,缺少受管 Pi 时按该 tier 约定跳过;本机实际执行两项。

手工验证

macOS arm64,受管 Pi 1.0.2。实际启动独立 Pi 进程,走真实回环 HTTP 代理与生产授权路径;同账号远程和受邀者两条路径均收到模拟上游的回复,撤权后的下一次原生调用被拒绝。临时目录、子进程、代理和测试绑定均已清理。未读取真实供应商凭证、未访问云端推理接口。

未执行的验证

完整 Desktop GUI、原远程机器升级后的复验、真实 OpenAI 云端推理、Windows 实机和全包类型检查未执行;当前核心验证覆盖实际 Pi 到生产代理的故障路径,完整测试交 CI。上游返回“只允许官方 Codex 客户端”的 422 属另一个账号准入问题,本 PR 不宣称解决。

风险

风险分类

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

影响与回滚

  • 影响范围:Pi 原生订阅的代理请求授权。只将已认证 ChatGPT zstd 请求的模型判定延后到已有原生解码器之后;供应商身份约束继续先执行。handler 重新检查精确 ID、实时授权和在途撤回,不能借独立窗口型号或删除绑定绕过。
  • 回滚 / 降级方式:回退本提交,无 schema 或持久数据变更;回退会恢复压缩远程请求被误拒绝的现象。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s,见 DCO)
  • UI 改动已在「UI 变化」注明引用的设计规范章节(不涉及 UI 则跳过)
  • 未提交凭证、令牌或授权文件
  • 已核对受影响的文档,行为变化涉及的旧结论已同步修订(不涉及则无需修改文档)
  • 已确认测试结果或说明未执行原因

Signed-off-by: zqchris <chrisz83@gmail.com>
@zqchris
zqchris requested a review from a team as a code owner October 29, 2026 07:51
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 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 ⚠️ Failed 2026-10-29T07:55:15.916533Z
We couldn’t complete this review. Comment @codex review to try again.
63990fb PR opened
ℹ️ 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.

@greptile-apps

greptile-apps Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The change is limited to model authorization for shared Pi subscription requests.

合并前需要修复读取 ChatGPT 凭证期间关闭 Fast 仍会发送优先请求的问题。

Findings

  1. P1 关闭 Fast 后仍发优先请求 ▶
Fix with agent prompt
### Issue 1
apps/desktop/src/main/maker-host/anthropic-responses-bridge-host.ts:850-851
将 `getChatgptAuth()` 移到请求改写之后,会漏掉读取凭证期间的 Fast 撤权。例如,请求带有 `service_tier: 'priority'`,账号刷新尚未完成时供应商或组关闭 Fast;此时 `outboundBody` 已生成,后面的 `modelAllowed()` 只检查模型权限,仍会发送优先请求,产生本应禁止的额外费用。此前 Fast 检查在读取凭证之后执行。

请在凭证读取和最终模型授权完成后重新检查 Fast,并在需要时重新生成请求体;补充读取凭证期间关闭 Fast 的回归测试。

---

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

Summary

本 PR 将已认证 Pi ChatGPT 压缩请求的模型授权延后到解压之后,并在发送前再次检查实时权限。

  • Shared Pi requests can use compressed ChatGPT models without skipping access checks.

Reviews (1) · Last reviewed commit: "fix(pi): authorize compressed remote GPT..." · Reviewed by Greptile

Signed-off-by: zqchris <chrisz83@gmail.com>

@xd-bobo xd-bobo 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.

Approved by compliance check: CI passed and no blocking reviews.

@MagicLizi

Copy link
Copy Markdown
Contributor

PR #7821 独立审查报告(heavy 档)

  • PR: fix(pi): 解压后校验共享 GPT 请求的模型授权 #7821 fix(pi): 解压后校验共享 GPT 请求的模型授权
  • head=5c5a0abb35832482928be686b59139b60dae6279 base=dea80435b02f005701979e253a4778c05faf2b23(main)
  • diffHash=317d3173747e00a221127ee8adc99d2a3c40603053788710d3e1df79316bef11,改动 5 个文件(360 diff 行):
    anthropic-compat-proxy-host.ts、anthropic-responses-bridge-host.ts 及 3 个测试文件。
  • 审查档位:heavy(危险写法软命中 4 处触发),含恶意代码/数据外发专项与 security-scan。

Findings

  • 无 P0/P1。
  • 排查过的疑点(均不构成阻断):
    • security.softHits 2 处(claudeProxyGuestRoute.test.ts:346、piSharedSubscription.e2e.test.ts:91,credential-assignment)逐条定性为测试桩占位:字面量 'fixture-token' 与 alg:'none' 的伪造 JWT(自签假账号 id),非真实凭证,未读取开发者 HOME/凭证目录,符合「测试只使用明显无效的假凭证」。
    • semgrep 对 2 个测试文件报 TS 泛型语法解析错误,该部分规则未覆盖(已在 Verification 如实标注,不当作「已扫描无问题」);人工读过这两个文件,无外发/危险写法。
    • 重档专项:本改动未新增依赖、未引入 install 钩子;请求仅携带既有订阅 OAuth token 到既有上游端点,未让数据流向新位置;权限检查只收紧(压缩请求从「误拒」变为「解压后精确校验」),无越权面扩大。
    • 未改动 spawn env、权限档、models.json 装配、system prompt、wire protocol schema,Pi 原生能力非退化红线未触及(修复方向即恢复被误拒的原生请求)。

Rule coverage — 读取的规则文件及逐项结论

  • docs/dev-rules/pi-harness.md(§1 架构/原生请求 Fast 偏好、§2 运行中的模型目录与凭据更新、§4 维护不变量):
    凭证仍只经 getChatgptAuth/getGrokToken 内存交接进请求头,不落盘、不进日志;Fast 偏好按「关闭实例/查询失败/受限时用普通档」处理,撤权后强制 service_tier: default;未破坏维护不变量(无权限档、env、斜杠命令、计量链改动)。
  • docs/dev-rules/credentials-and-local-storage.md Review 清单:无写盘;凭证不入仓/不进 fixture(见 Findings 定性);错误响应只含模型名与既有错误码,不回显鉴权材料。
  • docs/dev-rules/architecture-invariants.md Review 清单:新增 import 均为同层 main 模块(guest-provider-route-store、session-provider-store),无反向依赖、无运行时动态 import()。
  • docs/dev-rules/engineering-conventions.md Review 清单:无裸 console.log;无 IPC handler 改动;main 侧新逻辑带主路径+关键错误路径测试(授权拒绝、在途撤回、Fast 竞态 × 明文/zstd);e2e 用受管 Pi 子进程+回环代理,无外网/固定端口冲突,临时目录与子进程在 finally 清理;子进程回收用 kill(),跨平台成立,Windows 未实测(PR 已注明)。
  • docs/dev-rules/electron-security-and-process-boundaries.md §8:无 Renderer/preload/CSP/BrowserWindow 改动;loopback 信任边界顺序未放松——session token 认证、provider mismatch、guest 越界约束仍在解压/授权检查之前执行,nativeCompressedPiRequest 只跳过「解压前的模型预检」,且该分支必然落入 native handler 的解压后精确授权(无 fallthrough 旁路)。
  • docs/dev-rules/development-workflow.md §2–§3:验证命令如实(见下),DCO 两 commit 均签名;严重度口径按 P0/P1 判定,无可证实 P0/P1。

审查要点核对(共享符号/调用方/错误路径/权限边界):

  • guestProviderOffersModel / hostedProviderOffersModel / guestProviderModelDenial 的调用方(codex-proxy-host.ts、remote-agent/host/service.ts、路由 transform)语义一致:guest 绑定被释放或换绑后 guestProviderModelAllowed 的 bySession 复核拒绝在途请求;hosted 路径显式复查 hasHostedSessionModelAccess,避免 hostedProviderOffersModel 在解绑后 fail-open。
  • 每次 deps.fetch 出站前都有 modelAllowed() 成功 + throwIfOwnerBoundDispatchUnsafe 且最后一个检查与派发之间无异步间隙;zstd 重压缩的异步等待之后循环会复查模型授权与 Fast,forceStandard 一旦置位不回退。
  • 解码失败/空模型/未知模型/未授权模型/在途撤回均拒绝且不发上游请求、不取凭证(测试断言 fetch/getChatgptAuth 未调用);本机普通请求(无 guest/hosted 绑定)行为不变(modelAllowed 直通,原始字节保留)。
  • [1m] 窗口档位以原始请求型号作授权依据,withOpenaiContextProfileModel 只为上游兼容剥后缀,档位间不能互借授权(providerOffersModel exact 匹配)。

Verification — 实际运行的命令、结果、未执行项及原因

命令 结果
pnpm --dir apps/desktop exec vitest run src/main/maker-host/__tests__/claudeProxyGuestRoute.test.ts src/main/maker-host/__tests__/piNativeSubscriptionForwarding.test.ts --maxWorkers=1 EXIT=0,103 passed(30+73),14.8s
pnpm --dir apps/desktop exec vitest run src/main/maker-host/__tests__/piSharedSubscription.e2e.test.ts --maxWorkers=1 EXIT=0,2 passed(真实 Pi 子进程 + 真实回环代理 + 生产路由/授权路径,本机受管 Pi 存在,实际执行未跳过),5.6s
pnpm --filter desktop run --if-present typecheck(tsc --noEmit) EXIT=0
pnpm check:test-hygiene EXIT=0,PASS(359 files within baseline)
git diff --check EXIT=0
pnpm check:dco EXIT=0,2 commits signed off
node review-pr/scripts/security-scan.mjs --base dea80435 EXIT=0;依赖漏洞扫描:本 PR 未新增依赖,无需扫描;静态扫描(semgrep,仅新增):0 条;注意 semgrep 对 piNativeSubscriptionForwarding.test.ts:19、piSharedSubscription.e2e.test.ts:26 有语法解析错误,该部分规则未覆盖
GitHub checks(head 5c5a0ab,合并前复核) DCO / verify / Windows unit tests / Linux unit tests (1–4/4) / verify-checks / client-ci / pr-design-basis 等全部 completed+success

未执行:Windows 实机与完整 GUI 验证(PR「未执行的验证」已如实注明);完整单测由 CI(client-ci)覆盖。

Intent alignment

  • 描述来源(PR 标题+正文,读取于本审查时点):远程/分享使用 Pi + ChatGPT 订阅时,Pi 原生适配器发 zstd JSON,代理侧 parsedBody=undefined 被当成空模型,已授权请求被误拒(model '' is not available…);目标是对已认证的原生 ChatGPT zstd 请求在解压后核对目录精确模型与实时授权,再取凭证发送;鉴权后复查模型与 Fast;空/未知/未授权型号和在途撤回仍拒绝;本机普通请求保留既有行为。
  • 初始实现:63990fb478c5d907011ba43f6e90572814e0fced(fix(pi): authorize compressed remote GPT requests after decoding,基于 d58c58d),同批次含路由 transform 例外、native handler 解压后授权与 3 个测试文件,与上述目标一一对应。
  • 待合并 head:5c5a0abb35832482928be686b59139b60dae6279。与初始实现的差异仅为第二个 commit(fix(pi): recheck Fast policy after async authorization):把最终请求体生成推迟到凭证读取与最终授权之后,异步重压缩后复查授权/Fast。
  • 变化依据:Greptile P1 thread(#discussion_r4409892769,已 Resolve)指出把 getChatgptAuth 移到改写后会漏掉凭证读取期间的 Fast 撤权;第二 commit 按该意见修复并补 4 项回归(旧代码复现 priority、修复后 default),作者回复与最终 diff 一致。属同一「出站前授权/档位时序」目标内的缺陷修复,无功能反转、无扩范围、无依赖/配置新增。Codex review 状态为 Failed(未产出意见),无维护者讨论 issue(signoff 未 hold),无遗留讨论要求。
  • 对照结论:一致,无原意偏离。核心目标(压缩请求解压后精确授权、在途撤回拒绝、本机行为不变)在最终 diff 中均落实并有测试覆盖。

Overall

pass —— 没有 P0/P1。

@MagicLizi
MagicLizi merged commit b247a32 into makecindy:main Oct 29, 2026
15 of 16 checks passed
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.

3 participants