为什么我不再信任 npm audit(并自己动手构建)
Source: Dev.to
从 package-lock.json 生成 CycloneDX SBOM 与可审计的确定性风险报告
你运行 npm audit,它显示 “47 个漏洞”。
酷。到底哪些是真正重要的?生产环境的 bundle 中的那个?你根本不知道。
于是你只能:
- 什么都不管 → 直接发布
- 无论如何都失去信号
真正的问题不是漏洞——而是决策。
真正的问题不是漏洞——而是决策
大多数工具只能回答:
“哪里出问题了?”
它们却不回答:
“我该怎么处理?”
最后这个问题才是核心。
于是出现:audit‑ready
它不提供分数,而是给出决策。确定的、可复现的、可审计的。
🔑 reasonCode 取代 CVSS
每个依赖只会得到唯一的标签,例如:
DEV_DEPENDENCY_ONLY
无需解释。CI 变得轻而易举——不再是 “7 个高危漏洞”。
🧠 约束决定一切
相同的 package-lock.json → 完全相同的输出。始终如此。
约束的实现方式
核心逻辑中有硬性约束:
const banned = ['Date', 'Date.now()', 'Math.random()', 'process.env'];
如果确定性被破坏 → 构建失败。
⚙️ 引擎刻意保持简单
没有评分,也没有启发式。
先匹配即为胜出——优先级由规则顺序决定。
🧾 你真的能用的输出
所有内容都与 reasonCode 关联。
🔐 安全性:该工具自审计
如果你在生成审计产物,工具本身必须值得信赖。
没有环境访问
核心引擎根本无法读取:
- 环境变量
输出仅取决于输入 + 工具版本
确定性的 PURL 生成
标准编码器(encodeURIComponent、URL)在不同 Node 版本间可能表现不一致,因此 PURL 手动构建。
- 同一包 → 同一 PURL → 永远一致
模式校验(输入 + 输出)
如果校验失败 → 不会写入任何内容。
不可变的输出
没有静默的变更。异常不能永久存在;每个异常都必须给出理由。过期?audit-ready audit-exceptions → 退出码 1。没有静默忽略。
设计上的网络安全
仅有一次外部调用:
- 使用 PURL 的 OSV API
如果调用失败,SBOM 仍会生成。工具在自身上运行同样的流水线——相同代码、相同规则。如果它撒谎,就会自曝其短。
⚠️ 该工具不做的事
如果遇到未覆盖的情况 → 会大声报错。
为什么这很重要
这并不是为了更好的扫描,而是为了可复现的决策。生产发布计划在第 3 阶段之后。
💬 征求反馈
https://github.com/neve7er/audit-ready
最后思考
大多数工具想要“聪明”。这个工具想要“可预测”。因为在安全领域,可预测性胜过智能。