前言¶
在 DSH「一切皆插件」的开发方式下,插件作者最容易踩的坑往往不在编译期:产物能构建、单测能通过,发布之后却可能因为 tarball 缺文件、bundle 在宿主里注册失败、卸载弄坏 profile 而翻车。这类问题的共同点是,它们只出现在「用户实际安装的那个打包产物」与「真实宿主」之间,作者本机的静态检查覆盖不到。
dsh-testkit 补的就是这一段:把 npm pack 出来的产物放进精确指定的真实 DSH 宿主,完整走一遍生命周期,并把证据留给维护者审查。
这是什么¶
iiwish/dsh-testkit 自述为 “The real-host release gate for DeepSeek Harness plugins”,即 DeepSeek Harness 插件的真实宿主发布门槛。它明确了自己的边界:是发布门槛,不是单元测试框架、静态 linter、模型输出评估器,也不是安全认证。整个流程不做模型调用,不需要模型 API key,许可证为 MIT。
一次隔离运行回答三个发布问题:
| 发布问题 | 一次隔离运行给出的证据 |
|---|---|
| 可发布的产物能否安装并注册? | npm pack、精确版本 DSH 安装、bundle 组装、配置行、services 与 tool schema |
| 承诺的行为是否可用? | 确定性运行时探针、声明的工具调用、可选 loopback HTTP 路由、显式浏览器 smoke |
| 用户能否干净地卸载? | 卸载、同 profile 重启、能力检查、owned-path 残留、进程与端口检查 |
生命周期:从 resolve 到 cleanup¶
一次完整的隔离生命周期是:
resolve -> install-dsh -> package -> install-plugin -> assemble -> boot -> register
-> exercise -> update? -> uninstall -> reboot -> recover? -> cleanup
每次隔离生命周期只测试一个被测插件;多插件所有权与更新顺序属于组合层面问题,不在这个工具的职责内。
适配器目前只接受 @deepseek-ai/dsh 的精确版本:0.1.1-rc.2(默认)、0.1.0-rc.8、0.1.0-rc.7、0.1.0-rc.6。未知版本会在创建 runner 之前以退出码 4 终止,宿主版本漂移不会被误标为插件失败。官方 dsh-v0.1.2-alpha.1 因对应 npm 包不可用仍是待定 canary;0.1.2-alpha.2 仅进入一次性 canary 矩阵。两个 alpha 都不在默认支持矩阵内。
通过意味着什么¶
- 报告中标识的同一个打包产物完成了全部必需阶段;
- 配置行来自 DSH
--dump-config,services 与 tool schema 来自进程内 Cordis 探针; - 声明的 exercise 通过真实工具运行时执行,不经过模型选择;
- 卸载后同一 profile 重启,没有被测 bundle、能力或可归因残留;
- 必需的 observer 可用,缺少必需覆盖记为
unsupported,不会合成一个「通过」。
反过来,通过也不代表任意可执行代码安全、模型输出良好或未断言的行为可用。
行为与洁净度验证¶
行为侧的手段包括:确定性运行时探针、声明的工具调用、可选的 loopback HTTP 路由断言,以及显式的浏览器 smoke 测试。HTTP 与浏览器流量限制在 runner 自有的 127.0.0.1;缺少 Chromium 记为 unsupported。
卸载洁净度验证覆盖:同 profile 重启、能力检查、owned-path 残留、进程与端口检查。
安装与启用¶
运行要求:Node.js 22 或更新版本,以及 Docker(Docker 是默认 runner)。
安装为 devDependency:
pnpm add -D dsh-testkit
安装后 CLI 入口为 dsh-test,最短路径是先生成场景,再执行测试:
pnpm dsh-test init
pnpm dsh-test
典型用法¶
dsh-test init 生成场景¶
dsh-test init 离线运行,定位最近的 Git worktree,生成三个可审查的文件:
<plugin-root>/dsh-testkit.yaml:包含精确 DSH 版本与探测到的行期望;<repository-root>/.github/workflows/dsh-lifecycle.yml:默认只读 token 契约与正确的嵌套路径;<repository-root>/.agents/skills/dsh-testkit/SKILL.md:让兼容的编码智能体执行同一道门槛。
生成是字节级幂等的,并对所有目标做预检;发现冲突会停止全部写入,除非显式传 --force。如果被测 bundle 在仓库根目录之下:
pnpm dsh-test init plugin/
pnpm dsh-test --config plugin/dsh-testkit.yaml
场景即代码¶
场景是 schemaVersion: 1 的 YAML。init 生成的起始场景大致如下:
schemaVersion: 1
name: my-plugin-quick
subject:
source: .
dsh:
version: 0.1.1-rc.2
expect:
boot: success
rows: [tool-my-plugin]
services: [myService]
tools: [my_tool]
exercise:
- tool: my_tool
arguments:
value: smoke
observers:
filesystem: required
process: preferred
ports: preferred
network: off
canary: preferred
expect 声明 boot 结果、配置行、services 与 tools,exercise 声明要执行的工具调用。本地目录 subject 以只读方式挂载,复制到 runner 拥有的可写根目录后再打包;声明了 prepare、prepack 或 postpack 时,会在副本内按 packageManager 与 lockfile 恢复依赖再 npm pack,原始检出不会被改动。场景还支持 http.routes、更新目标、预期失败与恢复、阶段重跑、observer 策略与全局 watchdog,细节见仓库内的 Scenario Reference。
对提供 DSH web 路由的插件,设置 profile: web 并添加仅 Docker 的断言,例如要求 /health 返回 200:
profile: web
http:
routes:
- id: health
path: /health
expect:
status: 200
json:
status: ok
version: $subject.packageVersion
CI 集成¶
生成的 workflow 默认使用只读 token,并把这一契约写进文件:
permissions:
contents: read
steps:
- uses: iiwish/dsh-testkit/.github/actions/dsh-test@v0
with:
plugin: .
dsh-version: 0.1.1-rc.2
config: dsh-testkit.yaml
publish-junit-check: 'false'
默认行为是把 JUnit 注解写进 job、上传完整证据目录,并给出 artifact ID、URL、digest、报告路径与稳定退出码,不调用 Checks API。受信任的 push 或 release workflow 可以开启命名 JUnit Check:
permissions:
contents: read
checks: write
steps:
- uses: iiwish/dsh-testkit/.github/actions/dsh-test@v0
with:
plugin: .
dsh-version: 0.1.1-rc.2
publish-junit-check: 'true'
开启 publish-junit-check 需要 checks: write 权限,且不要对不受信任的 fork PR 启用。GitHub Enterprise Server 与其他 CI 系统可以直接调用 CLI。
报告与退出码¶
报告落在 .dsh-testkit/runs/:canonical 的 report.json、CI 可用的 junit.xml、可读的 report.md、脱敏命令日志与有界阶段证据。
退出码是稳定的,脚本可以直接按它分支:
| 退出码 | 含义 |
|---|---|
| 0 | 通过 |
| 1 | 生命周期失败 |
| 2 | 输入无效 |
| 3 | 基础设施错误 |
| 4 | 不支持 |
| 5 | flaky |
适用场景与注意¶
适合谁:维护 DSH 插件的作者、审查发布 PR 的维护者、运营插件模板的团队,以及需要可复现宿主级 bug 报告的人。
使用前注意几点:
- 每次隔离生命周期只测一个被测插件;多插件的所有权与更新顺序是组合层面的问题;
- 适配器只接受前文列出的四个精确 DSH 版本,其他版本以退出码 4 终止;
- 一个「通过」不代表任意可执行代码安全、模型输出良好或未断言行为可用,它也不是安全认证;
- 两个 alpha 版本仅进 canary 矩阵,不在默认支持范围内。
安全方面需要说明:在 DSH 生态里,插件以当前 dsh 进程的权限运行,安装任何插件前都应检查其源码与许可证。dsh-testkit 本身以 npm devDependency 形式安装,许可证为 MIT,源码公开;它不做模型调用,CI 侧默认最小权限(只读 token)。
小结¶
dsh-testkit 把发布验证从「我本地能跑」推进到「这个打包产物在精确的真实宿主上装得上、跑得动、卸得干净,并且留下了证据」。对维护 DSH 插件的团队来说,把它挂在发布 PR 和 tag 上,是一种成本可控的把关方式。
- 插件目录页:https://www.skillhub.cn/plugins/iiwish/dsh-testkit
- GitHub 仓库:https://github.com/iiwish/dsh-testkit
目录页为社区维护的独立站点,与 DeepSeek / 幻方无官方从属关系。