检查自己写着「这不会让任务失败」:一条 Critical 风险就这么过了 178 天

口径先钉住 :本篇每一条锚点都来自公开文件,匿名可直接打开 ,而且我逐字读过两个版本: - .github/workflows/verify-build-reproducibility.yml ------ 首版(2026-04-20)与今天(v1.x)我都拉下来逐行读过 - THREATMODEL.md ------ 第 401 / 407 / 409 / 457 行逐字 - 提交历史走 commits/...atom,第一条就是文件创建那一次 本文没有引用学术文献 ,见文末引用节。 ⚠️ 先说本文最大的短板:我能证明「这个机制存在」,但证明不了「它已经造成了伤害」。 见第四节。

事情是这样的

axios 有一个安全威胁模型文件,叫 THREATMODEL.md。 不是谁写的小作文,是这个项目自己维护的风险清单。

清单里有一条,编号 T-S5,标题逐字:

shell 复制代码
#### T-S5: Build-output tampering (dist/ != lib/)

同一条目的「影响」栏里写着:

markdown 复制代码
****Impact** / **Critical****

Critical。 最高那一档。 翻译成人话:产物目录和源码目录对不上。 也就是你分发出去的代码,和你以为你分发的不是同一个东西。

按一个项目自己的威胁模型,这种风险该配一道硬门禁:构建两次,两次结果不一致就挡住合并。

那道门禁长什么样

我去 axios 仓库里找那条检查,找到了:

.github/workflows/verify-build-reproducibility.yml,逐字:

yaml 复制代码
  verify-reproducible-build:
    name: Two-pass build and diff
    runs-on: ubuntu-latest
    # Non-blocking until divergence is eliminated. Surfaces regressions in
    # the build's determinism without gating merges. Remove this line to
    # promote to a hard gate once the build is byte-identical across runs.
    continue-on-error: true

continue-on-error: true,一行的意思就是:这条检查失败了,任务照样算成功。

上面那三行注释是这个项目自己写的,翻译过来:

在不一致被消除之前保持非阻塞。它把构建确定性上的退化暴露出来, 但不阻断合并 。等构建在多次运行之间逐字节一致了,把这一行删掉, 就把它提升为硬门禁。

写得很清楚。它知道自己该变成硬门禁,也写清楚了条件。

但真正让我停下来的,是文件里的另一行

同一个文件,第 65 行:

bash 复制代码
echo "This does not fail the job (continue-on-error: true) but is visible in the run summary."

这句是它运行时打印到日志里的。逐字:

这不会让任务失败 (continue-on-error: true),但它在运行摘要里是可见的。

我读到这儿停了一下。

我见过两种情况:

  • 判据悄悄失效 ------ 没人知道它在不在跑。
  • 判据大声地说自己没用 ------ 像这条,它每次跑都明确告诉你「我不会拦住你」。

后者比前者好查得多。后者也更容易被忽略------ 构建是绿的,所有提示都写着「正常完成」,混在一堆绿色对勾里。 谁会盯着一行 echo 看?

解除条件写在两个文件里

这个条件不是写在某个人的脑子里,也不是工单里。 它同时写在两处,我逐字贴出来。

第一处,是上面那个 workflow 的注释: 「Once divergence is eliminated, remove this line」。

第二处,是 THREATMODEL.md 第 409 行,「Gaps」栏:

It is currently non-blocking (continue-on-error: true)... Once divergence is eliminated, remove continue-on-error to promote this to a hard gate.

第三处,是同一份文件第 457 行的行动项表:

css 复制代码
**T-S5 Build tampering / Low / Critical / Adequate**

  Eliminate build non-determinism, then promote reproducibility check to blocking |

三处,三种说法,指向同一件事。

178 天

178 天。这条检查从被创建的第一天起,就不具有否决权。

