☰
Extension.js 发布产物校验指南:用 Sigstore 与 SLSA 验证 npm 包和 Release 的完整性
2026/10/13 2:57:28 网站建设 项目流程
  • 开发工具
  • CLI
  • 前端构建

【免费下载链接】extension-create

The cross-browser extension framework.

项目地址:https://gitcode.com/gh_mirrors/ex/extension-create
点击查看免费下载

Extension.js(本仓库即其源码)的每一个发布版本都使用 Sigstore 进行无密钥(keyless)签名,npm 包携带来源证明(provenance),GitHub Release 附带 SLSA 证明文件。本文基于 docs/VERIFYING_RELEASES.md,完整讲解"为什么可以无密钥签名"以及"如何用npm audit signatures、gh attestation verify、slsa-verifier三步验证发布产物",并结合本仓库的发布流水线源码(.github/workflows/release-attest.yml、.github/workflows/publish-release.yml)说明校验背后的实现细节。

读完本文,你将掌握:如何审计项目依赖中 Extension.js 四个 npm 包的签名与来源证明、如何核对某个版本的 attestation 详情、如何验证 GitHub Release 上 tarball 与 SLSA 证明文件的对应关系,以及新旧两种证明文件(provenance.intoto.jsonl与multiple.intoto.jsonl)各自对应的校验工具与参数差异。

为什么可以"无密钥"签名:Sigstore 信任模型

官方文档首先解释了整个签名体系的设计前提:

Every Extension.js release is signed with Sigstore. Signing is keyless.

所谓 keyless(无密钥)签名,核心是不存在长期有效的私钥:

  • Sigstore 的Fulcio组件会为构建发布版本的 GitHub Actions 工作流签发一个短期证书(short-lived certificate);
  • 签名记录同时写入Rekor透明日志(transparency log),任何人都能追溯;
  • 由于没有长期私钥,npm、GitHub 或任何分发站点上都没有可泄露的签名密钥;
  • 公共信任根(public trust roots)属于 Sigstore 本身,下面所有校验工具都会自动为你获取这些信任根。

这种设计把"密钥管理"问题转化为"工作流身份 + 透明日志"问题:攻击者无法通过窃取某个长期密钥来伪造发布,因为签名身份是每次构建临时产生的,且记录公开可查。在本仓库的 docs/ASSURANCE_CASE.md 中,这一机制被明确列为"源代码仓库与发布包之间"信任边界(Trust boundary 5)的保障:发布工作流运行在 GitHub 托管的 runner 上,配合 OIDC 发布与 Sigstore 来源证明;同时它也是 CWE-494(未经验证下载的代码)的对策之一——"npm 完整性哈希 + 包签名来源证明"。

校验 npm 包:来源证明(npm provenance)

Extension.js 一共发布四个公共 npm 包,发布范围在 docs/RELEASING.md 中列明:

源码目录npm 包名用途
programs/extensionextensionCLI 元包,聚合其余三个包
programs/createextension-create独立的脚手架创建引擎
programs/developextension-develop开发、构建、预览与打包
programs/installextension-install浏览器运行时安装支持

这四个包均以 npm provenance 发布。发布侧的证据在 .github/workflows/publish-release.yml 中:

  • 工作流环境变量NPM_CONFIG_PROVENANCE: "true"(第 29 行);
  • 每个包的发布命令均带--provenance标志,例如npm publish --access public --tag ${{ steps.validate.outputs.tag }} --provenance(第 530–535、571–576 行,四个包各有一次);
  • 发布不读取任何 npm token,而是通过 GitHub OIDC 可信发布(trusted publishing,id-token: write),与 docs/RELEASING.md 中"npm authentication: the workflow publishes through npm trusted publishing with GitHub OIDC"的描述一致。

审计项目内已安装的包

在安装了这些包的任意项目里运行:

npm audit signatures

输出中必须报告这四个包的 verified registry signatures(已验证的注册表签名)与 verified attestations(已验证的来源证明)。这一步直接校验node_modules中已安装产物的完整性,是最快的日常检查手段。

查看某个版本的 attestation 详情

