分类 技术志 下的文章

Rust 的“跨越鸿沟”时刻:Ubuntu 全面拥抱 Rust 意味着什么?

本文永久链接 – https://tonybai.com/2026/02/25/rust-crossing-the-chasm-ubuntu-embrace

大家好,我是Tony Bai。

在技术世界里,一门编程语言的成功往往分为两个阶段:第一阶段是赢得“极客”和“先驱者”的狂热追捧;第二阶段则是说服那些保守、务实的“早期大众”将其投入到枯燥却庞大的企业级生产中。这两个阶段之间,横亘着一条深不见底的“鸿沟”。

2026 年初,Rust 核心团队成员、语言设计的灵魂人物 Niko Matsakis 在参加完 Rust Nation 大会后,发表了一篇引人深思的文章——《What it means that Ubuntu is using Rust》。在这篇随笔中,Niko 借由 Canonical(Ubuntu 的母公司)全面拥抱 Rust 这一标志性事件,极其坦诚地剖析了 Rust 当前在行业接纳生命周期中所处的位置、面临的阵痛,以及为了走向真正的“工业标准”,Rust 社区必须在技术和心理上做出的巨大改变。

本文将深度解读 Niko 的这篇文章,带你透视 Rust 在“后狂热时代”的商业化演进路线、标准库之争、开源商业模式,以及为何“同理心”成了这门硬核语言最大的护城河。

无处不在的“鸿沟”——Rust 到底走到哪了?

如果你熟悉硅谷营销大师杰弗里·摩尔(Geoffrey Moore)的经典理论《跨越鸿沟》(Crossing the Chasm),就会知道任何一项高科技产品在市场推广时,都会经历创新者(Innovators)、早期采用者(Early Adopters)、早期大众(Early Majority)、后期大众(Late Majority)和落后者(Laggards)五个阶段。而在“早期采用者”与“早期大众”之间,存在着一个巨大的断层,这就是“鸿沟”。

Rust 跨过这条鸿沟了吗?

Niko 给出的答案是:这取决于你问的是谁。

  • 在某些互联网巨头(大厂)中:答案是“已经跨越了一大半”。比如在亚马逊云(AWS)这样对性能和资源有着极致苛求的地方,Rust 已经被牢牢确立为构建大规模数据平面(Data Planes)和资源感知代理(Agents)的“正确选择”。它甚至正在向设备端和机器人领域的底层代码渗透。
  • 在普通企业应用中:依然存在一种根深蒂固的刻板印象——“Rust 是给 S3(亚马逊云存储)那些穿西装打领带的高级工程师用的,对于我们普通的 CRUD(增删改查)业务来说,完全是杀鸡用牛刀。”
  • 在安全关键软件(Safety Critical Software)领域:比如汽车的转向柱控制系统或航空航天系统,Rust 依然在艰难地寻找立足点。大多数传统工业巨头仍处于“观望”状态,他们希望让早期采用者先去铺路、踩坑。

这揭示了一个残酷的现实:技术上的优越性并不等同于市场上的普遍接受度

当技术走向“早期大众”时,受众的心态发生了根本性变化。

早期采用者买的是“变革”,他们愿意容忍不成熟的生态,只为获得降维打击的竞争优势;而“早期大众”买的是“生产力提升”,他们极度厌恶风险,追求的是业务连续性——他们想要的是进化,而不是革命。

寻找“标杆客户”——Ubuntu 搭建的跨越之桥

如何说服那些极度厌恶风险的“早期大众”尝试新事物?唯一的答案是:让他们看到与他们相似的成功案例。

这就是为什么 Canonical(Ubuntu 背后的公司)的入局对 Rust 生态具有决定性的历史意义。在 Rust Nation 大会上,Canonical 的工程副总裁 Jon Seager 发表了题为《在 Ubuntu 中大规模采用 Rust》的闭幕演讲。这场演讲完美诠释了什么是“既有远见,又极其务实”。

Canonical 明确表示,他们已将公司内部开发的语言收敛为一个极小的集合:Python、C/C++ 和 Go。

而现在,Rust 被正式引入,并被确立为编写新底层基础工具的首选语言,逐步取代 C、C++ 以及部分 Python 的使用场景。

