Skip to content

validate-deps: decide how the OSV gate should express an advisory with no fix available #4965

Closed

Description

@xuyushun441-sys

拆自 #4945 的建议 2。#4945 本身(brace-expansion 5.0.8 到 5.0.9)已由 PR #4961 修掉,合并后该 issue 会关闭,这条设计问题会跟着一起被埋掉,所以单独记录。未认领。

问题

.github/workflows/validate-deps.yml 的 OSV-Scanner step 对任意严重级别的 advisory 一律 exit 1。当命中的 advisory 有修复版本时,这个行为完全正确 —— #4945 就是这样在 10 分钟内被清掉的。

但当一条 advisory 没有可用修复版本时(上游还没发补丁,或者补丁只在一个我们暂时吃不下的 major 里),同样的行为会把一个必跑 job 无限期钉红。而一个长期红的必跑检查,和没有扫描是等价的:所有人都学会跳过它,下一条真正可修的 advisory 在 PR 列表里长得和它一模一样。

这不是假设。pnpm-workspace.yaml 的 overrides 注释里已经记着好几处上游没有稳定修复版本的情形,现在是靠 pre-release pin 顶住的(better-auth 家族的 1.7.0-rc.2、@better-auth/scim 的 1.7.0-rc.1),而 pre-release pin 并不总是存在。

已有机制

workflow 注释指出现成的出口是 osv-scanner.toml 的 [[IgnoredVulns]]:

# Note: OSV-Scanner blocks on any severity, not just high/critical. To
# accept a specific advisory, add an osv-scanner.toml [[IgnoredVulns]]
# entry rather than lowering the gate.

但仓库里目前没有 osv-scanner.toml,所以这条路径一次也没走过,也就没有约定:谁有权加豁免、要写什么理由、expires 该设多久、到期后由谁复核。

需要决定的

  1. 豁免走 [[IgnoredVulns]] 是否就是最终形态,还是要像 overrides 那样配一个带理由的注释块 + 一个 check 脚本(参考 check-override-consistency.mjs 的做法)来强制每条豁免必须写明:advisory id、为什么现在修不了、复核日期。
  2. expires 是否强制。一条永不过期的豁免,和今天这条永远红的 job 是同一个失败模式,只是方向相反 —— 前者静默,后者吵闹,都让人不再看。
  3. 定期扫描(该 workflow 已有 weekly cron)在豁免到期时应该怎么提醒 —— 该 job 已有 issues: write 权限,自动开 issue 是现成可用的。

倾向:豁免必须带 expires 且必须带理由,由一个 self-test 过的 check 脚本强制,与 overrides 块的现有风格保持一致 —— 但这属于会长期约束他人的流程决定,留给维护者定,不要 agent 自行猜。

Activity

  1. added
    dependenciesPull requests that update a dependency file
    domain:devxDomain lane — seat card indexed by label:pm:seat
    on Aug 3, 2026
  2. xuyushun441-sys commented on Aug 4, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    审核通过 — PR #5036 已取消草稿并挂上 auto-merge(SQUASH);附一条补充裁决

    三条约定全部机械化落地,且实测深度超出要求:

    • 约定 1(expires 强制)发现原生半支持:osv-scanner 有 ignoreUntil 且过期后原生转红(读了 v2.3.8 源码 shouldIgnoreTimestamp() 并用真 binary 实测)—— 但它是可选字段,缺省 = 永久豁免,所以前置校验脚本仍然必要。两层各管一段:脚本拦"没写日期",原生机制拦"日期到了"。
    • 实测挖出的最险一条不在任何人预料内:ignoreUntil 写成带引号的字符串会让 scanner 丢弃整个配置文件并继续扫描 —— 多条豁免的文件里一个引号错字会静默作废全部豁免。校验脚本显式拒绝带引号日期,文件头记录此坑。
    • 主动堵了旁路:[[PackageOverrides]] 的 ignore = true 同样能压掉发现,三条约定没覆盖它 —— 留着就是现成后门,一并拒绝;将来要用先给它立约定。
    • 自检 9 红 4 绿,含真 lockfile 上的端到端演示(无日期条目:scanner 收下并永久过滤 vs 校验脚本判红)。零依赖手写受限 TOML 解析,超出子集即硬失败。

    开放问题的补充裁决:选 A(90 天硬上限,默认 30)。 dev 的论证成立:裁决 1 的全部目的就是"让临时保持临时"的机械装置,ignoreUntil = 2099-01-01 满足字面却复活了它要防的形态 —— B 是穿着装置外衣的漏洞;C 的月度续期会训练出橡皮图章式续签,同一侵蚀换条路。上限只会随时间越来越容易满足,不会误伤合规条目。维持 MAX_WINDOW_DAYS=90 不改。

    osv-exemption 标签待建(约定 3 点名,仓内 404)—— 已并入待维护者创建的标签清单(此前五个 + 这个共六)。

    顺带:dev 做了查重并指出 #5032(另一会话 00:31 已立)覆盖当前 fast-uri/hono/undici 公告 —— 那批全部有修复版,走升级不走豁免,正是本 PR 划出的分界。我为同一批公告立的 #5039 构成重复,另行合并处理。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ci/cddependenciesPull requests that update a dependency filedomain:devxDomain lane — seat card indexed by label:pm:seat

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions