跳至正文
Nodejs — npm Trusted Publishing 与 OIDC:以 astro-book 自动发布为例

npm Trusted Publishing 与 OIDC:以 astro-book 自动发布为例

AI 参与说明(Agent:Codex):本文通过 Context7、npm 与 GitHub 官方文档,以及 astro-book 的公开源码和发布记录整理并校验。资料整理于 2026-09-08;命令版本与案例提交见正文。执行入口:Codex Desktop;本次模型与 reasoning effort 未取得可核验运行记录。本文不包含账号凭据或认证链接。

阅读前先看这几个词

一个项目可以在代码推送后自动发布 npm 包,而不要求维护者每次打开浏览器登录。要理解这件事,先分清“证明这次任务是谁”和“允许它做什么”。

英文术语中文名称简要解释
Trusted Publishing可信发布npm 接受预先授权的 CI workflow 发布包的机制
Trusted Publisher可信发布者包设置中保存的一条授权,例如允许某个 GitHub 仓库的指定 workflow 发布
OIDC(OpenID Connect)开放身份连接让一个系统验证另一个系统提供的身份证明的协议
workflow / job工作流 / 作业GitHub Actions 中定义自动化步骤的文件,以及其中一次执行单元
claim声明字段身份证明里的信息,例如来自哪个仓库、何时过期
access token访问令牌调用受保护操作时使用的凭据,可以长期保存,也可以临时签发
provenance来源证明把发布包与构建它的源码、自动化执行记录关联起来的可验证信息
2FA(two-factor authentication)双重身份验证账号操作时要求额外验证,例如安全密钥或一次性验证码

1. 不保存长期 npm token,仍然有认证

Trusted Publishing authenticates an authorized workflow through OIDC. It does not make package publishing anonymous. npm 官方说明

传统做法是先创建 npm access token,保存到 GitHub Actions Secrets,再在发布时交给 npm。Trusted Publishing 则先在 npm 中建立授权:允许指定来源的 workflow 发布这个包。任务运行时再取得短期凭据,不需要维护者提前把长期 npm access token 复制到 GitHub。

astro-book 的实际关系是:

对象案例中的值作用
GitHub 仓库tcitry/astro-book发布代码与 workflow 的来源
workflow 文件.github/workflows/publish.yml执行发布步骤;npm 设置里只填 publish.yml
npm 包@tcitry/astro-book被授予发布权限的具体包
Trusted PublisherGitHub Actions,绑定上述仓库与文件npm 保存的授权规则

两个平台的用户名是否相同,不是授权条件。 GitHub 的 tcitry 标识仓库所有者,npm 包名前的 @tcitry 是 npm scope。这里恰好相同,不代表 npm 自动把两个账号认作同一个人;即使名称不同,也可以由有权限的 npm 维护者明确授权某个 GitHub 仓库。配置字段及其转换实现

同样,package.json 里的 repository URL 只描述源码位置,不能单凭这个字符串获得发布权限。别人 fork 仓库后,即使保留同样的 package name 和 workflow 文件名,也不匹配原仓库的 Trusted Publisher。

2. GitHub 证明身份,npm 决定权限

GitHub 提供 OIDC 身份证明;npm 根据包维护者建立的 Trusted Publisher 决定是否授权。两边各负责一部分,代码仓库本身不能替 npm 作出授权决定。

flowchart TD
    A[维护者在 npm 配置 Trusted Publisher] --> B[npm 保存仓库与 workflow 的授权条件]
    C[GitHub Actions 启动发布 job] --> D[npm CLI 向 GitHub 请求 OIDC token]
    D --> E[GitHub 签发包含 claims 的 OIDC token]
    E --> F[npm 验证身份与授权条件]
    B --> F
    F --> G{是否匹配}
    G -->|是| H[取得短期发布凭据]
    H --> I[上传经过检查的 npm 包]
    G -->|否| J[拒绝授权]

