Workflow & Automation

dsh-changeproof

apageoflove/dsh-changeproof · ★ 5

apageoflove

DeepSeek Harness plugin that verifies whether changed lines are actually covered by tests.

README body is shown in Chinese.

License
MIT
Added
2026-08-23
Maintenance
active
Install kind
github

No manifest check is available; listing does not imply compatibility or security review.

安装

dsh plugin --profile web add github:apageoflove/dsh-changeproof

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: zh · Read Chinese README

Table of contents
  1. 解决的问题
  2. 部署到 DSH
  3. 前提
  4. 1. 获取 DSH 源码
  5. 2. 构建 DSH
  6. 3. 构建插件
  7. 4. 安装到 profile
  8. 5. 验证安装
  9. 6. 使用
  10. 卸载
  11. 分发
  12. 独立使用(不装 DSH)
  13. 被验证项目的配置
  14. 技术要点
  15. 执行安全模型
  16. 测试
  17. 目录结构
  18. 仓库
  19. License
  20. dsh.so 提交说明

DeepSeek Harness(DSH)插件:代码改动后,确认改动的行真的被测试覆盖到。

解决的问题

"测试通过"不等于"改动被验证":

  • 改的是 A 文件,测试跑的是 B 文件,全绿但改动没被测到;
  • 测试跑了,但只执行到改动行的一部分,剩余行没测到,照样报通过;
  • 验证完成后代码又被修改,旧结论仍然有效,无人察觉。

插件做三件事:

  1. 关联测试:根据代码引用关系,找出与本次改动相关的测试(不是全量跑,也不是猜);
  2. 行级核对:执行测试后逐行核对,改动行未被执行到则不予通过,并明确指出未覆盖的行;
  3. 结论过期:证据绑定代码指纹,代码一变,旧结论自动失效。

结论状态:VERIFIED(通过)、PARTIAL(部分覆盖)、FAILED(测试失败)、STALE(结论过期)、UNVERIFIED(无有效证据)、NOT_APPLICABLE(无可验证内容)。

底线:没有覆盖证据,或证据与当前代码不一致,一律不给 VERIFIED。

部署到 DSH

以下步骤在 Windows 实测通过(macOS / Linux 命令相同)。

前提

  • Node.js ≥ 24(DSH 要求 ^22.19 || >=24)
  • pnpm 11.7(npm install -g pnpm@11.7.0)
  • Git

1. 获取 DSH 源码

git clone --depth 1 https://gitee.com/mirrors/deepseek-harness.git DSH
# GitHub 直连:git clone --depth 1 https://github.com/deepseek-ai/deepseek-harness.git DSH
cd DSH

2. 构建 DSH

pnpm install
pnpm run build:lib
pnpm run build:web   # 仅使用 headless 可跳过

3. 构建插件

cd <插件目录>        # 如 E:\agent\dsh-changeproof
npm install
npm run build        # 产物在 dist/

4. 安装到 profile

cd <DSH 目录>
pnpm dsh plugin --profile web add <插件目录>
# 需要命令行模式再加:pnpm dsh plugin --profile headless add <插件目录>

5. 验证安装

pnpm dsh --profile web --dump-config | grep changeproof
# 输出包含 "# == dsh-changeproof" 即安装成功

6. 使用

# 图形界面
pnpm dsh web    # 访问 http://localhost:3080,设置中填入 API Key

# 命令行(需 DEEPSEEK_API_KEY 环境变量)
export DEEPSEEK_API_KEY=sk-xxxxxxxx
pnpm dsh --profile headless "修改 src/calc.ts 的折扣为 75 折并验证"

模型修改代码后会自动调用 changeproof_verify 验证(插件自带工作流规则,无需手动触发)。

卸载

pnpm dsh plugin --profile web remove dsh-changeproof

分发

  • 对方获得插件目录后按步骤 4 add 本地路径;
  • 发布到 npm 后(暂未发布):pnpm dsh plugin add dsh-changeproof。

独立使用(不装 DSH)

cd <插件目录>
npm install && npm run build

node dist/host/cli.mjs plan   --workspace <项目路径>   # 仅分析
node dist/host/cli.mjs verify --workspace <项目路径> --yes   # 执行测试
node dist/host/cli.mjs status --workspace <项目路径>   # 结论是否过期