更令人振奋的是,Canonical 不仅仅是自己“用”,他们还在“反哺”生态,充当桥梁。

Jon Seager 谈到了 Ubuntu 作为操作系统发行版的责任——通过支持内存安全的基础设施库来“向前支付(Pay it forward)”。Canonical 正在提供财务和声誉上的双重支持:
1. 赞助 Trifecta Tech 基金会开发 sudo-rs 和 ntpd-rs(用 Rust 重写关键的系统组件)。
2. 赞助 uutils 组织开发 Rust 版的 coreutils(Linux 核心命令集)。

为什么说 Ubuntu 是完美的“标杆客户”?

在 Linux 用户态领域,Ubuntu 的体量和权威性毋庸置疑。当 Ubuntu 愿意承担尝试新事物的风险,并证明“用 Rust 重写 sudo 是可行的且更安全的”时,这种示范效应是巨大的。

那些“早期大众”企业看到这一幕时会想:“如果连 Ubuntu 这样对稳定性要求极其变态的操作系统底层都在用 Rust,那我们的业务系统用 Rust 应该也是安全的。”

这正是《跨越鸿沟》中破局的核心策略:利用标杆客户的背书,提供能无缝融入现有工作流的“即插即用”方案,从而最小化系统的不连续性。

成长的阵痛——为了壮大,Rust 必须改变“人设”

当目标受众从追求极致的“极客”变成追求稳定的“务实派”时,Rust 面临着一种极其尴尬的转型痛点。

Niko 在文中引用了《跨越鸿沟》里的一段话:

“在任何两个采用群体之间的过渡通常都是极度令人尴尬的,因为你必须在你对旧策略感到最舒服的时候采用新策略……当务实派想听到‘行业标准(Industry Standard)’时,科技公司可能还在向他们推销‘最先进的技术(State-of-the-art)’。”

这精准地命中了 Rust 当下的软肋。

在过去的十年里,Rust 社区的营销口号是“零成本抽象”、“无畏并发”、“最先进的内存安全所有权模型”。这套说辞成功吸引了早期的系统工程师。

但如今,当 Rust 走向大众时,普通开发者更关心的是:“有没有现成的库?”、“编译能不能快点?”和“能不能开箱即用?”

核心冲突爆发点:标准库的规模之争。

在闭门晚宴上,Canonical 的 Jon Seager 提出了一个极具挑衅性的观点:Rust 需要重新审视其维持“极小标准库(Small Standard Library)”的政策。

长期以来,Rust 奉行“标准库只包含最核心的类型和原语,其余全部交给社区(Crates.io)”的哲学。比如,Rust 的标准库里甚至没有随机数生成、正则表达式或 HTTP 客户端。这种设计在早期非常受极客欢迎,因为它保证了核心库的轻量级,并允许社区自由竞争出最好的第三方库(如 serde、tokio)。

但对于“早期大众”来说,这简直是个噩梦。他们不明白为什么解析一个 JSON 或发起一个 HTTP 请求都需要在数以万计的第三方包中去筛选、评估安全性、担心供应链投毒。他们想要的是像 Go 语言或 Python 那样“内置电池(Batteries Included)”的开箱即用体验。

实际上,Rust 社区在 2016 年曾推出过一个名为“Rust 平台(Rust Platform)”的提案,试图官方“钦定”一批高质量的第三方包作为“扩展标准库”。但当时遭到了早期采用者的强烈抵制,理由是“直接改 Cargo.toml 很容易,没必要官方下场干预”。

Niko 反思道:当年早期采用者讨厌的东西,恰恰可能是如今“早期大众”最渴望的东西。

Rust 必须面对现实:过去引导其成功的信条,正在阻碍其向更广阔的市场迈进。

Niko 透露,他正在构思一个名为“电池包(Battery packs)”的新项目,试图在不搞庞大标准库的前提下,为企业级用户提供一种官方背书的、开箱即用的库集合方案。这标志着 Rust 正在从“追求它能成为什么样(What it could be)”向“承认它实际是什么样(What it actually is)”的务实转变。

商业与开源的闭环——如何将“采用率”转化为“真金白银”?

