供应链数仓里,数字本身往往没那么难算。难的是同一张表,安全和业务读出两种意思。

这篇只谈口径。演示大屏见:oss.zl4629.xyz

01先约定三个词

  1. 范围级高危:包的某段版本区间落在 OSV 的影响范围里。
  2. 代表版本:一个包当天用于汇总的那一个版本。
  3. 种子闭包:当前采集种子及其拉到的依赖图覆盖范围,不是全网。

下面四个指标都围绕这三件事。

02M01:直接依赖数

算法:

text
只统计 relation = DIRECT 的边
且 from_version = 代表版本

为什么:

deps.dev 返回的图里经常同时有 DIRECT 和 INDIRECT。如果把 INDIRECT 也算进“直接依赖”,包会显得异常臃肿。
多版本采样时,如果 5 个版本各算一遍再相加,数字还会再虚一次。

误读:

“这个包有 200 个直接依赖” —— 可能只是采样版本叠加,或把传递边算进去了。

03M03:高危影响包 / 条数

算法:

text
affects 中 severity ∈ {CRITICAL, HIGH}
按包统计 distinct osv_id

为什么它只能是范围级:

OSV 记录经常只有 introduced/fixed,没有完整 versions 列表。
在版本比较器(M04)做好之前,我拒绝把“范围命中”说成“当前线上版本已中招”。

误读:

把 M03 直接当成事故级别。正确顺序应是:范围命中 → 业务是否引用 → 实际版本是否落在区间 → 再定处置。

04M08:被依赖次数

算法:

text
count(DIRECT edges where to_package = X)
coverage = seed_closure

接口事实:

deps.dev 的 dependents 路径实测 404。没有全网反查时,硬说“全网依赖数”就是假。

所以指标名和页面注释都写死:只在当前种子闭包内。

误读:

拿 M08 比较两个包的“生态地位”。种子一变,排名就会变。

05M07:僵尸包

算法(当前):

text
生态 = npm
代表版本发布时间 <= dt - 730 天
近 7 日下载 >= 1000

为什么阈值写进配置:

730 和 1000 都是可调的运营参数,不是物理定律。
页面上把它当成“替换候选池”,不是“立刻删除清单”。

下载样本若因 429 不全,僵尸包数量会偏低。这也要在注释里说。

06指标字典比看板更重要

我把定义放进 ads_metric_definition,字段包括:

  • metric_id / version
  • grain
  • formula
  • filters
  • known_limits

口径变更时升 version,而不是静默改 SQL。
这听起来像形式主义,但能避免一周后的自己也解释不清“这个数到底怎么来的”。

07一个会上能用的说法

如果只能讲 30 秒:

高危榜是影响范围,不是利用确认。
直接依赖只算代表版本的 DIRECT。
被依赖次数只在我们采到的闭包里。
先确认业务引用,再谈升级。

把这句话写进页面注释,比再加三张图有用。

08和项目主文的关系

主文看链路和部署:开源供应链数仓:从公开数据到可解释风险大屏
这篇只负责口径,避免主文被细节淹没。