![依赖锁定与安全抽象示意](https://blog.kbmp.club/upload/ci-lock.jpg) CI 里有一类风险很隐蔽:`uses: octo-org/deploy-action@v3` 里的 `v3` 只是别人仓库里的一个 git 引用。它指向哪次提交,是在**运行时**解析的——你评审通过之后,那个提交完全可以移动,而你的仓库里什么都没变。 2026 年 10 月 14 日,GitHub 把工作流依赖锁文件推进公开预览,就是为了补上这个洞。 ## 一、它到底锁了什么 每个仓库生成一个文件:`.github/workflows/actions.lock`,由 CLI 扩展生成: ```bash gh extension install github/gh-actions-lock gh actions-lock generate git add .github/workflows/actions.lock ``` 文件里记录每个依赖的三样东西:工作流里写的 ref、它解析出来的具体 commit,以及 owner_id 和 repo_id。最后两项是裸 SHA 装不下的——**GitHub 在运行时用它们确认这个名字背后的仓库,还是不是你锁定的那一个**。仓库改名或转让(ID 不变)会告警;换成一个同名但完全不同的仓库,直接阻断运行。 关键改进在于:锁文件覆盖**传递依赖**。你 pin 了最外层 action 的 SHA,它内部用 tag 调用的 helper action 照样会变——旧办法对传递依赖束手无策,而传递依赖恰恰是主要攻击面。复合 action 内部的 `uses` 会挂在父条目下。 ## 二、四道控制,缺一不可 生成锁文件、把工作流接入(onboard)、在 CI 里跑校验、以及 Require lockfile 策略,是四件不同的事: 1. **生成**只产生文件,不影响运行; 2. **接入**是按工作流逐个来的,接入后该工作流用到的每个依赖都必须在锁文件里有条目; 3. **校验**(`gh actions-lock --verify` / `check`)不改文件,适合放在 CI 里挡住不同步的合并; 4. **Require lockfile 策略**是唯一能拦住「根本没接入的工作流」的手段,需要管理员权限。 第 4 条把个人最佳实践变成组织治理。而闭环靠 Dependabot:它为已接入的 action 提版本更新时,会在**同一个 PR 里**重新生成对应的锁文件条目。没有这个集成,锁文件会变成一堆没人敢碰的过期 commit。 ## 三、它不做什么 这点 GitHub 自己写得很清楚:**「锁定并不判断依赖本身是否安全,锁定前请先审阅依赖。」** 锁文件保证的是不可变性——你跑的是你读过的代码,不是这段代码可信。锁住一个已被投毒的 action,等于把危害冻结在原地。 已知的边界还有: - **可复用工作流的依赖不覆盖**,由定义它的那个仓库的锁文件负责; - **容器镜像按 tag 拉取的部分不锁定**; - 锁定的 commit 必须存在于源仓库的某个分支上——上游强推或删分支,最先受影响的就是被废弃的 action; - 功能处于公开预览,文件格式和行为可能变(CLI 10 月 12 日 v0.2.0、10 月 22 日 v0.3.0),且**不支持 GitHub Enterprise Server**。 还有一个来自历史数据的提醒:Palo Alto Networks 在 2023 年统计头部 Marketplace action,发现**约 32% 实际上无法被 pin**(例如 JavaScript action 在运行时才去拉外部资源);而在约 2000 个项目的 6000 条工作流里,67% 的项目 pin 了这些不可 pin 的 action。USENIX Security 2022 年对 21 万余仓库的统计则显示,18% 的仓库至少执行一个带有缺失安全更新的 action。 ## 四、该怎么落地 - 已经在手工 pin SHA 的团队迁移最省力:`generate` 会读取现有引用生成锁文件,之后交给 Dependabot。收益是**可读性**——`actions/checkout@v4` 从一个 commit 挪到另一个 commit 的 diff,比一整墙哈希好审得多,外加手工 SHA 永远给不了的强制策略。 - 先挑一个敏感工作流(部署、发布、涉及密钥)做 bounded pilot,别一次性铺开。 - 锁文件覆盖不到的地方——可复用工作流、容器镜像——继续保留 SHA pin。 - 把 `gh actions-lock check` 加进 CI。没人看着的锁文件,是把锁挂在已经打开的门上。 ## 小结 锁文件把依赖解析从运行时搬到了评审时:你审阅的那个产物,就是真正执行的那个产物。它不取代依赖审阅,也不取代 `GITHUB_TOKEN` 权限收紧和触发器限制,但它补上了「谁在 CI 里跑了什么」这条链上一直缺的一块。 --- **说明**:本文为公开资料的整理与评述,信息来源包括 GitHub Changelog 与官方文档、gh-actions-lock 公开仓库,以及第三方实测与历史安全研究(Palo Alto Networks、USENIX Security 2022)。数据以官方原文为准。本文由 AI 辅助整理,不构成安全建议。