任何一门编程语言生态的长远发展,都离不开雄厚的资金支持。随着 Rust 采用率的爆炸式增长,对 Rust 开源项目和生态系统的维护压力也与日俱增。钱从哪来?

Niko 分享了几个关于开源投资的深刻洞见,这不仅适用于 Rust,对所有开源项目(包括 Go、Node.js 生态)都有极大的启发。

洞见一:投资不一定只是“砸钱”,更是“下场共建”。

对于像 Canonical 这样的纯粹开源组织,最宝贵的投资是“建立深度的组织间关系”。

在“Rust for Linux”项目中,早期都是 Rust 核心维护者在帮 Linux 内核开发者修 Bug。但随着时间推移,现在越来越多的 Linux 内核开发者开始自己动手修复 Rust 编译器或工具链的问题,而 Rust 维护者则退居幕后扮演导师的角色。这种“授人以渔”的贡献,比单纯的捐款更有价值。

洞见二:钱往往在公司“采用 Rust 之前”到来,而不是之后。

我们通常认为,企业是在大量使用某个开源软件后,出于反哺或维护自身利益的目的才会掏钱赞助。

但 Niko 观察到了一个完全不同的趋势:更容易获取的资金,来自于那些“正在考虑但尚未采用” Rust 的公司。

在这些公司内部,通常有一批“早期采用者”(内推者),他们试图说服保守的公司管理层采用 Rust。为了促成此事,他们往往需要拿着一份“准入条件清单”——比如,Rust 必须支持某种特定的芯片架构,或者必须具备某个安全认证组件。

更关键的是,这些内推者手里往往握有预算。为了让这门技术顺利落地公司,他们愿意花钱去填补 Rust 生态中的这些空白。

Rust 基金会的 Alexandru Radovici 证实了这一点:许多对安全性要求极高的公司,手里攥着钱想帮 Rust 补齐短板,却“不知道该怎么花这笔钱”。Canonical 赞助 sudo-rs 本质上也是一样的——他们是在花钱扫除阻碍 Ubuntu 更大规模采用 Rust 的障碍。

开源社区需要建立一种机制,精准对接这些带着预算的“潜在采用者”,将他们的痛点转化为开源项目的开发资金。

社区的终极考验——同理心是最大的护城河

在文章的最后,Niko 抛出了一个直击灵魂的观点,这不仅是给 Rust 社区的警钟,也是所有程序员的必修课:

“如果我们在其中表现得太像‘中学生(Middle School)’,那开源跨越鸿沟的愿景就会彻底破灭。”

什么是“中学生”行为?

当你深度参与一个开源社区时,你会觉得这里充满阳光,欢迎所有人。但对于外部的“早期大众”来说,开源社区往往看起来像一个充满小圈子、潜规则和“口口相传的规矩(Oral traditions)”的排外组织。

一个企业级的保守开发者,带着一个务实的业务问题来到社区提问。他可能只是用错了一个术语,或者没有遵循某种隐形的“社区政治正确”,结果就遭到了一群激进贡献者的群嘲、冷嘲热讽,甚至因为提出不同的设计理念而被强硬关闭 Issue。

这位企业开发者根本分不清哪些是喷子,哪些代表官方立场。他只会觉得:“这个语言的社区太有毒了,我们公司还是用 Java 吧。”

只需要一次粗鲁的回复,就能彻底赶走一个潜在的企业级标杆客户。

Niko 强调,帮助 Rust 最终取得成功的,绝不是更快的编译速度或更完美的类型系统,而是“开源中的同理心”。

“早期大众”并不想参与编程语言的“宗教战争”,他们不关心“纯粹性”,他们只是想按时下班,安全地把产品发布出去。Rust 社区必须学会倾听这群人的声音,理解他们的价值观,用温和、包容和同理心去服务他们,而不是用技术傲慢去居高临下地教训他们。

小结:语言的进化,更是心智的成熟

从 2015 年发布 1.0 版本至今,Rust 用了十余年的时间,证明了自己在技术和理论上的卓越。如今,借由 Ubuntu 这样的重磅标杆客户的背书,它正式站在了跨越主流企业级市场鸿沟的跳板上。

