ci(deps): OSV 门禁的逃生口立三条约定,并把前两条做成机械门禁 (#4965) - #5036
Merged
Conversation
OSV 门禁对**无修复版本**的公告,唯一出路是 `osv-scanner.toml` 的
`[[IgnoredVulns]]`。但仓库里此前没有这个文件,逃生口一次也没走过,也就
没有任何约定:谁能加、写什么理由、多久复核。没有约定的逃生口会在第一次
紧急情况下被随手用坏,然后永久留在那里。
新增零豁免的 `osv-scanner.toml`(三条约定写在文件头 + 一个注释掉的模板
条目)与 `scripts/check-osv-exemptions.mjs`。约定 1、2 机械强制,约定 3
是纪律。
对 osv-scanner v2.3.8 实测(真实二进制 + 离线 OSV 库,故意让 5 条公告命中):
- 缺 `ignoreUntil` → 公告被过滤、退出 0、无任何告警,永久有效。
静默的永久豁免与永远红的 job 是同一个失败模式,只是更安静。
- `ignoreUntil` 已过期 → 公告重新报出、退出 1。**到期转红是 scanner 原生
行为**,所以缺的从来不是过期机制,而是"必须填"这件事。
- `reason = "probe"` → 照单全收,scanner 从不读它。
- `ignoreUntil` 加了引号 → **整个配置文件被丢弃**("Ignored invalid config
file"),扫描照跑;一个引号能让文件里其它所有豁免一起静默失效。
因此 check 脚本要求:`ignoreUntil` 必填、必须是裸 TOML 日期、未过期、且不
超过 90 天上限(默认 30 天 —— 没有上限的话 `2099-01-01` 同样满足"必须带
过期时间",只是给永久豁免戴了顶帽子);`reason` 必填,须含 advisory 链接
与链接之外一句真正的理由;并拒绝 `[[IgnoredVulns]]` 以外的表(
`[[PackageOverrides]]` 也能压掉发现,而三条约定没有覆盖它)。
`--self-test` 双向自证:17 个用例,合法台账判绿、每一条约定违反判红。
零豁免状态下门禁行为与改动前逐条一致:同一 lockfile,带/不带本文件都是
"4 packages / 8 vulnerabilities / exit 1",且日志出现
"Loaded filter from: <repo>/osv-scanner.toml",证明根目录配置确实被发现。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
Author
|
CI 结果说明(本 PR 的 新增 step 在真实 CI 里的输出: scanner step 的失败与本分支无关:同一个 step 在 2026-08-03 19:55 的其它分支上就已经红了(run 30847850410),原因是 顺带,CI 的实时 OSV API 结果与我本地用离线库跑出的 8 条逐条一致,且日志里出现 —— 在真实 runner 上再次确认了根目录台账确实被 Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4965
OSV 门禁对无修复版本的公告,唯一出路是
osv-scanner.toml的[[IgnoredVulns]]。但仓库里此前没有这个文件 —— 逃生口一次也没走过,也就没有任何约定:谁能加、写什么理由、多久复核。没有约定的逃生口会在第一次紧急情况下被随手用坏,然后永久留在那里。本 PR 按维护者裁决落三条约定,前两条做成机械门禁,第三条明确标记为纪律。
落点
osv-scanner.toml(新)scripts/check-osv-exemptions.mjs(新)--self-test双向自证.github/workflows/validate-deps.ymlpaths触发器补上这两个新文件.changeset/osv-exemption-conventions.md根
package.json未改动,没有新增依赖 —— 脚本零依赖,TOML 子集手写解析(与check-override-consistency.mjs手写 pnpm-workspace.yaml 解析同一套做法)。为什么必须有脚本:对 osv-scanner v2.3.8 的实测
用真实二进制 + 离线 OSV 库,在一个故意命中 5 条公告的 lockfile 上逐项验证:
ignoreUntilignoreUntil已过期reason = "probe"ignoreUntil加引号源码侧对应
internal/config/config.go的shouldIgnoreTimestamp:IgnoreUntil为零值时直接返回"应当忽略"。结论(回答 issue 的三个问题):到期转红是 scanner 原生行为,机制本身不缺 —— 缺的是"必须填"。所以脚本不重复实现过期判定的语义,只保证每条豁免都带着一个合法、未过期、且不荒唐的日期存在,让原生机制真的有东西可到期。
约定 1 的机械形状
ignoreUntil必填,必须是裸 TOML 日期(加引号会静默废掉整份文件里其它所有豁免);ignoreUntil = 2099-01-01同样满足"必须带过期时间",只是给永久豁免戴了顶帽子。上限只会随时间推移越来越容易满足,不会把当初写下时合规的条目判红。数值在脚本顶部MAX_WINDOW_DAYS一行可调。约定 2 的机械形状
reason必填,且必须含至少一个https://advisory 链接 + 链接之外至少 40 字符的真正理由。判据是"复核的人能不能据此判断前提是否还成立":Not exploitable六个字给不了任何可核对的东西。另外拒绝
[[IgnoredVulns]]以外的表:[[PackageOverrides]](ignore = true)同样能压掉发现,而三条约定完全没有覆盖它 —— 留着就是绕过约定的现成后门。真要用,先定它的约定,再教这个脚本认它。约定 3:纪律,不是门禁
"豁免必须单独成 PR、打
osv-exemption标签"写进了台账文件头(加豁免的人必然读到)与 workflow 注释,并在有豁免存在时由脚本每次打印提醒 —— 但没有做成门禁。原因是便宜的机械形状会误伤好情形:"osv-scanner.toml必须单独改动"会把"终于修好依赖、顺手删掉豁免"的 PR 也判红,而那正是我们最想鼓励的 PR。因此规则表述为:删除豁免可以夹带在修复 PR 里,新增或续期不行。osv-exemption标签当前不存在(已确认 404),需要维护者建一个 —— 或者告诉我改用现成标签。self-test(双向)
零豁免状态下门禁行为不变(实测)
同一份
pnpm-lock.yaml,带 / 不带本文件,scanner 结果逐条一致:Loaded filter from:一行同时证明了根目录的osv-scanner.toml确实被--lockfile=pnpm-lock.yaml这条扫描路径发现(scanner 只读被扫文件所在目录的配置,而 lockfile 就在根目录)。端到端演示:脚本抓住了 scanner 放行的东西
在真实 lockfile 上临时插入一条缺
ignoreUntil的豁免:改为已过期的
ignoreUntil = 2026-07-01:scanner 重新报出该公告(原生到期),checker 同时以EXPIRED 34 day(s) ago判红,并要求重新裁决而不是顺手延期。顺带说明(不在本 PR 范围)
本地扫描显示
main当前有 8 条都有修复版本的公告(undici / hono / fast-uri),即 OSV 门禁此刻是红的;已由 #5032 记录,本 PR 不碰 —— 那些是"有修复就吃修复"的情形,恰恰不该走豁免。验证命令
Generated by Claude Code