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,不是可选项,而是必选项。

相关推荐
笨鸟先飞,勤能补拙10 小时前
下一个十年:网络安全正在被重写
网络·人工智能·安全·web安全·网络安全·github
潘正翔11 小时前
k8s进阶_Harbor镜像仓库
git·云原生·容器·kubernetes·gitee·github
vibecoding7711 小时前
GitHub 2026 年 7 月热榜:累计 Star 总榜与月度飙星榜
人工智能·github·ai编程
Pniubi11 小时前
Gitee&GitHub同步仓库教程
gitee·github
TunerT_TQ12 小时前
GitHub深度工程评测:AI 系统提示词泄露知识库深度评测:6万星system_prompts_leaks情报资产背后,藏着什么?
人工智能·chatgpt·github·提示词工程·#valhalla静态工程审阅·systemprompt·大模型工程
茉莉玫瑰花茶13 小时前
TCP 全连接队列与 tcpdump 抓包
git·github·tcp·tcpdump
炸膛坦客14 小时前
Git 和 GitHub:(十四)rebase 到某个有新提交的远程仓库的分支
git·github
小弥儿14 小时前
GitHub今日热榜 | 2026-07-31:AI Agent工作流共享赛道升温
人工智能·学习·github
白猫不黑1 天前
GitHub 30K Star 的 AI 渗透测试工具
web安全·网络安全·信息安全·渗透测试·github·ai渗透测试
炸膛坦客1 天前
Git 和 GitHub:(十二)基于远程仓库的某一个分支的某一笔提交创建新分支
git·github