Niko Matsakis 的这篇文章,不仅是对 Rust 现状的一份清醒诊断,更是对整个技术生态演进规律的深刻洞察,也非常值得其他主流编程语言的掌舵者和社区学习借鉴。

无论是标准库的扩展、商业投资机制的完善,还是社区同理心的建设,都表明 Rust 正在经历一场脱胎换骨的“成年礼”。它正在从一个由极客驱动的“炫酷玩具”,蜕变为一个能够承载人类核心数字基础设施的“工业巨兽”。

也许属于 Rust 的激荡时代,才刚刚开始。

资料链接:https://smallcultfollowing.com/babysteps/blog/2026/02/23/ubuntu-rustnation/


你认为 Rust 该“扩充”标准库吗?

Rust 坚持“极小标准库”让极客疯狂,却让企业用户头大。你是支持 Go 这种“内置电池”的开箱即用,还是支持 Rust 这种“社区竞争”的极简主义?你在项目中是否也曾因为 Rust 缺乏某个基础库(如随机数、正则)而感到沮丧?

欢迎在评论区分享你的看法!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

拒绝无效告警!用 Govulncheck 构建高信噪比的 Go 安全扫描工作流

本文永久链接 – https://tonybai.com/2026/02/25/govulncheck-high-signal-to-noise-ratio-security-workflow

大家好,我是Tony Bai。

在当今的软件开发流程中,持续集成/持续部署(CI/CD)和自动化的安全左移(Shift Left)已经成为行业共识。在这个大背景下,诸如 GitHub Dependabot 这样的自动化依赖更新工具应运而生,并迅速占据了几乎每一个开源项目和商业级代码库的 Repository 设置。它们不知疲倦地扫描 go.mod,一旦发现有依赖项爆出 CVE 漏洞,就会自动生成一个拉取请求(Pull Request, PR),仿佛是在告诉你:“别担心,我已经帮你修好了。”

然而,事实真的如此美好吗?

近日,密码学领域的权威专家、前 Google Go 安全团队负责人 Filippo Valsorda 在其个人博客上发表了一篇极具冲击力的文章,标题直截了当:“TURN DEPENDABOT OFF”(关掉 Dependabot)。他毫不客气地指出,这款被无数开发者信赖的工具,实际上是一个“噪音制造机”(Noise Machine)。它不仅浪费了开发者的宝贵精力,更在无形中损害了整个 Go 生态系统的安全根基。

作为 Go 开发者,我们该如何审视这种看似“政治正确”的安全自动化工具?如果不使用 Dependabot,我们又该如何保卫代码库的安全?本文将深度剖析 Filippo 的核心观点,揭示传统版本比对扫描的致命缺陷,并手把手教你如何利用官方推荐的 govulncheck 构建真正高效、高信噪比的现代化 Go 安全扫描工作流。

安全自动化的幻象与“告警疲劳”

为了理解 Filippo 为什么如此强烈地反对 Dependabot 这种类型的扫描工具,我们需要先剖析软件工程心理学中的一个经典问题:告警疲劳(Alert Fatigue)

什么是告警疲劳?

告警疲劳是指操作人员或开发人员在长时间暴露于频繁且大量低价值(即假阳性、False Positives)的系统警告下,逐渐变得对这些警告麻木、脱敏的现象。

在医疗领域,如果重症监护室的心电监护仪总是因为轻微干扰而发出刺耳的警报声,护士最终可能会忽略真正的病危信号;在网络安全领域,如果防火墙每天产生一万条拦截记录,安全分析师就不可能从中挑出那一条真正的 APT 高级持续性威胁。


图:Dependabot alerts

在软件开发中,Dependabot 完美地扮演了那个“总是狼来了”的角色。它带来的不是安全感,而是一种虚假的工作充实感。正如 Filippo 所言:“它让你感觉自己好像在做有用的工作,但实际上你是在阻碍真正有用的工作。”

传统版本扫描的致命缺陷:一刀切的模块级匹配

Dependabot 和大多数传统的软件成分分析(SCA)工具一样,其工作原理极其简单粗暴,可以概括为基于版本的字符串比对

