Back to home@988hj7tczd-oss

dsh-dep-vuln-scan

Scan project lockfiles (npm/pnpm/yarn/pip/go/cargo/maven/gradle) against the free OSV API and report confirmed dependency vulnerabilities with fix versions

Stars
0
Language
TypeScript
Created
Aug 24, 2026
Updated
Aug 24, 2026

Introduction

dsh-dep-vuln-scan

[!IMPORTANT] 依赖前置:相邻 dsh-src 检出(link: 依赖) 本项目在开发形态下使用 link: 依赖指向相邻的 DeepSeek Harness 源码检出(dsh-src), 与当前仓库保持同一父目录布局(<parent>/dsh-src)。克隆本仓库后:

  1. 先把官方 deepseek-ai/deepseek-harness 检出到与本仓库同级的 dsh-src/ 目录,并执行其 pnpm install && pnpm run build
  2. 再按下方「安装」一节执行本仓库的 pnpm install --offline && pnpm build 与测试。 发布到 npm 的版本会尽量把 link: 依赖替换为 registry 真实版本;无法替换的内部包保持 link:,见各包 README 说明。

DSH(DeepSeek Harness)原生依赖漏洞扫描工具:读取工作区内项目锁文件,调用 OSV 免费 APIapi.osv.dev,无需 key)批量查询漏洞,输出「包 / 当前版本 / 漏洞 ID(CVE/GHSA 优先)/ 摘要 / CVSS / 修复版本」表格 + 汇总 + 修复命令,结果通过 presentationMeta 持久化到 tool/result,回放可复制。

只读分析:不写、不改、不装任何文件 —— 修复命令仅作建议,由用户确认后自行执行(与上游 remediation posture 一致)。

功能一览

能力说明
生态支持npm(package-lock.json/pnpm-lock.yaml/yarn.lock)、PyPI(requirements.txt/Pipfile.lock/poetry.lock)、Go(go.mod)、crates.io(Cargo.lock)、Maven(pom.xml/build.gradle*)、NuGet(packages.lock.json)、RubyGems(Gemfile.lock
数据源OSV POST /v1/querybatch,零配置、免费、商用友好
确认口径仅展示确认存在的漏洞:查询带 version 让 OSV 过滤 + 本地 introduced ≤ version < fixed 区间复核(verifier 口径)
修复信息取 affected ranges 中最早 fixed;有修复版标 √ 有修复版 <版本>,否则「无修复版」
严重度CVSSv3 数值(≥9 critical / ≥7 high / ≥4 medium / <4 low),无数值时用 OSV qualitative 关键词
effortfast(默认):只查根锁文件、并发 4、无 SBOM;full:递归子目录(跳过 node_modules 等)、并发 16、生成 SBOM 摘要
健壮性分块(250/批)批量查询、并发池、30s 超时、2 次重试退避、HTTP 429 按 Retry-After 等待;所有失败以结构化 errors 返回,不阻塞会话
持久化output.presentationMeta 投影整个报告 → tool/result.meta,UI 卡片回放可复制

安装与使用

作为 DSH 插件 bundle 安装进 profile:

# 1. 构建(产出 lib/,bundle 行引用 dsh-dep-vuln-scan/lib/index.js)
pnpm install && pnpm build

# 2. 加入 profile(声明了 dsh.bundle,dsh 会把本包作为配置层挂载)
dsh plugin --profile demo add ./dsh-dep-vuln-scan

# 3. 验证挂载
dsh --profile demo --dump-config | grep -A2 dep-vuln-scan

安装后,模型可直接调用工具(系统提示词已注册引导片段):

dep_vuln_scan(path?: string, ecosystems?: string[], effort?: 'fast'|'full')
  • path:项目目录或单个锁文件路径,省略 = 工作区根(自动发现根级锁文件);
  • ecosystems:过滤(npm / pypi / go / crates / maven / nuget / rubygems,大小写不敏感,也接受别名如 pip/cargo/java);
  • effort:默认 fastfull 时递归发现 + 并发 16 + SBOM 摘要段。

架构与文件

dsh-dep-vuln-scan/
├── cordis.yml            # dsh.bundle.patch 层:insert 插件行
├── package.json          # dsh.bundle 声明 + exports(./lib/*)
├── src/
│   ├── index.ts          # 装配:注册工具 + systemPrompt 引导片段(name/inject/apply)
│   ├── tools/dep-scan.ts # defineTool 定义 + 扫描编排(FsAdapter 注入 + ctx.fs 适配)
│   ├── lockfile-parsers.ts # 各生态锁文件 → [(name, version)](纯函数)
│   ├── osv-client.ts     # querybatch 分块/并发/重试/超时/错误分类 + 漏洞归一化
│   ├── report.ts         # 报告组装 + render(markdown 表格/汇总/修复命令)+ presentationMeta
│   └── semver.ts         # 最小语义化比较(无运行时依赖)
├── tests/
│   ├── smoke.e2e.ts      # 27 项离线冒烟/E2E + 1 项 live(网络可用时)
│   └── fixtures/         # npm/pip/go/clean/full 五个 fixture 项目 + 录制 OSV 响应
└── tsconfig{,.build}.json

插件模块符合 Cordis 规范:export const name / inject = ['tools','fs','systemPrompt'] / apply(ctx)ctx.tools.register(defineTool(...))ctx.systemPrompt.section({...}) 均为 effect 注册,插件卸载自动清理。

为什么用全局 fetch 而不是 ctx.web

PROMPT 建议走 ctx.web seam,但 dsh-web 的 fetch seam 只支持对单个 URL 的 GET 检索(返回 HTML/text 正文),不支持 OSV 需要的 POST /v1/querybatch + JSON body。因此默认 transport 使用宿主进程全局 fetch —— 与内置 @deepseek-ai/dsh-web-fetch-http provider 完全相同的传输层 —— 并遵循 seam 的约定:服从调用方 AbortSignal、超时合并、结构化错误。transport 本身可注入,测试用本地 stub 覆盖。

测试

pnpm test          # 离线:解析器单测 + 录制 OSV 响应走真实客户端代码路径(分块/重试/解析/归一化)
pnpm test:live     # 额外跑一次真实 api.osv.dev 查询(网络不可用时自动跳过)
pnpm typecheck
  • 三种生态 fixture(npm/pip/go)各自断言:命中漏洞、fixed 版本、修复命令(npm install lodash@4.17.21 / pip install pillow==9.0.0 / go get golang.org/x/text@0.3.7);
  • clean fixture 断言报告输出 0 受影响
  • 无网络(transport 抛错)断言错误信息含「无法访问 OSV,检查网络或稍后重试」且不抛异常;
  • fast/full 断言根扫描 1 个锁文件 vs 递归 2 个 + SBOM 差异。

录制 fixture 为「快照式」响应:内容对齐已公开公告(CVE 编号与修复版本为稳定公开事实,测试只断言这些字段),离线可用;需要最新数据时以 pnpm test:live 结果为准。

已知限制

  • pnpm-lock.yaml / yarn.lock 用行级解析(不引入 YAML 依赖):pnpm 的 peer 后缀、yarn berry(v2+ __metadata:)会被跳过,仅覆盖常见形态;
  • pom.xml/gradle 只识别字面量版本,${property} 版本跳过;依赖树传递性不做解析(以锁文件记录为准);
  • requirements.txt 仅精确 == 版本可查,>=/~=/裸包名跳过;
  • 扫描上限:递归深度 8、锁文件 200 个,超大 monorepo 建议按子目录分别扫描。

License

MIT — 扫描逻辑按 OSV 口径自写;修复建议文案参考 wshobson/agents(MIT)的 remediation posture(只建议、不自动改动)。