如需查看某一版本的来源证明内容,例如 4.1.18:

npm view extension@4.1.18 dist.attestations

该命令输出该版本发布时的证明元数据(包含签名的 build 信息等)。此外,npm 的包页面也会显示一个Provenance区块,其中链接到构建该发布的确切工作流运行记录与 commit——也就是说,你可以从包页面一路追溯到"这个 tarball 是哪次 CI 运行构建出来的"。

校验 GitHub Release tarball

除了 npm,每个 GitHub Release 还会附带四个包的 tarball 和一份已签名的 SLSA 证明文件。官方文档特别强调两个关键事实:

  1. Release 上的 tarball 与 npm 包字节完全一致("The release tarballs have the same bytes as the npm packages");
  2. 发布工作流在上传之前,会先对照注册表完整性哈希(registry integrity hashes)逐一核对它们。

这两点在 .github/workflows/release-attest.yml 中有对应的实现细节:subjects任务通过npm pack <name>@<version>从注册表取回 tarball,然后用npm view <pkg>@<ver> dist.integrity取期望值,再以openssl dgst -sha512计算实际哈希,两者不一致立即失败("does not match the registry integrity")。也就是说,Release 资产在生成时就已被证明与 npm 分发的内容同源。

使用方式:从仓库的 Releases 页面下载 tarball 与对应版本的证明文件,然后根据该 Release 上的证明文件名选择匹配的校验命令——这取决于该版本由哪条工作流签名。

新版本:provenance.intoto.jsonl,用gh attestation verify

较新的 Release 携带provenance.intoto.jsonl,由release-attest.yml工作流配合 GitHub 的 attestation action(actions/attest-build-provenance)签名。校验命令(需安装 GitHub CLI):

gh attestation verify extension-X.Y.Z.tgz \ --repo extension-js/extension.js \ --bundle provenance.intoto.jsonl \ --signer-workflow extension-js/extension.js/.github/workflows/release-attest.yml

参数说明:

  • extension-X.Y.Z.tgz:替换为你实际下载的 tarball 文件名;
  • --repo extension-js/extension.js:声明产物来源仓库,防止跨仓库混淆;
  • --bundle provenance.intoto.jsonl:指定本地下载的 Sigstore bundle 文件;
  • --signer-workflow extension-js/extension.js/.github/workflows/release-attest.yml:将签名身份钉死到这条工作流文件,避免"任何工作流签名都能通过"的宽泛校验。

官方文档还说明:如果不带--bundle,gh attestation verify会直接从 GitHub 拉取同一份 attestation 进行校验——因为 GitHub 同时把证明存储在仓库的 attestation API 中(对应release-attest.yml中attestations: write权限与Attest build provenance步骤)。

旧版本:multiple.intoto.jsonl,用slsa-verifier

较早的 Release 携带multiple.intoto.jsonl,由 SLSA GitHub generator(slsa-github-generator 可复用工作流)签名。校验前先安装 slsa-verifier,然后运行:

slsa-verifier verify-artifact extension-X.Y.Z.tgz \ --provenance-path multiple.intoto.jsonl \ --source-uri github.com/extension-js/extension.js

两点注意事项(官方文档明确强调):

  • 命令必须打印PASSED才算通过;
  • 必须使用--source-uri而不是--source-tag:因为证明文件记录的 source ref 是main——attest 工作流并不在 tag 上运行,用--source-tag会校验失败。

从源码角度看,这条历史差异的来龙去脉记录在 .github/workflows/release-attest.yml 的注释中:旧的 slsa-github-generator 拒绝 commit 固定(pin),所以早期版本携带multiple.intoto.jsonl;迁移到 GitHub 官方attest-build-provenanceaction(按 commit 固定)后,新版本改带 Sigstore bundle(provenance.intoto.jsonl),并且同一份证明同时保存在 GitHub 上,因此两种校验方式(带--bundle或不带)都能验证同一个 tarball。

背后的发布与证明流水线

理解校验命令之后,再看流水线本身会更容易把握"证明从哪里来"。

发布流水线(publish-release.yml)

发布由Release – Publish工作流驱动,支持三条通道:

通道npm dist-tag说明
stablelatest正式版,需纯净 semver(如4.1.33)
nextnext预发布,需-next.*形式
canarycanary静默发布,自动版本号<base>-canary.<run_number>.<short_sha>,不建 GitHub Release

对 stable/next,CI 构建后生成 release notes、提交版本号、打v<version>tag、创建 GitHub Release 与 Deployment;canary 则全部跳过。发布时通过 OIDC 可信发布 +--provenance,整个过程不读取 npm token。

证明流水线(release-attest.yml)

该工作流与发布工作流刻意解耦("decoupled from publish-release.yml on purpose"),由三个事件触发:

  • workflow_run:发布工作流成功完成后触发(常规路径);
  • releasepublished:手动把草稿 Release 转为公开时触发;
  • workflow_dispatch:手动为某个 tag 补签(backfill),例如gh workflow run release-attest.yml -f tag=v4.1.17。

其内部由四个任务串成:

  1. resolve:解析出要签名的 release tag,拒绝 draft 状态;
  2. subjects:从 tag 自身的 package.json 读取四个包名,等待 npm 复制完成后拉取 tarball,用 sha512 对注册表 integrity 做逐字节核对,再算出sha256sum作为证明的 subject 列表;
  3. provenance:用 OIDC 令牌调用actions/attest-build-provenance做 keyless Sigstore 签名,把 bundle 以provenance.intoto.jsonl上传到 Release;
  4. assets:重新拉取 tarball、再次核对 integrity,用gh attestation verify --bundle provenance.intoto.jsonl逐一验证后才把 tarball 上传到 Release。

这个"先传证明、后传产物"的顺序是有意为之的保证:任何失败都只会让 Release 停留在"未评分"或"仅含证明"的状态,绝不会出现"有 tarball 却没有证明"的不可校验状态(注释中提及 OpenSSF Scorecard 的 Signed-Releases 检查会据此评分)。

校验实践建议与常见注意点

综合文档与仓库源码,可以总结出几条可落地的操作要点:

  • 日常依赖审计:在项目里定期运行npm audit signatures,确认四个 Extension.js 包均为 verified registry signatures + verified attestations;
  • 核对单个版本:用npm view extension@<version> dist.attestations查看来源证明,再结合 npm 包页面的 Provenance 区块追溯到具体工作流运行与 commit;
  • 验证 Release tarball:先看该 Release 携带的是哪种证明文件——provenance.intoto.jsonl用gh attestation verify(记得带--signer-workflow收紧签名身份),multiple.intoto.jsonl用slsa-verifier verify-artifact(用--source-uri而非--source-tag,并确认输出PASSED);
  • 新旧版本差异:同一仓库的不同版本可能使用不同的证明格式与签名工作流,务必"按文件匹配命令",不要拿新命令去验旧文件;
  • canary 与草稿 Release:canary 通道不创建公开 Release;草稿状态的 Release 不会被 attest 工作流处理(会直接拒绝),需要先公开再触发校验。

延伸阅读

  • docs/VERIFYING_RELEASES.md:本文的原始依据文档;
  • docs/RELEASING.md:发布通道、版本规则与 npm 可信发布细节;
  • docs/ASSURANCE_CASE.md:将签名与来源证明置于整体安全模型中的论证;
  • .github/workflows/release-attest.yml:SLSA 证明与 tarball 上传的实现;
  • .github/workflows/publish-release.yml:--provenance发布与 OIDC 可信发布的实现;
  • 四个发布包的publishConfig(public 访问与 npmjs 注册表)可见于 programs/extension/package.json、programs/create/package.json、programs/develop/package.json、programs/install/package.json。
  • 开发工具
  • CLI
  • 前端构建

【免费下载链接】extension-create

The cross-browser extension framework.

项目地址:https://gitcode.com/gh_mirrors/ex/extension-create
点击查看免费下载
上一篇:B站弹幕太吵?用这个弹幕屏蔽词分享平台,3 步找回清净
下一篇:TiXL 交互 Gizmo 指南:在输出视口中直接拖拽操控三维对象

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询