这张图把一次性配置和每次发布放在一起:上方维护者建立的规则会保留;每次 job 都重新走身份验证与临时授权流程。GitHub 文档将这种机制描述为由 workflow 提供身份信息,再由目标服务验证并签发短期访问权限。GitHub OIDC 机制

OIDC token 采用 JWT 格式,其中包含 claims。与本例有关的字段包括:

claim说明
iss谁签发这份证明;GitHub Actions 的 issuer 是 https://token.actions.githubusercontent.com
aud这份证明面向的接收方;接收方必须验证它适用于自己的用途
repository当前 job 所属仓库
workflow_refworkflow 的来源路径及 Git ref
exp证明的过期时间

这些是 GitHub 支持的字段,不是本次 job 的原始 token 内容。通常不需要开发者自己构造 JWT、把它打印出来或手动调用交换接口;支持 Trusted Publishing 的 npm CLI 会处理认证流程。GitHub OIDC claims

A signed identity is evidence about the caller; authorization is the registry’s decision about what that caller may do. 因此,拥有一个有效的 GitHub OIDC token,并不等于可以发布任意 npm 包;还必须满足目标包的授权条件。

3. Trusted Publisher 是何时设置的

它需要显式配置。对于 astro-book,维护者在首次发布后,通过 npm CLI 把包与 workflow 绑定起来;它不是由相同用户名、一次 Git push 或 npm login 自动生成的。

下面是本例采用的配置命令。它会修改 npm 包权限,仅供该包有管理权限的维护者使用;复用到其他项目时,应替换包名与仓库名,并先确认 package settings 中是否已有连接。

sh
npx npm@12.0.2 trust github @tcitry/astro-book \
  --file publish.yml \
  --repo tcitry/astro-book \
  --allow-publish \
  --yes
  • --file 填 workflow 文件名,不填完整路径。
  • --repo 填 owner/repository。
  • --allow-publish 允许直接执行 npm publish。
  • --yes 跳过命令确认提示,不会绕过 2FA。

该命令等价于在 npm 网页中管理 Trusted Publisher。当前 CLI 将直接发布和 staged publishing 区分为不同权限;只允许 staged publishing 的流程仍需后续审核,不能当作本例的无人值守直接发布。npm trust 文档、权限与 2FA 的实现

在 npmjs 后台查看的路径是:Packages → @tcitry/astro-book → Settings → Trusted publishing。这里保存的是包级别的发布授权,所以它不在账号的 Access Tokens 列表里。可从 包页面 进入 Settings;需要具有相应权限的账号登录。npm 设置入口

本例采用“首次本地发布 → 配置 Trusted Publisher → 后续由 CI 发布”的顺序。第一次创建包和修改发布权限属于账号操作,可能要求交互认证;日常 CI 发布使用已经建立的信任关系。包管理操作与自动化发布没有变成同一种认证方式。

4. GitHub Actions 中哪些配置真正相关

下面是 astro-book 发布 workflow 的核心片段,省略了版本判断和完整验收步骤,不能单独作为完整 workflow 使用。完整文件及其配套脚本固定链接到 已成功发布的提交。

yaml
permissions:
  contents: read
  id-token: write

steps:
  - uses: actions/checkout@v6
  - uses: actions/setup-node@v6
    with:
      node-version: 24
      registry-url: https://registry.npmjs.org/
      package-manager-cache: false
  - run: npm install --global npm@11.12.1
  # 完整 workflow 在这里检查版本,并执行依赖安装与打包验收。
  - run: npm run release:publish -- --provenance

id-token: write 允许 job 请求 OIDC token。这个 write 不表示可以修改仓库,也不直接授予 npm 发布权限;npm 仍会独立检查 Trusted Publisher。contents: read 则供 checkout 等步骤读取仓库。GitHub OIDC permissions

本例使用 GitHub-hosted runner。npm 文档给出的 Trusted Publishing 前提是 npm CLI 11.5.1 或更高版本,以及 Node.js 22.14.0 或更高版本。这里的 Node.js 24、npm 11.12.1 满足该条件;配置 Trusted Publisher 时使用 npm 12.0.2,是为了支持当时的权限参数,不代表日常发布也必须升级到 npm 12。npm 前置条件