verify 不带 --yes 仅打印将执行的命令,确认后加 --yes 才执行。

被验证项目的配置

项目根目录放置 .changeproof.yml:

schemaVersion: 1
packages:
  - id: web
    root: packages/web
    languages: [typescript]
    include: [packages/web/src/**/*.ts]
    test:
      adapter: vitest-istanbul    # 支持 vitest / jest / pytest
      argv: [pnpm, vitest, run, --coverage]
      cwd: packages/web
      timeoutMs: 120000
      coverageFile: packages/web/coverage/coverage-final.json
thresholds: { changedLines: 1.0, minimumImpactConfidence: MEDIUM }
exclude: ["**/generated/**", "**/*.d.ts"]

字段说明见 docs/configuration.md。

技术要点

  • 技术栈:TypeScript / Node.js(≥20.11)/ ESM;测试用 vitest + fast-check;覆盖率适配 Istanbul(vitest/jest)与 coverage.py(pytest)
  • 架构:Host(分析、执行、证据存储)与 DSH 绑定层分离——绑定层在 src/host/adapters/dsh/ 单目录,其余代码零 DSH 依赖;同时提供独立 CLI,不装 DSH 也能用
  • 影响解析:四级来源(配置显式映射 → 历史覆盖记录 → 静态 import graph → 命名约定),按 (包, 测试集) 合并,置信度取最高可信值
  • 覆盖率口径:分母 = 本次改动行中 adapter 可靠识别为可执行的行;删除行不计入分母,单独记为风险
  • 证据与过期:workspace 指纹覆盖源文件/测试/lockfile/runner 配置/插件配置;证据绑定指纹,代码一变自动判 STALE
  • 执行安全:argv-only(禁止 shell 字符串)、cwd 路径牢笼(realpath 二次校验)、环境变量白名单、超时 + 进程树终止、输出上限 + digest
  • 判定底线:exit 0 但无覆盖产物 / 解析错误 / 低置信度映射 → 一律不给 VERIFIED

执行安全模型

插件会执行用户配置的测试命令,因此对子进程执行做了显式加固(不是依赖"信任配置"):

  • argv-only:命令是 argv 数组,直接 spawn 执行,不经 shell,绝不拼接 shell 字符串;空参数、含 NUL 的参数一律拒绝
  • 配置防御:校验配置时默认拒绝长得像 shell 命令行(含 &&、||、; 、换行等)的 argv 条目;CP_ALLOW_SHELLY_ARGV=1 是显式的逃生开关,默认关闭
  • 环境变量白名单:子进程只拿到显式传入的白名单环境,不继承宿主完整环境
  • cwd 路径牢笼:工作目录经 realpath 二次校验,防止软链接逃逸到预期目录之外
  • 超时 + 进程树终止:超时或取消时 Windows 用 taskkill /T /F、POSIX 用负进程组 SIGKILL,回收整棵进程树,不留孤儿进程
  • 输出上限:stdout/stderr 有字节上限,超限截断并记录 digest,防止失控输出撑爆内存

代码位置:src/host/config/schema.ts(argv 校验)、src/host/execution/process-tree.ts(进程树终止)、src/host/adapters/dsh/subprocess-port.ts(受控执行)。

测试

npm test            # 163 项测试
npm run benchmark   # 31 个基准用例(12 个"假绿"场景全部被识破)
npm run verify-package

目录结构

src/shared/      核心模型与状态机(不依赖 DSH)
src/host/        工具、分析引擎、执行器、证据存储
src/host/adapters/dsh/   DSH 绑定层
src/client/      界面组件(预留,未启用)
tests/           测试
fixtures/        测试用真实产物样本
docs/            文档

仓库

https://github.com/Apageoflove/DSH-changeproof

License

MIT

dsh.so 提交说明

针对 dsh.so 插件提交页 的静态扫描报告:

  • 扫描中的 Critical 均为 Node.js 内置子进程模块的用法——插件运行 git 与测试进程的核心功能,实现为 argv-only 安全模式(见上文「执行安全模型」),无 shell 拼接,无法也不应移除;
  • 已将 README 示例中的硬编码回环地址改为 localhost 写法;
  • 该扫描为静态启发式检查,非安全审计;审阅请以「执行安全模型」一节为准。