以 Go 语言为例,它们的逻辑是这样的:
1. 解析你的 go.mod 和 go.sum 文件,列出你所使用的所有依赖模块(Module)及其版本(如 github.com/foo/bar v1.0.0)。
2. 查询公共漏洞数据库(如 NVD)。
3. 如果数据库显示 github.com/foo/bar 在 < v1.2.0 时存在某个漏洞,且你的版本在这个范围内,立刻生成一个高危告警,并创建一个将版本升级到 v1.2.0 的 PR。

在某些动态类型语言(如 Ruby 或早期 JavaScript)生态中,这种方法或许是唯一可行的。但在 Go 语言这样强调静态类型、拥有明确抽象边界和包级结构的生态中,这种“模块级”的一刀切匹配就显得极其愚蠢和低效。

真实案例分析:edwards25519 漏洞风波

为了让这个问题更加具象化,Filippo 在文章中分享了一个他亲身经历的“案发现场”。

不久前,Filippo 为他维护的密码学基础库 filippo.io/edwards25519 发布了一个安全修复版本(v1.1.1)。这个库在 Go 生态中举足轻重,被数十万个开源项目间接依赖。然而,这个漏洞的触发条件极其苛刻:

漏洞仅存在于 (*Point).MultiScalarMult 这个非常高级且罕用的 API 方法中,且只有当该方法的接收者(Receiver)不是初始的 identity point 时才会产生未定义的行为。

现实情况是:在整个 Go 生态系统中,几乎没有任何项目实际调用了这个存在缺陷的特定方法。 大多数依赖该库的项目(比如著名的 github.com/go-sql-driver/mysql 库,拥有 22.8 万以上的依赖者)仅仅是导入了该库的其他基础功能,与有漏洞的代码路径八竿子打不着。

Dependabot 的反应是什么?

灾难性的噪音。Dependabot 不分青红皂白,仅仅因为版本号低于 v1.1.1,就向 GitHub 上的数千个甚至根本不受影响的 Repository 发送了疯狂的更新 PR。更糟糕的是,这些 PR 附带了由算法自动生成的、耸人听闻的、根本不合逻辑的 CVSS v4 漏洞评分,以及所谓的“73% 兼容性风险警告”。

结果就是,无数个深夜,开源项目的维护者们收到了刺耳的安全警报,被迫中断手中的工作,去 review 一个修改了一行他们压根用不到的代码的依赖升级 PR。如果他们不合并,项目上就会一直挂着一个红色的“安全风险”标签;如果他们机械地合并了,这就成了“告警疲劳”的典型发作。

Filippo 一针见血地指出这种行为的荒谬性:

“由于扫描器未能过滤掉无关的漏洞,这种额外的劳作被硬生生地扔到了开源维护者的脚下,这是不可持续的。维护者的责任是确保项目不受安全漏洞影响;而扫描工具的责任是确保它们不会用假阳性告警去打扰用户。

当升级依赖(Dependency bump)成为一种应付扫描工具的机械动作,而不是基于对漏洞影响的真实评估(如是否需要轮换生产环境的密钥、是否需要通知受影响的用户),我们距离真正的安全就已经越来越远了。

拥抱静态分析,Govulncheck 的降维打击

既然基于版本的 Dependabot 如此不堪,我们应该如何科学地防范软件供应链安全风险?

答案是:抛弃盲目的版本匹配,使用严肃的、基于静态代码分析的漏洞扫描器。 计算机完全有能力为你完成过滤无用噪音的工作。在 Go 语言生态中,这个“杀手级”的工具就是官方出品的 govulncheck

丰富的 Go 官方漏洞数据库

要实现精准的扫描,首先需要高质量的数据源。这正是 Filippo 在 2020 年至 2021 年领导 Go 安全团队时极力推动的战略——投入大量资源建设 Go 官方漏洞数据库(Go Vulnerability Database)

与一般只记录模块版本和一段文字描述的 CVE 库不同,Go 漏洞数据库包含了极其丰富的、机器可读的元数据。它严格遵循标准的 OSV (Open Source Vulnerability) 格式。

让我们看看前面提到的 edwards25519 漏洞(GO-2026-4503)在数据库中的记录:

modules:
  - module: filippo.io/edwards25519
    versions:
      - fixed: 1.1.1
    vulnerable_at: 1.1.0
    packages:
      - package: filippo.io/edwards25519
        symbols:
          - Point.MultiScalarMult   # 关键所在:精确到了有漏洞的具体方法!