在这个仓库中,release:publish 是项目自己的脚本名,实际上传已经验收的 .tgz 文件,并显式使用 --access public。npm scope 不意味着一定私有;这里的 @tcitry/astro-book 是公开包。案例 package.json、npm publish

main 自动发布与 OIDC 是两件事

案例 workflow 在 push 到 main 时运行,但不会为每个 commit 自动生成一个版本号。它读取包版本:已发布就跳过;未发布则执行 build、类型检查、测试和独立项目的真实打包安装验收,最后上传通过检查的 tarball。

上传前还会再次检查版本,减少另一条发布流程抢先上传同一版本所产生的冲突。缓存规避和复查是项目的工程措施,不构成跨流程的原子锁;最终仍由 npm registry 拒绝覆盖已有版本。案例版本判断脚本

因此日常发布仍需要维护者决定新版本号,更新相关 manifest 与 lockfile,并提交到 main。Trusted Publishing 解决认证问题;何时运行、发布哪个版本、需要哪些测试,由项目的 workflow 决定。

本例的 npm 授权绑定了仓库与 workflow,没有额外填写 GitHub environment;main 限制在 workflow 的触发器和 job 条件里。不能把它误读为“npm 另外保存了一条只允许 main 的规则”。有权修改受信任 workflow 的人会影响发布能力,所以仓库写入权限、代码审查与分支保护仍有实际意义。

5. 如何验证它真的自动发布了

@tcitry/astro-book@0.1.1 是本例通过 main 推送触发的实际发布。公开的 GitHub Actions run 显示完整检查及 OIDC 发布步骤成功;npm 的该版本元数据同时包含 provenance 信息。

读者无需发布权限,就能在安装了 Node.js / npm 的终端运行下面的只读查询:

sh
npm view @tcitry/astro-book@0.1.1 \
  name version dist.integrity dist.attestations \
  --json --registry=https://registry.npmjs.org/

预期结果包含包名、0.1.1、SHA-512 integrity,以及 dist.attestations.provenance.predicateType 对应的 https://slsa.dev/provenance/v1。固定查询具体版本,避免未来 latest 更新后改变案例对象。本文整理时已核对这些公开字段。

这里需要区分三种证据:

证据能回答的问题
CI 检查结果这次自动化运行中的哪些检查通过了?
integrity下载的包文件是否匹配指定的摘要?
provenance这个包与哪份源码、哪次构建执行相关联?

Provenance records origin; it does not certify that the package is free of bugs or malicious behavior. 本例保留 --provenance 表明发布意图;npm 对符合条件的公开仓库、公开包的 GitHub Actions Trusted Publishing 也会自动生成 provenance。仅看到元数据里存在一个证明 URL,不等于已经独立验证了证明的签名与全部声明。npm provenance 文档

6. 以后还要人工登录 npm 吗

对于已经配置好的正常 CI 发布,维护者不需要逐次执行 npm login 或打开浏览器认证。认证仍在发生,只是由 GitHub、npm CLI 和 npm registry 自动完成。

但这个结论有明确范围:

  • 本地手动发布:不在受信任的 GitHub Actions job 中,仍可能要求账号登录或 2FA。
  • 修改发布授权:新增、删除或重新绑定 Trusted Publisher 是账号管理操作,可能再次要求身份验证。
  • 安装私有依赖:发布权限不会自动给 npm ci 增加私有包读取权限;私有依赖仍需对应的安装凭据。
  • 授权或环境发生变化:连接被删除、仓库或 workflow 改名、runner 不满足支持条件时,需要修复配置,不能保证永远无需人工处理。

所以准确的承诺是“配置保持有效时,日常 CI 发布无需交互式登录”,而不是“这个账号以后不再需要登录 npm”。npm Trusted Publishing 的适用范围

关联阅读与源码

本文共 3000 字,创建于 Sep 8, 2026

相关标签:Frontend, Nodejs, ByAI

评论

博客助手

正在打开博客助手…