Conversation
… provider Three layers of defense against the corruption observed in the wild (a Keychain 'Claude Code-credentials' item holding empty-string tokens): 1. claude-code-creds: toSession rejects empty/invalid tokens at the import gate, so a broken Keychain item can no longer be written into the store. 2. store: saveAccountSession validates on write (read-path strictness now matched on the write path), and parseStore skips unusable ACCOUNT entries with a console warning instead of rejecting the whole file — one corrupt entry no longer blinds every provider's status; the next write drops it. 3. rpc + client: the status endpoint degrades per provider on failure, and the Settings page shows the error instead of an endless 'Checking…'.
|
感谢修复,空凭据导入后导致整份 auth store 读取失败的问题确实成立,导入入口拦截和写入前校验的方向也正确。 我将本 PR 与当前 main(已包含 #45)在临时工作树中合并验证,无冲突,375 项测试全部通过。不过,额外检查发现两个现有测试没有覆盖的回归,需要调整后再合并:
请分别补上“默认字段损坏但有效账号在后续写入后仍保留”和“操作失败后状态刷新成功仍保留错误提示”的回归测试。修复这两处后再继续合并检查。 |
|
感谢贡献。已将你的空凭据隔离修复按当前 main 适配并合并为提交 6c97ace:包含导入校验、存储读写校验、坏账号隔离、按 provider 的 status 降级和前端错误显示。合并前解决了当前 Fetch RPC 路由版本的冲突,并通过完整测试。该 PR 现关闭为已由本地适配实现覆盖,未直接合并此分支。 |
背景
实际环境中观察到一次完整故障链:macOS 钥匙串中存在一条损坏的
Claude Code-credentials项(accessToken/refreshToken为空串、expiresAt: 0,推测由 Claude Code CLI 登出残留)。toSession()只检查字段类型不检查空串 → 空壳被导入并经saveAccountSession()(同样无校验)写入 auth.json;parseStore()的严格校验 →status端点整体 reject → 全部 provider 的状态查询失败;refresh()静默吞错 → 界面无限停留在「查询中…」,用户只能看到一半症状(登录时报entry "claude/token-e3b0c44298fc1c14" is missing ...,其中 key 正是sha256("")[:16])。(原 issue 报告后转为直接修复,issue 已关闭。)
修复内容(三层防御)
1. 导入入口拒绝空凭据 —
claude-code-creds.tstoSession()增加空串与Number.isFinite校验,坏钥匙串项在入口即被丢弃。2. 存储层读写对称 + 单点隔离
saveAccountSession()写入前校验,与读取侧同样严格——坏数据无法再落盘;parseStore()对不可用的账号条目跳过并console.warn,不再整体抛错:一条坏记录不再拖垮所有 provider 的状态读取(与accounts.ts中「单个失效账号不得隐藏其他账号的模型」既有哲学一致);空 token 的会话本来就不可能可用,因此没有丢弃任何有价值的数据;下一次写入会顺带清掉被跳过的条目;3. RPC 与前端兜底
status端点按 provider catch 降级为该 provider 的detail,其他 provider 照常上报;refresh()失败时把错误显示在每个 provider 的错误行上(复用现有errors管道),轮询恢复时清除——不再无限「查询中…」。测试
pnpm build通过。兼容性