请注意最底部的 symbols 字段。Go 安全团队并没有笼统地标记整个模块不安全,而是像外科手术刀一样,精准定位到了那个有缺陷的方法 Point.MultiScalarMult。这就为后续的精准静态分析提供了弹药。

Govulncheck 的核心优势:基于可达性分析

有了精确到“符号(函数/方法)”级别的数据源,govulncheck 就可以对你的代码库施展“降维打击”了。相比于 Dependabot,它具有两大碾压级的优势:

优势一:包级别的过滤

Go 语言的模块通常由多个子包(Packages)组成,这是良好的代码组织习惯。如果一个漏洞发生在模块的 pkgA 中,而你的代码只导入了 pkgB,你显然是安全的。

任何合格的漏洞扫描器至少应该做到这一层过滤。实际上,这只需要执行一次简单的 go list -deps ./… 命令即可分析出包依赖关系。Dependabot 甚至连这基本的一步都没有做到,导致了大量的假阳性。

优势二:基于调用图的符号可达性分析

这是 govulncheck 引以为傲的黑科技。它不仅知道你引入了哪些包,它还会像编译器一样分析你的代码,构建出一棵完整的函数调用图(Call Graph)

当扫描器运行时,它会沿着调用链路一路追溯:从你的 main 函数或测试入口开始,顺着你的业务逻辑,追踪到你调用的第三方库,再追踪到第三方库调用的更底层的库……

如果 govulncheck 发现,存在漏洞的那个特定函数(比如 Point.MultiScalarMult),在这棵庞大的调用树中根本不可达(即没有任何一条代码执行路径会调用到它),那么它就会保持沉默。

让我们看看实际的运行效果。如果你的项目只使用了 go-sql-driver/mysql,并且运行 govulncheck:

$ govulncheck ./...
=== Symbol Results ===
No vulnerabilities found.

Your code is affected by 0 vulnerabilities.
This scan also found 1 vulnerability in packages you import and 2
vulnerabilities in modules you require, but your code doesn't appear to call
these vulnerabilities.
Use '-show verbose' for more details.

看,结果多么清爽!

govulncheck 明确地告诉你:“我看到了你的依赖树里有一个有漏洞的模块,但是不用慌,你的代码逻辑根本没有触碰到那个雷区,你是安全的。”

这种极高的信噪比,是 Dependabot 永远无法企及的。它把安全专家的宝贵时间,留给了真正需要紧急响应的致命漏洞,而不是在日常的升级杂务中消耗殆尽。

重塑现代 Go 项目的 CI/CD 工作流

如果你被 Filippo 的观点说服,决定彻底关闭 Dependabot 的安全警报,那么你必须建立一套更为科学的自动化机制来接管依赖管理和漏洞检测的工作。

Filippo 给出了非常具体的行动指南:用两个定时执行的 GitHub Actions 替换 Dependabot。

行动一:部署独立的 Govulncheck 定时扫描任务

你应该每天定时运行一次 govulncheck。它的作用是充当真正有价值的安全哨兵。

name: Govulncheck Scan
on:
  push:
    branches: [ "main" ]
  pull_request:
  schedule:
    # 每天 UTC 时间 10:22 执行
    - cron: '22 10 * * *'
  workflow_dispatch:

permissions:
  contents: read

jobs:
  govulncheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          persist-credentials: false

      - uses: actions/setup-go@v6
        with:
          go-version-file: go.mod

      - name: Run govulncheck
        run: |
          go run golang.org/x/vuln/cmd/govulncheck@latest ./...

为什么这个 Action 不会自动开 PR?

这是深思熟虑后的设计。如果 govulncheck 报警并导致 CI 失败,这意味着:你的代码明确且切实地调用了一个有已知漏洞的函数。

此时,情况已经相当严重了。你不能仅仅是指望像机器人一样点击“Merge”升级一个版本就万事大吉。你需要人类工程师介入:

  1. 评估该漏洞在你的特定业务上下文中是否可被利用。
  2. 检查是否有数据泄露。
  3. 评估是否需要紧急轮换生产环境的数据库凭证、API 密钥或 JWT 签名密钥。
  4. 手动更新依赖,运行详尽的回归测试,然后再部署上线。

