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)。克隆本仓库后:
- 先把官方
deepseek-ai/deepseek-harness检出到与本仓库同级的dsh-src/目录,并执行其pnpm install && pnpm run build;- 再按下方「安装」一节执行本仓库的
pnpm install --offline && pnpm build与测试。 发布到 npm 的版本会尽量把link:依赖替换为 registry 真实版本;无法替换的内部包保持link:,见各包 README 说明。
DSH(DeepSeek Harness)原生依赖漏洞扫描工具:读取工作区内项目锁文件,调用 OSV 免费 API(api.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 关键词 |
| effort | fast(默认):只查根锁文件、并发 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:默认fast;full时递归发现 + 并发 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(只建议、不自动改动)。