npm Classic Token 作废后,CI/CD 自动发包如何改?一份完整踩坑复盘

背景

最近在给 npm 包做 CI 发版时,突然开始频繁失败,npm 的提示也非常直白:

Classic tokens have been revoked.
Granular tokens are now limited to 90 days and require 2FA by default.
Update your CI/CD workflows to avoid disruption.

一句话总结就是:

老的 npm token 方案,已经不适合 CI 了。

现在就记录一次完整的 CI/CD 改造过程,包含:

  • npm 新规则到底改了什么
  • CI 为什么会突然发布失败
  • 过程中遇到的几个"必踩坑"
  • 最终一套可长期运行的 GitHub Actions 发包方案

一、npm 这次到底动了谁的蛋糕?

先说结论:

npm 正在彻底废弃"长期有效 token + npm login"的发布模型。

核心变化有三点。

1. Classic Token 作废

以前最常见的做法是:

yaml 复制代码
env:
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

这种 Classic Token

  • 长期有效
  • 没有明确权限边界
  • 一旦泄露,后果很严重

现在 npm 明确表态:
Classic Token 不再推荐,并会逐步失效。


2. Granular Token 默认 90 天 + 2FA

新的 Granular Token:

  • 必须开启 2FA
  • 默认 90 天过期
  • 非常不适合无人值守的 CI

👉 这意味着:
即使你换成 Granular Token,CI 依然不稳定。


3. npm 开始强制推广 provenance(供应链校验)

这是最关键、也是最容易被忽略的一点。

npm 现在会校验:

  • 这个包是不是在 GitHub Actions 里发布的
  • 发布它的仓库是谁
  • package.json.repository 指向哪里
  • GitHub OIDC 身份是否匹配

校验失败,直接拒绝发布。


二、为什么"明明登录了",还是发布失败?

我们最初遇到的错误包括:

❌ ENEEDAUTH

vbnet 复制代码
npm error need auth This command requires you to be logged in

原因很简单:

  • CI 里已经不再支持老的登录方式
  • token 被判定为过期或 revoked

❌ 404 / E404

kotlin 复制代码
404 '@scope/package@x.y.z' is not in this registry

这个错误非常迷惑,但本质上是:

npm 拒绝了你的发布请求,并不是包不存在。


❌ 422 Unprocessable Entity(最坑)

vbnet 复制代码
Error verifying sigstore provenance bundle:
package.json: "repository.url" is ""
expected to match "https://github.com/infinilabs/ci"

这一步,几乎是所有人都会踩的坑。


三、npm provenance 校验在校验什么?

npm 的逻辑是:

我不只要你能发布,我还要知道你是从哪里发布的。

它会做一组严格匹配:

校验项 来源
GitHub Actions 所在仓库 CI
OIDC 身份 GitHub
package.json.repository.url 包元数据

只要有一个不一致:

👉 422,拒绝发布。


四、为什么构建产物里的 package.json 会出问题?

我们的发布流程是:

bash 复制代码
pnpm run build:web
cd out/search-chat
npm publish

注意重点:

真正 publish 的不是源码目录,而是构建产物目录。

很多项目在 build 后:

  • package.json 是重新生成的
  • repository 为空
  • 或指向源码仓库,而不是 CI 仓库

这在 npm provenance 时代,直接就是死刑。


五、正确的 CI 改造思路

目标很明确:

不用 npm token,不用 npm login,让 CI 自己完成身份认证。

核心方案是:

✅ GitHub Actions + OIDC + npm provenance


六、关键改造点一:npm 账户设置以及包设置

npm 账户设置:

npm 对应包设置:


七、关键改造点二:开启 OIDC 权限

在 workflow 顶部增加:

yaml 复制代码
permissions:
  contents: read
  id-token: write

这一步非常关键:

  • id-token: write 是 npm provenance 的前提
  • 没有它,npm 无法验证 CI 身份

八、关键改造点三:彻底移除 npm token

我们做了三件事:

  • 删除 NODE_AUTH_TOKEN
  • 删除 .npmrc
  • 不再执行 npm login

CI 里只保留:

复制代码
npm publish

GitHub Actions 会自动用 OIDC 身份和 npm 通信。


九、关键改造点四:修正构建产物里的 repository

在真正 publish 前,强制修正 package.json

vbnet 复制代码
jq '.repository = {
  "type": "git",
  "url": "https://github.com/infinilabs/ci"
}' package.json > tmp.json && mv tmp.json package.json

注意几个要点:

  • URL 必须是当前 CI 所在仓库
  • 不能是源码仓库
  • 不能为空
  • 必须是 https GitHub 地址

十、最终发布流程(核心片段)

bash 复制代码
pnpm run build:web
cd out/search-chat

# 修正 repository
jq '.repository = {
  "type": "git",
  "url": "https://github.com/infinilabs/ci"
}' package.json > tmp.json && mv tmp.json package.json

# 发布
npm publish

发布成功时,npm 会输出:

  • provenance 已签名
  • 已写入 sigstore transparency log

十一、为什么不直接关 provenance?

npm 提供了:

css 复制代码
npm publish --no-provenance

但这只是一个 临时选项

  • 官方趋势是默认开启
  • 未来可能直接强制
  • CI 早适配,后面少折腾

十二、这次改造后的收益

最终我们得到的是一套:

  • ✅ 无 token
  • ✅ 无 2FA 人工参与
  • ✅ 不会过期
  • ✅ 可审计、可追溯
  • ✅ 符合 npm 官方长期路线

真正意义上的 无人值守 CI 发包


十三、小结

npm 不再相信"你是谁",

它只相信 你从哪里来

在这个前提下,
OIDC + provenance,不是可选项,而是必选项。

相关推荐
yyuuuzz2 小时前
aws亚马逊入门常见认知误区
运维·服务器·网络·云计算·github·aws
逛逛GitHub7 小时前
你的 Mac 就是一个 AI Agent,4B 模型本地操控电脑。
github
铁皮哥9 小时前
【后端/Agent 开发】给你的项目配置一套 .claude/ 工作流:别再裸用 Claude Code 了!
java·windows·python·spring·github·maven·生活
Resistance丶未来11 小时前
Agency-Agents 多智能体协作系统落地指南
python·大模型·nlp·github·copilot·claude·gemini
輕華11 小时前
YOLOv5 实战:从 GitHub 拉取到自定义数据集训练
yolo·github
海域云-罗鹏13 小时前
豆包开启付费订阅,想白嫖越来越难了,企业不如部署自己的算力服务器
服务器·人工智能·github
遁神银灵子14 小时前
OMO(oh-my-openagents)插件在OpenCode Desktop v1.4.33以上版本失效问题研究
github
码流怪侠15 小时前
【GitHub】TextGen:开源本地大模型运行平台的终极解决方案
python·程序员·github
小雨青年15 小时前
GitHub Copilot Commit Message 生成与自定义配置优化指南
人工智能·github·copilot
无限进步_16 小时前
【C++】AVL树完全解析:从平衡因子到四种旋转
c语言·开发语言·数据结构·c++·后端·算法·github