把安全审计权交还给人类大脑,这才是对工程负责的态度。

行动二:测试最新的依赖项,而不是盲目更新

有人会反驳:可是 Dependabot 除了报安全漏洞,还能帮我们保持依赖常新,避免未来积累过多的技术债啊!

Filippo 认为,这种做法同样陷入了误区。

依赖的更新节奏,应当服从于你自身项目的开发周期和发布节奏,而不是被你的上游库作者的发布频率牵着鼻子走。例如,你应该在决定发布下一个主要版本时,集中精力进行一次依赖升级和全面测试,而不是天天被各种次要版本的更新 PR 打扰。

但是,保持对上游变化的敏感度同样重要。如果我们不天天更新,等真正需要安全更新时,可能会因为版本跨度太大而遭遇严重的 API 不兼容(Patch Delta 过大)。

Filippo 提出的巧妙解法是:每天在 CI 中,使用你所有依赖的最前沿版本运行一次你的测试套件。

name: Go Nightly Tests against Latest Dependencies
on:
  schedule:
    # 每天运行
    - cron: '22 10 * * *'

# ... 省略部分环境配置 ...

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        go:
          - { go-version: stable }
          - { go-version-file: go.mod }
        deps:
          - locked  # 针对锁定版本的 go.mod 运行测试
          - latest  # 针对最新版本依赖运行测试
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-go@v6
        with:
          go-version: ${{ matrix.go.go-version }}

      - name: Run tests with sandboxed CI environment
        uses: geomys/sandboxed-step@v1.2.1
        with:
          run: |
            if [ "${{ matrix.deps }}" = "latest" ]; then
              # 关键指令:将所有依赖临时拉取到最新版本,但不修改 go.mod
              go get -u -t ./...
            fi
            go test -v ./...

这种策略的双赢之处:

  1. 零打断的早期预警:你的测试套件每天都在与最前沿的第三方代码搏斗。一旦某个上游库发布了一个引发不兼容的改动,你的每日 CI 就会立刻失败并向你报警,你可以在闲暇时从容应对,而不需要在某个紧急修复的当口被卡住。
  2. 极简的代码库:只要测试通过,你根本不需要去修改 go.mod 提交没必要的版本跳跃。你的仓库历史依然干净。

进阶安全提示:防范 CI 投毒

当你在 CI 中运行 go get -u 时,你实际上是在无审查的情况下执行可能包含了恶意代码的第三方库(尤其是在执行测试时)。为了缓解供应链攻击带来的风险,Filippo 强烈推荐在执行此类测试时引入安全沙箱机制。在上述配置中,geomys/sandboxed-step 是一个基于 gVisor 的沙盒工具,它收回了工作流脚本对 GitHub 环境变量、机密信息以及不必要网络的访问权,确保即使拉取到了恶意的依赖包,它也无法窃取凭证或进行横向移动。这种防御深度,展现了前 Google 安全专家一贯的严谨。

小结:让工具回归辅助的本位

从盲目轻信机器人的批量 PR,到利用编译原理和图论(可达性分析)进行精准手术刀式的漏洞定位,Filippo Valsorda 给 Go 社区上了一堂生动的工程哲学课。

自动化绝不是推卸责任的借口。作为一个成熟的软件开发团队,我们应当停止对“警报数量”的崇拜,转而追求“警报质量”。关闭那些让你产生疲劳的噪音机器,配置好你的 govulncheck,把精力集中在真正需要人类智慧去解决的架构演进和安全设计上。

这不仅是 Go 语言最佳实践的一次更迭,更是我们在面对日益复杂的软件供应链时,应有的冷静与定力。

资料链接:https://words.filippo.io/dependabot/


你被 Dependabot “骚扰”过吗?

自动生成的 PR 虽然方便,但也可能成为开发者的负担。在你的项目中,你是选择一键合并所有的安全更新,还是会仔细评估漏洞的真实影响?你会考虑关掉 Dependabot 的警报,转而投奔 Govulncheck 吗?

欢迎在评论区分享你的安全治理心得!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com
这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats