Skip to content

bug: 自定义供应商旧密钥密文不可解密时配置更新死锁,新 API key 也无法保存 #3821

Description

@fico-hub

问题描述 / What happened

自定义供应商已存的 API key 密文一旦用当前 safeStorage 密钥解不开(例如 Keychain 密钥变更、或密文由另一个构建写入),该供应商的配置更新会永久死锁:即使用户在表单里粘贴了全新的 API key 点保存,也始终报 failed to read existing <agent> provider credential,没有任何自救路径(UI 上无法清除坏密文,只能手动去 safe-storage/ 目录删 .enc 文件)。

根因链路:

  • maker:provider:custom:update 在写入新 key 前,会先经 stageProviderKeys 对每个待变更 runtime 做严格快照读取(providerHandlers.ts#L677-L680)。
  • 快照读取走 readCustomProviderKeyForMutation,按注释设计「仅 ENOENT 表示没有旧 key,解密失败必须抛错」,目的是防止把暂时不可读的凭证误判为空而永久删除。
  • 但当密文是永久性不可解(safeStorage 密钥已变,重试多少次都一样)时,这层保护反而把用户锁死:明明提供了替换值,旧值反正会被覆盖,却因为「拿不到回滚快照」拒绝整个保存。readCustomProviderHeadersForMutation 的请求头路径同理(providerHandlers.ts#L773)。

期望行为(建议方向,供维护者裁量):

  1. 当本次 mutation 携带显式替换值时,快照解密失败可降级为「快照 = 不可恢复」,回滚语义退化为删除该 runtime 的密文,不阻塞覆盖写入;仅在 mutation 是「保留旧值」或「仅删除」语义时维持现有严格失败。
  2. 或者至少:错误信息告知用户旧凭证已损坏及恢复方式(重新填 key / 提供「清除已存凭证」入口),而不是笼统的 INTERNAL。

环境 / Environment

  • Cindy 版本或 commit / version or commit: 0.1.71(release 安装版);main 11e02c03 上代码路径一致
  • 平台与版本 / platform & OS version: macOS (Darwin 25.4.0, Apple Silicon)
  • 安装方式 / install method: 官方 dmg 安装到 /Applications

复现步骤 / Steps to reproduce

  1. 自定义供应商配置好 API key(密文落盘为 userData/safe-storage/owner_<id>_provider_key_<provider>_<agent>.enc)。
  2. 使该密文对当前 safeStorage 密钥不可解。实机是历史写入的密文解不开(疑似曾由不同签名/构建写入);模拟复现可直接用任意 base64 垃圾字节覆盖该 .enc 文件内容。
  3. 打开「编辑自定义供应商」,粘贴一个全新的 API key,点保存。
  4. 观察:顶部 toast 报 failed to read existing claude-code provider credential,保存失败;反复重填 key 均无效,UI 无任何恢复路径。
  5. 手动把对应 .enc 文件移走后再保存 → 立即成功(证明死锁仅由坏密文快照引起)。

日志与截图 / Logs & screenshots

[2026-09-02T22:36:34.282+08:00] [WARN ] [providerSecretStore] {
   providerId: 'kimi-code',
   agent: 'claude-code',
   err: 'Error while decrypting the ciphertext provided to safeStorage.decryptString.'
 } decrypt custom provider key snapshot failed
[2026-09-02T22:36:34.282+08:00] [ERROR] [console] Error occurred in handler for 'maker:provider:custom:update': Error: [INTERNAL] failed to read existing claude-code provider credential
     at createIpcError (.../bootstrap-electron-ClZHv728.js:221:19129)
     at throwIpcError (.../bootstrap-electron-ClZHv728.js:221:19279)

(已按模板要求删除凭证与个人数据;kimi-code 为本机自定义供应商 id。)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions