pnpm audit 漏洞摘要“净额”统计:被 auditConfig 忽略的漏洞不再计入结果
【免费下载链接】pnpmFast, disk space efficient package manager项目地址: https://gitcode.com/gh_mirrors/pn/pnpm
导读
pnpm audit的摘要输出此前会把被auditConfig.ignoreGhsas显式忽略的漏洞继续算进总数,导致“红色高危数字 + 零退出码”并存的矛盾观感。本仓库的 changeset audit-summary-net-of-ignored.md 记录了这一行为的修正:摘要标题与Severity:分解现在只统计经过过滤后“存活”的漏洞,被忽略的漏洞单独成行展示,全部被忽略时输出友好提示。读完本文,你将掌握该行为变更的三种输出场景、auditConfig配置方法,以及 Rust(pnpm)与 TypeScript(pnpm11)两套实现与测试的对应关系。
一、变更背景:红色数字与零退出码的矛盾
在本次变更之前,pnpm audit的摘要会统计全部advisories,包括那些已在pnpm-workspace.yaml的auditConfig.ignoreGhsas中显式忽略的条目。由此产生一个让用户困惑的场景:
- 若项目中的所有漏洞都被显式忽略,摘要仍然打印红色的
1 vulnerabilities found; - 但由于没有“存活”漏洞,命令又返回退出码 0。
一个 “红色的漏洞数字” 与 “成功的退出码” 同时出现,既不符合直觉,也容易误导 CI 脚本与开发者的判断(该问题记录于上游 issue #14535,见 changeset 内文)。本次 patch 的目标就是让摘要输出与真实处理结果保持一致:摘要只反映“经过 ignoreGhsas 过滤后仍然存活的漏洞”。
二、行为变更的三个核心要点
根据 audit-summary-net-of-ignored.md,本次变更涉及@pnpm/deps.compliance.commands、pnpm、pacquet三个包,具体包含三点:
- 标题总数只计存活漏洞:摘要中的 headline total 不再包含被
auditConfig.ignoreGhsas抑制的 advisories。 Severity:分解同步净额化:严重级别计数(info/low/moderate/high/critical)同样只统计过滤后存活的数量。- 被忽略的漏洞单独成行:若存在被抑制的漏洞,会追加一行形如
2 ignored: 1 moderate | 1 critical的摘要,按严重级别列出被忽略的数量。
变更前后输出对比
| 场景 | 变更前 | 变更后 |
|---|---|---|
| 有存活漏洞,且部分被忽略 | 总数与 Severity 包含被忽略项 | 总数与 Severity 只含存活项,另起一行N ignored: … |
| 全部漏洞均被忽略 | 红色1 vulnerabilities found+ 退出码 0 | All found vulnerabilities were already reviewed and decided to be ignored+ 退出码 0 |
| 无任何漏洞 | No known vulnerabilities found | 不变 |
第三种“全被忽略”场景正是本次修复的核心:输出由红色的1 vulnerabilities found变为一句明确的说明——All found vulnerabilities were already reviewed and decided to be ignored(“所有发现的漏洞都已被审查并决定忽略”)。
三、如何配置:pnpm-workspace.yaml 中的 auditConfig.ignoreGhsas
被忽略漏洞的来源是工作区配置文件中的auditConfig字段。在项目根目录的pnpm-workspace.yaml中添加:
auditConfig: ignoreGhsas: - GHSA-ignr-1111-2222 - GHSA-xxxx-3333-4444ignoreGhsas是一个 GHSA(GitHub Security Advisory)ID 字符串数组,列出的 advisories 在执行pnpm audit时会被过滤掉。仓库集成测试 audit.rs 中即使用了这种写法;测试辅助函数audit_config_ignore_ghsas(见 audit.rs)也从pnpm-workspace.yaml解析出精确的auditConfig.ignoreGhsas列表,用于校验过滤行为。
在 TypeScript 实现中,过滤时会对 GHSA ID 做归一化(normalizeGhsaId)再与 advisory 上的github_advisory_id比较,从而保证用户以不同大小写存储的条目也能匹配到规范形态(见 audit.ts)。
四、源码级实现:Rust 端 report_summary
Rust(pnpm)侧的核心实现在 render.rs 的report_summary函数中:
- 被忽略漏洞的总数与严重级别计数由调用方传入的
ignored: &AuditVulnerabilityCounts携带; - 若
total_ignored_count > 0,追加\n{total} ignored: {severity counts}行(按count severity格式、以|连接,见list_severity_counts,render.rs); - 当
total_vulnerability_count == 0时,若存在忽略项,headline 输出All found vulnerabilities were already reviewed and decided to be ignored,否则输出No known vulnerabilities found; - 当仍有存活漏洞时,输出
{N} vulnerabilities found(红色)与Severity: …,随后再接 ignored 行(render.rs)。
render_text_report(render.rs)负责先按严重级别降序渲染各 advisory 表格,再调用report_summary收尾,确保表格与摘要之间以换行分隔(对应测试text_report_separates_advisory_table_from_summary)。
五、源码级实现:TypeScript 端 reportSummary
TypeScript(pnpm11)侧有行为一致的平行实现。过滤逻辑位于 audit.ts:读取opts.auditConfig?.ignoreGhsas,命中则将该 advisory 从auditReport.advisories中剔除,并累加到ignoredVulnerabilities计数对象中。
摘要生成函数reportSummary(audit.ts):
- 通过
totalIgnoredCount === 0判断是否追加\n{N} ignored: {severity counts}; totalVulnerabilityCount === 0时按是否有关忽略项选择 headline:No known vulnerabilities found或All found vulnerabilities were already reviewed and decided to be ignored;- 否则输出红色总数与
Severity:分解,再接 ignored 行。
同时,返回的exitCode与存活漏洞绑定:exitCode: output ? 1 : 0(audit.ts)。也就是说,全部漏洞被忽略时输出体为空、退出码为 0,与新的友好 headline 语义一致——不再出现“红字却成功退出”的误导。
六、测试验证:三个关键断言
仓库为本次行为变更提供了单元测试与集成测试双重验证:
- 单元测试(Rust):位于 tests.rs:
text_report_summary_omits_advisories_fully_suppressed_by_ignore_ghsas:断言全被忽略时输出精确为All found vulnerabilities were already reviewed and decided to be ignored\n1 ignored: 1 high\n;text_report_summary_excludes_ignored_advisories_from_severity_counts:验证忽略项从 Severity 计数中剔除、单独成行。
- 集成测试(Rust CLI):
pnpm/crates/cli/tests/suite/audit.rs中模拟了配置了auditConfig.ignoreGhsas的 workspace,断言标准输出以1 vulnerabilities found\nSeverity: 1 moderate\n1 ignored: 1 high\n结尾(audit.rs),并逐项验证 headline 文案。 - TypeScript 测试:测试夹具
has-vulnerabilities-with-ignored-ghsas/pnpm-workspace.yaml(fixtures)与快照(index.ts.snap)共同固定了N ignored: …输出行格式。
七、使用建议与注意事项
- CI 中区分“有风险”与“已决策”:变更后,
pnpm audit的退出码与红色摘要只反映“未被忽略的存活漏洞”,因此 CI 可以放心地同时使用摘要文本与退出码判断是否失败,不会再被忽略项的残留数字干扰。 - 被忽略项仍然可见:
N ignored: …独立成行,团队仍能一眼看到被审查决策覆盖的漏洞数量及其严重级别分布,便于定期复盘。 - 两端行为对齐:Rust 原生 CLI(
pnpm)与 TypeScript 实现(pnpm11)对 headline、Severity:分解与 ignored 行的格式保持一致,跨实现切换不会出现输出差异。 - 忽略 ID 的写法:
ignoreGhsas使用 GHSA ID(GHSA-xxxx-xxxx-xxxx格式),实现层会做归一化比较,但建议配置时统一使用规范大写形式,便于阅读与维护。
小结
本次变更让pnpm audit的摘要输出回归“所见即所得”:标题总数与Severity:分解只反映真实存活的漏洞,被auditConfig.ignoreGhsas忽略的条目以2 ignored: 1 moderate | 1 critical形式独立呈现,而“全部被忽略”的极端场景也从矛盾的红色数字改为明确的人类可读提示。通过 render.rs(Rust)与 audit.ts(TypeScript)两套平行实现以及配套单元/集成测试,你可以清晰地追踪这一语义从过滤、计数到渲染的完整链路。
【免费下载链接】pnpmFast, disk space efficient package manager项目地址: https://gitcode.com/gh_mirrors/pn/pnpm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考