那么它是怎么来的?查得出来------这条 workflow 的提交历史一共 10 次, 第一条是 2026-04-20T17:52:36Z,commit 302e2739c6, 标题是 docs: update docs, add a couple actions etc (#10776)。

我把那个 commit 里的文件版本拉下来看了。第 21--24 行,逐字:

php 复制代码
    # Non-blocking until divergence is eliminated. Surfaces regressions in
    # the build's determinism without gating merges. Remove this line to
    # promote to a hard gate once the build is byte-identical across runs.
    continue-on-error: true

一模一样。

continue-on-error: true 不是后来被谁加上去的。 从 2026-04-20 到今天 2026-10-15,178 天里它一次也没能拦住过任何东西。

那么,解除条件满足了吗?没人记录------这一点我在第四节单独说。

⚠️ 第四件必须说的事:我证不了后果

上面全是真的。但有一件事我做不到。

我找不到任何一次公开记录,能证明 axios 的构建产物真的不一致。 所以我也不能说,它挡住过什么、或者放过什么。

我不能证明这 178 天里发生过什么。我只能证明:

我能证明 / 我不能证明

  • 这条风险被项目自己评为 Critical ------ 它已经造成过实际损害
  • 唯一能发现它的检查从第一天起没有否决权 ------ 构建真的出过不可复现
  • 解除条件写在三个地方 ------ 解除条件一直没满足

第 3 行尤其要说清楚:解除条件可能一直是满足的。 也可能是构建早就逐字节一致了,只是没人把那一行删掉。 这两种情况在这条证据面前长得一模一样。

所以我不会写「axios 被攻破过」,也不会写「它放过了一次篡改」。 一个判据写了它想做什么、且每天都在老实汇报, 这本身不构成它失职的证据。

那这篇还值得写吗

我认为值得,但理由和上面那些数字无关。

值得写的是这件事的形状:

一个团队把一条风险评为 Critical,把解除条件写在三个地方, 然后把「解除」这个动作本身,交给了一个不会有人主动去做的流程。

门禁类的东西有个共同点:它不制造工作,它消除工作。 一旦一道门禁长期挂着「不阻塞」,它就会一直挂着。 没有任何东西会因此变红。所以没有人需要做决定。

这和「有人在某个群里拍板说这条先不管」不一样。 那至少还有个人,可以被追问「你怎么决定的」。

而 continue-on-error: true 是另一种东西: 它把一个待决事项,写成了一个已完成事项。

如果要我给一条可带走的

不是「给 CI 加硬门禁」------那是空话,而且很多门禁就不该硬。

我能给的只有一条具体的。

当一条判据写着「暂时不阻塞」,去找它自己写下的解除条件。 然后检查那个条件现在成不成立。

如果条件成立了而它还挂着,那说明没有人回头看 。 这时候把它打开是零风险的改动------它一直在跑,只是改一个开关。

如果条件不成立------那至少「暂时」是诚实的。 你只是需要知道它现在还不成立,而不是以为它在拦着。

关键区别在于: continue-on-error: true 和「没人在看」在你这里长得一模一样。 要么它在拦,要么它不拦,中间没有第三态。

附:本文引用

锚点 / 出处(匿名可开) / 我做了什么

  • continue-on-error: true 与三行注释 ------ raw.githubusercontent.com/axios/axios/v1.x/.github/workflows/verify-build-reproducibility.yml ------ 拉下来逐行读,:21-24
  • 文件自己打印的那句话 ------ 同上 ------ :65,逐字
  • 首版文件(创建那一次) ------ raw.githubusercontent.com/axios/axios/302e2739c6/.github/workflows/verify-build-reproducibility.yml ------ 拉下来逐行读,:21-24 与今天逐字节一致
  • 文件创建那一次提交 ------ github.com/axios/axios/commits/v1.x/.github/workflows/verify-build-reproducibility.yml.atom ------ 解析 10 条提交,最早 2026-04-20T17:52:36Z / 302e2739c6 / #10776
  • 默认分支是 v1.x ------ api.github.com/repos/axios/axios ------ 读 default_branch
  • T-S5 与其 Critical ------ raw.githubusercontent.com/axios/axios/v1.x/THREATMODEL.md ------ :401 标题;:407 的 Impact 一栏写着 Critical
  • 解除条件(第三处) ------ 同上 ------ :409 Gaps 栏、:457 行动项表
  • 178 天 ------ 本机 datetime 实算 ------ 2026-04-20 → 2026-10-15

本文没有引用学术文献

这篇没做文献综述,也没引用任何论文或书籍。 第二节查的是项目自己的文件,不是文献。 写清楚是为了避免读者以为我做过文献工作。

取到 / 没取到的

来源 / 状态

  • workflow 首版与当前版逐行 ------ ✅ 取到,亲自拉下来对比过
  • 提交历史(atom feed) ------ ✅ 取到,10 条,最早即文件创建
  • THREATMODEL.md 四处锚点 ------ ✅ 取到,逐行读过
  • 默认分支 ------ ✅ 取到,v1.x
  • 「解除条件一直没被满足」 ------ ❌ 没有任何公开记录支持 。文件里没有,工程 issue 里我没找到。本文没有这样断言
  • 构建是否真的不可复现 ------ ❌ 没查到公开证据。我不写「它放过了一次篡改」
  • 中文侧是否已有人写过这个题 ------ ❌ 未能验证 (百度验证码 / cn.bing 301 / DuckDuckGo 返空 / 掘金与 CSDN 搜索页 JS 渲染 / 知乎 403)。因此我不声称它是中文首例

取不到的东西我不用记忆去补。

尤其是上面两条打 ❌ 的。它们恰好是这个题最像样的两个论点。 正因为拿不到一手证据,这篇才退到只讲机制。

读者是能分辨「可能出过事」和「出过事」的。 而那个差别,是整个系列的立足点。

相关推荐
55873生态系统手记1 小时前
三足鼎立,文明永续:55873 全域文明生态系统的架构师分工、十三套子大典与 Web4 技术底座拆解
架构
姜鱼问生1 小时前
备份和服务器在同一台机器上,等于没备份
算法·架构
搜狐技术产品小编20231 小时前
MVI + Compose 架构实战:从状态混乱到单向数据流
架构
姜鱼问生2 小时前
别再 chmod 777 了,用 ACL 给它开一扇窗
后端·算法·架构
仿生joe会梦见漫天的大雪吗2 小时前
CTF Misc 工具选型指南:按题型分类的工具、原理与限制
后端·安全
QYR-分析2 小时前
工业安全无线遥控器:5.4% 稳步增长,起重与移动机械的安全控制终端
安全
Dawson Zhu3 小时前
《Agentic Design Patterns》第 21 章导读:探索与发现
人工智能·语言模型·架构·aigc·agi
李福春3 小时前
技术思考问题6:技术演讲该晒成功架构,还是交代失败与取舍?
java·开发语言·架构·computer use·深圳同盟·腾讯云架构师技术同盟·反演思维
JAVA_AI人工智能项目实战3 小时前
大模型结构演进.学习笔记
大数据·人工智能·语言模型·架构