🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

变更覆盖证明 Apageoflove/DSH-changeproof

DeepSeek Harness
Apageoflove46 天前有提交已提供中文文档扫描:含敏感能力

DeepSeek Harness 插件:确认改动的代码行真的被测试覆盖到,结论绑定代码指纹,代码一变自动过期

36.1/100
综合分
5
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/22 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Apageoflove/DSH-changeproof
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · dev
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 46 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

未发布到 npm registry,仅可从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-changeproof(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20.11.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/31 10:23:10

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 51 处,展示前 36 条)
  • 读取本地文件
    dist/host/cordis-plugin.mjs:90
    const st = await stat(absPath);
  • 读取本地文件
    dist/host/cordis-plugin.mjs:102
    const buf = await readFile(absPath);
  • 读取本地文件
    dist/host/cordis-plugin.mjs:107
    await lstat(absPath);
  • 读取本地文件
    dist/host/cordis-plugin.mjs:115
    const st = await lstat(absPath);
  • 读取本地文件
    dist/host/cordis-plugin.mjs:122
    const st = await stat(absPath);
  • 读取本地文件
    dist/host/cordis-plugin.mjs:131
    const rootReal = await realpath(rootAbs);
  • 执行外部命令来自配置/变量
    dist/host/cordis-plugin.mjs:204
    child = spawn(argv[0], argv.slice(1), {
  • 写入本地文件
    dist/host/cordis-plugin.mjs:2735
    await mkdir(this.dirAbs, { recursive: true });
  • 写入本地文件
    dist/host/cordis-plugin.mjs:2752
    await writeFile(file, next, { encoding: "utf8" });
  • 写入本地文件
    dist/host/cordis-plugin.mjs:2785
    await mkdir(this.dirAbs, { recursive: true });
  • 写入本地文件
    dist/host/cordis-plugin.mjs:2821
    await mkdir2(path4.dirname(this.fileAbs), { recursive: true });
  • 写入本地文件
    dist/host/cordis-plugin.mjs:2822
    await writeFile2(this.fileAbs, JSON.stringify(container, null, 2), { encoding: "utf8" });
  • 读取本地文件
    dist/host/index.mjs:125
    const st = await stat(absPath);
  • 读取本地文件
    dist/host/index.mjs:137
    const buf = await readFile(absPath);
  • 读取本地文件
    dist/host/index.mjs:142
    await lstat(absPath);
  • 读取本地文件
    dist/host/index.mjs:150
    const st = await lstat(absPath);
  • 读取本地文件
    dist/host/index.mjs:157
    const st = await stat(absPath);
  • 读取本地文件
    dist/host/index.mjs:166
    const rootReal = await realpath(rootAbs);
  • 执行外部命令来自配置/变量
    dist/host/index.mjs:239
    child = spawn(argv[0], argv.slice(1), {
  • 写入本地文件
    dist/host/index.mjs:2789
    await mkdir(this.dirAbs, { recursive: true });
  • 写入本地文件
    dist/host/index.mjs:2806
    await writeFile(file, next, { encoding: "utf8" });
  • 写入本地文件
    dist/host/index.mjs:2839
    await mkdir(this.dirAbs, { recursive: true });
  • 写入本地文件
    dist/host/index.mjs:2875
    await mkdir2(path4.dirname(this.fileAbs), { recursive: true });
  • 写入本地文件
    dist/host/index.mjs:2876
    await writeFile2(this.fileAbs, JSON.stringify(container, null, 2), { encoding: "utf8" });
  • 读取本地文件
    dist/host/cli.mjs:212
    const st = await stat(absPath);
  • 读取本地文件
    dist/host/cli.mjs:224
    const buf = await readFile(absPath);
  • 读取本地文件
    dist/host/cli.mjs:229
    await lstat(absPath);
  • 读取本地文件
    dist/host/cli.mjs:237
    const st = await lstat(absPath);
  • 读取本地文件
    dist/host/cli.mjs:244
    const st = await stat(absPath);
  • 读取本地文件
    dist/host/cli.mjs:253
    const rootReal = await realpath(rootAbs);
  • 执行外部命令来自配置/变量
    dist/host/cli.mjs:326
    child = spawn(argv[0], argv.slice(1), {
  • 写入本地文件
    dist/host/cli.mjs:2761
    await mkdir(this.dirAbs, { recursive: true });
  • 写入本地文件
    dist/host/cli.mjs:2778
    await writeFile(file, next, { encoding: "utf8" });
  • 写入本地文件
    dist/host/cli.mjs:2811
    await mkdir(this.dirAbs, { recursive: true });
  • 写入本地文件
    dist/host/cli.mjs:2847
    await mkdir2(path4.dirname(this.fileAbs), { recursive: true });
  • 写入本地文件
    dist/host/cli.mjs:2848
    await writeFile2(this.fileAbs, JSON.stringify(container, null, 2), { encoding: "utf8" });
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 确认改动行测试覆盖
  • 结论绑定代码指纹
  • 代码变更自动过期

README

由 DeepSeek 最新模型翻译生成
DSH-changeproof(变更证明 ChangeProof) DeepSeek Harness(DSH)插件:代码改动后,确认改动的行真的被测试覆盖到。 解决的问题 "测试通过"不等于"改动被验证": - 改的是 A 文件,测试跑的是 B 文件,全绿但改动没被测到; - 测试跑了,但只执行到改动行的一部分,剩余行没测到,照样报通过; - 验证完成后代码又被修改,旧结论仍然有效,无人察觉。 插件做三件事: 1. 关联测试:根据代码引用关系,找出与本次改动相关的测试(不是全量跑,也不是猜); 2. 行级核对:执行测试后逐行核对,改动行未被执行到则不予通过,并明确指出未覆盖的行; 3. 结论过期:证据绑定代码指纹,代码一变,旧结论自动失效。 结论状态:VERIFIED(通过)、PARTIAL(部分覆盖)、FAILED(测试失败)、STALE(结论过期)、UNVERIFIED(无有效证据)、NOT_APPLICABLE(无可验证内容)。 底线:没有覆盖证据,或证据与当前代码不一致,一律不给 VERIFIED。 部署到 DSH 以下步骤在 Windows 实测通过(macOS / Linux 命令相同)。
展开完整文档(README 剩余 1 节)
DSH-changeproof(变更证明 ChangeProof)

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
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 写法;
- 该扫描为静态启发式检查,非安全审计;审阅请以「执行安全模型」一节为准。
预览分享卡片长什么样 ↓Apageoflove/DSH-changeproof
分享 · DeepSeek Harness Hub
Apageoflove/DSH-changeproof

DeepSeek Harness 插件:确认改动的代码行真的被测试覆盖到,结论绑定代码指纹,代码一变自动过期

这是你的仓库?认领条目

回到顶部