DeepSeek Harness 源码解析 · 第 32 讲
DeepSeek Harness 源码解析系列 第 32 讲:Credentials 密钥与凭证管理 基于 DeepSeek Harness 源码 · 2026-09-15 💡 本讲一句话: Harness 里配置只存"密钥的名字"(环境变量名),真正的值由凭证服务按四层优先级现场解析——继承环境 > 托管存储 > 项目 .env > 用户 .env;改一次 key,下一次请求立刻生效,全程不重启、不把值写进任何配置文件。 一、引用与值分离:凭证层的总设计 先回答一个容易踩坑的问题: Harness 把 API key 存在哪? 答案是——它 不存值,只存引用 。配置面(settings、cordis.yml)里出现的永远是 DEEPSEEK_API_KEY 这样的环境变量名,真正的密钥值由凭证服务在每次操作时现场解析。这个"引用/值分离"的接缝(seam)定义在 @deepseek-ai/dsh-credentials 包里,只有 145 行,却把四条铁律写进了抽象基类: 🔹 引用必须是合法的 POSIX shell 标识符( /^[A-Za-z_][A-Za-z0-9_]*$/ ),否则在接缝上不可寻址; 🔹 空值即未配置 :空白字符串永远不能伪装成"已配置的密钥"; 🔹 解析是 每次调用一次 的,消费者禁止跨操作缓存——这正是"改 key 立即生效、无需重启"的来源; 🔹 describe() 只返回"配置状态/来源层/可写性", 绝不返回值本身 ——UI 能看到 key 存在哪一层,但看不到 key。 先看接缝的入口:引用品牌化函数和两个结果类型(packages/credentials/credentials/src/index.ts): 📄 packages/credentials/credentials/src/index.ts (第 16-46 行) const REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/ // 引用必须是合法 POSIX shell 标识符——它最终要能当环境变量名用,带空格/点号的"引用"在接缝上不可寻址 // 品牌化:把裸字符串提升为 CredentialRef(名义类型),让"随便一个字符串"和"凭证引用"在类型层面分开 export function credentialRef(value: string): CredentialRef { // 入口校验函数,非法引用在这里就 fail loud,而不是等到 resolve 时才炸 if (!REF_PATTERN.test(value)) { // 不匹配标识符规则(如 "MY KEY"、"a.b")直接拒绝 throw new TypeError(`credential ref "${value}" must match ${String(REF_PATTERN)}`) // 报错信息带上正则本身,调用方一眼知道合法格式是什么 } return value as CredentialRef // 校验通过即品牌化返回——运行时零开销,约束全部落在类型系统里 } // resolve() 的返回值:值 + 来源层 id(env / file / project-env / user-env),消费者据此知道这个 key 是谁给的 export interface ResolvedCredential { // 接口定义开始 value: string // 非空的密钥值——空值在接缝规则里等于"未配置",根本不会出现在这里 source: string // provider 自定义的来源层 id:本地 provider 用 env、file、project-env、user-env 四种 } // describe() 的返回值:给配置 UI 用的元数据——注意它只有三个字段,唯独没有 value export interface CredentialInfo { // "这个 key 配没配、从哪来、能不能写"三件事,UI 需要知道的全部事实 configured: boolean // resolve() 当前是否会返回一个值(空字符串不算配置) source?: string // 当前供值的来…