☰
opencodex Provider Workspace 账户体系 A 门审计:从账户切换器到多账号状态治理的源码级复盘
2026/9/25 6:03:43 网站建设 项目流程

【免费下载链接】opencodex

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载

导读

本文基于 opencodex 仓库 devlog 单元 260718_provider_workspace_accounts_rail 中的 A 门审计文档 011_account_audit.md,完整复盘该仓库将 Provider 工作区(#providers/workspace)改造成"账户切换一等公民"的过程:如何从既有WorkspaceItem、isAccountProvider、authMode、hasApiKey等字段无侵入地推导出认证表面,如何在并发刷新与失败网络下保住状态权威性,以及审计阶段发现并折叠的四个新增阻塞项。读完本文,你将掌握 opencodex 前端账户体系的认证表面判定规则、安全标签(masked email/序数)回退机制、代码级的状态提交策略,以及一套可复用的"审计 → 修订 → 验证"闭环方法。

1. 审计背景与输入:一条可独立复现的基线

1.1 前置探索结论

在正式 A 门之前,一条"roadmap 前账户探索链"独立追踪了完整链路:列表(list)→ 活动 ID(active id)→ PUT 切换 → 持久化 → 运行时凭证选择,最终返回VERDICT: READY,同时给出九条具体的风险/激活发现(详见 003_audit_synthesis.md)。

1.2 新鲜基线命令

本阶段 A 的基线测试命令与结果(来自 011_account_audit.md):

bun test --isolate tests/oauth-accounts-api.test.ts tests/oauth-store-multi.test.ts tests/oauth-public-surface.test.ts tests/codex-auth-api.test.ts tests/provider-workspace-data.test.ts tests/provider-workspace-state.test.ts 118 pass / 0 fail / 398 assertions

注意:后续账户切片实现后,聚焦套件提升至126 pass / 0 fail / 422 assertions(见 010_account_switcher.md C 验证收据);整合收尾后聚焦套件进一步达到133 pass / 0 fail / 462 assertions(见 030_integration_qa.md)。

1.3 评审委派的真实性记录

两个账户专项评审 agent 在各自三次有界等待后均未产出结果而被退役,这是同一数据包第二次派发失败。按 000_plan.md 的升级规则("主 agent 在两个不同 worker 失败后回收数据包"),主 agent 回收审计权并完成了本合成。这种"失败被记录而非隐藏"的做法是仓库审计纪律的一部分:C 阶段仍要求全新的实现评审。

2. 可行性审计:十个判定点

011_account_audit.md 对账户切片逐一做了可行性论证:

  1. ProviderAuthSurface可从既有字段推导——WorkspaceItem、isAccountProvider、isLocalProvider、authMode、hasApiKey、keyOptional均已存在,无需发明服务端字段。
  2. 渲染局部编排——通用按 provider 生成状态是Providers.tsx的渲染局部编排;功能性合并可修复当前"子集擦除"缺陷,无需全局 store。
  3. 切换失败可达——非 2xx 与 rejected fetch 都能触发;计划保留旧状态并增加finally恢复。
  4. Codex 假成功直接可达——setActive当前忽略res.ok;计划只在ok后消费响应并做权威刷新。
  5. 规范 vs 自定义 forward 判定——必须用isAccountProvider,不能用authMode === forward。
  6. needsReauth已存在于两个 DTO——阻塞变更并暴露恢复路径可达。
  7. 加载/空/一/多状态——从延迟/失败/真实响应可达;Anthropic 有两条真实活跃行、Codex 有四条,提供了真实的多账户证明。
  8. 键盘漫游焦点——现有 React tab 按钮可实现,无需依赖;浏览器 QA 必须做,因为仓库没有 DOM 测试夹具且新增依赖被禁止。
  9. 无身份单槽 provider 保持诚实——暴露当前返回行,但不被描述为"池"。
  10. 范围适配一个工作相位——服务端路由/存储不变,所有源修改都留在既有 GUI 属主链加一个纯分类器内。

3. 主审计追加折叠的四个阻塞项

除十个判定点外,主审计在 011_account_audit.md 中又发现四个可复现问题并折叠进计划:

3.1 跨 provider 的陈旧 tab 状态

ProviderDetails复用未带 key。修订:按 provider 名加 key,使 tab/设置状态无法跨 provider 身份串扰。实现后工作区详情按 provider 名重挂载(对应 010_account_switcher.md B 收据)。

3.2 OAuth/账户状态自相矛盾

独立请求可能返回陈旧的loggedIn=false覆盖真实活跃行。修订:非空权威账户行确立面板的登录摘要,两路请求不得在活跃行上方渲染矛盾的"未登录"。

3.3 通用 raw-id 反馈泄漏

Providers.tsx(文档标注:131,200-203)在可见通知/确认中使用了email ?? id。修订:所有工作区反馈路径统一走 shared masked-email/ordinal 标签。

3.4 Codex raw-id 确认泄漏

CodexAccountPool.tsx(文档标注:78,85-88)可能把 id 放进标签/确认文案。修订:只使用 masked email 或 main-account 文案。

这四个折叠项与仓库实际落地的安全标签工具相互印证:oauthAccountDisplayLabel优先返回 alias → masked email → 本地化序数,绝不回退到不透明存储 id(见 auth.ts)。

4. 残余项与主审计结论

4.1 记录的残余

  • Codex 池密度:完整内嵌 Codex 池仍比通用 OAuth 行列表稠密,但不阻塞功能;密度修复若进行,需留在CodexAccountPool/工作区样式内,并先作为 B 偏差补充(对应 020_provider_rail.md 的 rail 精修相位)。
  • 删除后焦点恢复:本切片不重新设计账户删除焦点恢复;保留现有确认,新增可访问标签,最终键盘 QA 必须确认非破坏性账户切换后焦点不丢失。

4.2 判定

所有可达的认证选择阻塞项现在都有精确属主与激活证据;不需要后端契约或凭证存储变更。正式评审交付失败被如实记录,最终 C/D 仍要求全新实现评审。

VERDICT: GO-WITH-FIXES (blockers=0)

5. 落地对照:认证表面的源码级实现

本小节以当前仓库源码佐证审计判定,帮助读者把"审计说了什么"映射为"代码实际是什么"。

5.1 纯分类器providerAuthSurface

gui/src/provider-workspace/auth.ts 定义了判定函数:

export type ProviderAuthSurface = "codex-accounts" | "oauth-accounts" | "api-keys" | null; export function providerAuthSurface(item: WorkspaceItem): ProviderAuthSurface { if (isAccountProvider(item.name, item)) return "codex-accounts"; const mode = (item.authMode ?? "").toLowerCase(); if (mode === "forward" || mode === "local" || isLocalProvider(item)) return null; if (mode === "oauth") return "oauth-accounts"; const hasKeyMaterial = item.hasApiKey === true; const keyAuth = mode === "key" || hasKeyMaterial || mode === ""; if (!keyAuth || (item.keyOptional === true && !hasKeyMaterial)) return null; return "api-keys"; }

规则解读:

  • 规范 OpenAI forward →codex-accounts:只有isAccountProvider为真才拥有 Codex 池。isAccountProvider在 catalog.ts 中定义为"名称等于规范 forward provider 且形状为规范 forward 形状"(name === CANONICAL_FORWARD_PROVIDER && isCanonicalForwardShape(p)),这正是审计点 5"必须用isAccountProvider而非authMode === forward"的实现。
  • 自定义 forward / local →null:绝不把全局 Codex 池继承给"看起来像 forward"的自定义代理,也绝不给无认证 provider 一个死 tab。
  • oauth→oauth-accounts:通用 OAuth 多账户。
  • key 形态 →api-keys:mode === "key"、已有 key 材料、或模式为空且非 keyOptional 时映射到 API keys;keyOptional且无 key 材料时返回null。

5.2 安全标签回退oauthAccountDisplayLabel

同一文件中的安全标签工具实现:

export function oauthAccountDisplayLabel<T extends OAuthAccountIdentity>( accounts: readonly T[], account: OAuthAccountIdentity, t: TFn, ): string { const alias = account.alias?.trim(); if (alias) return alias; const email = account.email?.trim(); if (email) return email; const index = accounts.findIndex(candidate => candidate.id === account.id); return t("pws.accountOrdinal", { count: String(index >= 0 ? index + 1 : 1) }); }

优先级为alias → masked email → 本地化序数(如Account 2/계정 2),绝不暴露存储 id。这正是审计折叠项 3/4(raw-id 泄漏)的收敛方案。

5.3 测试契约

测试文件 直接验证了上述两个工具:

  • 只有规范 OpenAI forward(openai-responses+chatgpt.com/backend-api/codexbaseUrl)得到codex-accounts;改名为custom-forward或改 baseUrl 即为null。
  • anthropic(oauth)→oauth-accounts;paid(key)/configured(hasApiKey: true)→api-keys;free(keyOptional: true无 key)与ollama(local)→null。
  • 标签:masked email 原样使用;alias 优先;无 email 时输出Account 2且断言不含opaque-second;未知行 fail-closed 到Account 1。

该测试与 010_account_switcher.md 的"RED → GREEN(8 pass / 0 fail)"收据一致,属于"先写契约测试、再生产代码"的路径。

6. 服务端契约:不变化的后端证据

审计判定"不需要后端契约变更"可在当前仓库源码中验证:

  • 通用 OAuth 账户列表:GET /api/oauth/accounts?provider=P返回{ activeAccountId, accounts[] },且注释明确"Emails are masked; tokens never leave the store"(见 oauth-account-routes.ts)。
  • 通用切换:PUT /api/oauth/accounts/active校验 provider 与accountId,调用setActiveAccount(写凭证存储锁内账户集,见 src/oauth/store.ts),随后清空模型缓存与配额缓存(clearModelCache/clearProviderQuotaCache)。
  • Codex 侧:GET /api/codex-auth/accounts与GET/PUT /api/codex-auth/active承载 canonical Codex 池(见 src/codex/auth-api.ts)。

从源码结构看,前端工作区的改造(ProviderAuthSurface纯分类器、Providers.tsx状态提交、ProviderAuthPanel/CodexAccountPool失败诚实化)完全是 GUI 侧行为,与凭证/路由契约解耦——这正是审计点 10 与最终判定"仅 GUI 属主链 + 一个纯分类器"的直接证据。

7. 后续相位承接与总账

A 门审计不是终点,它把结论交棒给两个实现相位与一个集成相位:

  • 010_account_switcher.md:账户切换器实现,含激活矩阵(loading / empty / one / many / reauth / HTTP failure / network failure / stale GET / custom forward / provider change / status race / safe fallback / keyboard tabs / live switch)与验证命令。
  • 020_provider_rail.md:rail 两行语义行 + 容器查询响应式修复。
  • 030_integration_qa.md:整合对抗 QA 与收尾(含#providers/workspace深链保持、同步重复切换防护、POST-PUT 刷新诚实性、显式 Codex 键盘切换按钮、诚实登出刷新、可见 DELETE 失败处理、单入口 rail 焦点模型等八项残余修复)。

整体设计意图(来自 000_plan.md 与 001_design_read.md)始终一致:账户身份成为一等工作区 tab,rail 每一行读作一个连贯状态对象;活跃状态由服务端权威,失败的切换不改变选中行,任何可见表面不出现 raw id/全邮箱/不透明账户 id。A 门审计以GO-WITH-FIXES (blockers=0)收敛,为后续 B/C 的实现与验收提供了精确、可复现的靶心。

【免费下载链接】opencodex

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载
上一篇:JNativeHook测试策略:单元测试与集成测试完整指南
下一篇:GitHub Pages URL Shortener 使用教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询