DSH plugin 凭据怎么接:CredentialRef、按操作解析与 CredentialInfo
DSH plugin 的凭据 seam 只有一条底线:配置里永远只放引用,不放值。 settings 分节与 cordis.yml 条目携带的都是 CredentialRef(环境变量名),真正的密钥由 dsh-credentials-local 这类提供方持有;消费方每次操作都重新解析,因此轮换后的凭据不需要重启就能作用于下一次请求。这条设计还带出一个硬规则:空的存储值在任何地方都视为不存在——resolve 会跳过它,describe 会报未配置,避免「空字符串冒充已配置的密钥」。
理解这两点,剩下的读、写、描述三类接口就都顺了。
DSH plugin 凭据 seam 的底线:配置只放引用
一句话结论:引用可以出现在配置里,值只属于提供方——这是凭据能安全备份、分享与跨设备同步的前提。
- 配置里写引用:settings 里存的是环境变量名,
cordis.yml条目同样只写引用。 - 值归提供方:本地提供方从进程环境、提供方管理的存储与
.env文件三层取到值。 - 空值即不存在:seam 级规则,空白存储值不会被当成已配置。
- 落盘检查:提交前确认配置里没有任何形似密钥的长字符串。
- 验证:把配置分享给另一台机器,引用仍在、值需要在新机器上单独配置——这才是正确的状态。
DSH plugin 的两种键空间:引用与记录
一句话结论:引用回答「这个环境变量后面是什么」,记录回答「这个插件为某 id 持有什么凭据」——后者不可分层、存在即事实。
| 键空间 | 回答的问题 | 是否分层 | 主要操作 |
|---|---|---|---|
| CredentialRef | 环境变量名后面是什么 | 是(环境 / 存储 / .env) | resolve、describe、set、unset |
| CredentialKey | 插件为某 id 持有什么 | 否 | readRecord、describeRecord、listRecords、modifyRecord、deleteRecord |
- 引用用于密钥类场景:模型 API key、第三方服务 token。
- 记录用于授权类场景:OAuth 授予一类的插件自有凭据。
- 引用没有枚举接口:配置界面从 settings schema 学到有哪些引用;记录则必须能枚举,否则界面既列不出已授权项,也找不到卸载插件留下的孤儿记录。
- 别混用:把记录当引用去
resolve,拿不到任何东西。
DSH plugin 按操作解析:为什么不要缓存 resolve
一句话结论:每次操作重新 resolve,是热更新的实现方式;缓存等于把轮换挡在门外。
- 调用形态:
const resolved = await ctx.credentials.resolve(ref)
if (!resolved) { /* 未配置:给出明确提示,而不是拿空串去请求 */ }
// resolved.value 与 resolved.source
- LLM 适配器就是范例:每次模型请求解析一次,所以轮换后下一次请求立即生效。
- 不要跨操作缓存:官方明确要求消费方不得缓存,按操作读取本身就是机制。
- 未配置返回 undefined:用
undefined分支处理,不要用空串兜底。 - 验证:改掉环境变量值,不重启,直接发下一次请求,应使用新值。
DSH plugin 的 describe、CredentialInfo 与可写性
一句话结论:describe 只给事实不给值;writable: false 表示有只读来源遮蔽,写了也是白写。
interface CredentialInfo {
configured: boolean
source?: string
writable: boolean
}
- 界面用它渲染徽标:是否已配置、来自哪一层、能不能写。
- 本地提供方的只读情形:由当前进程环境供值的引用被报告为
writable: false——写入会表面成功,但解析持续返回遮蔽值,所以 seam 直接拒绝。 - 界面提前置灰:看到
writable: false就渲染成只读,而不是让用户点了才报错。 - 变更通知:
credentials/reference-updated在set、unset或观察到外部编辑后发出,用于刷新徽标;进程环境自身的变化不可观测,不会发事件。 - 消费方不需要这个事件:按操作重新解析就够了,事件只服务配置界面。
DSH plugin 的写入:set/unset 与 modifyRecord
一句话结论:引用用 set/unset,记录只用 modifyRecord——后者是唯一能安全刷新 token 的路径。
- 引用写入:
await ctx.credentials.set(ref, value) // 空值会被拒,删除请用 unset
await ctx.credentials.unset(ref) // 删不存在的引用是 no-op
- 只读遮蔽时会被拒:
set与unset在只读来源遮蔽时都拒绝,避免假成功。 - 记录写入:
await ctx.credentials.modifyRecord(key, async (current) => {
// current 是独占时刻的记录;返回 undefined 表示不改
return next
})
- 为什么不能先读再写:两个进程同时刷新同一 refresh token 时,后写会覆盖先写;
modifyRecord在一次持锁的读—改—写里完成,跨进程也成立。 - 授权流程另有入口:
ctx.authorization注册取凭据的流程,同一 key 同时只允许一次尝试,重复注册会以DUPLICATE_FLOW拒绝。
DSH plugin 排查注意事项
一句话结论:凭据问题先分「读不到」「写不进」「界面看不到」三类,再判断是层级遮蔽还是流程冲突。
- 读不到 → 看
resolve是否返回undefined,确认环境变量名与提供方层级。 - 写不进 → 看
describe().writable是否为 false(只读遮蔽)。 - 界面看不到 → 引用没有枚举接口,检查 settings schema 是否声明了它。
- 轮换不生效 → 检查是否在插件里缓存了
resolve结果。 - token 刷新丢写 → 改成
modifyRecord,不要先读再写。 - 修复状态如实:本文的引用/记录两种键空间、空值规则、按操作解析与写入拒绝语义均取自官方「用户凭据」页面与包源码注释;接口签名以该页 Cordis API 区块与你所用版本为准。
常见问题
DSH plugin 的配置里只应该放凭据引用(环境变量名),不要写密钥本身。settings 分节与 cordis.yml 条目携带的都是 CredentialRef,真正的值由凭据提供方持有,这样配置可以安全分享与备份。
DSH plugin 的凭据解析是按操作进行的,缓存会破坏热更新:值被轮换后你不会重新解析,仍用旧值请求。官方要求消费方每次操作都重新 resolve,轮换后的凭据无需重启就能作用于下一次请求。
DSH plugin 的 describe 返回 writable 为 false,说明当前有只读来源遮蔽该引用,例如进程环境变量供值。此时写入会表面成功而解析仍返回遮蔽值,所以 seam 直接拒绝,界面应把它渲染成只读。
DSH plugin 的凭据有两个键空间:CredentialRef 是环境变量名,可分层解析;CredentialKey 是插件持有的某条凭据记录,没有可读环境,记录存在即事实。前者用于密钥类引用,后者用于授权记录。
DSH plugin 的 modifyRecord 是一次串行的读—改—写,全程持锁,跨进程也生效。先读再写会让两个进程同时刷新同一 token 时丢掉后写方,所以记录的唯一写路径就是 modifyRecord。
相关术语
- CredentialRef(凭据引用)
- CredentialRef 是指向一条凭据的具名引用,形式为 POSIX 风格环境变量名,构造时按 shell 标识符语法校验。它让配置只携带引用而不携带值。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/credentials
- CredentialInfo(凭据描述)
- CredentialInfo 是给配置界面用的凭据事实:是否已配置、由哪一层供值、当前是否可写,结构里没有任何能承载值的槽位。正因如此它才能安全地跨 Remote 传输。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/credentials
- CredentialKey(凭据记录键)
- CredentialKey 标识插件为某个 id 持有的一条凭据记录,例如授权授予。与引用不同,它没有可解析的环境层,记录是否存在就是全部事实。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/credentials
- modifyRecord
- modifyRecord 是凭据记录唯一的写路径,对单条记录做串行的读—改—写并在支持的后端上跨进程持锁。它让 token 刷新这类读决定写的操作不会互相覆盖。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/credentials
来源
- DeepSeek Harness 文档 — 用户凭据(CredentialRef、解析、描述、写入与两种键空间)· deepseek-harness.github.io
- dsh-credentials 包源码(resolve/describe/set/unset 与记录操作)· deepseek-ai(GitHub)
- DeepSeek Harness 文档 — 插件配置表单(secret 字段与脱敏)· deepseek-harness.github.io