ZeroClaw 发布工件验证指南:基于 GitHub Artifact Attestations 的 SLSA 在线与离线验证
【免费下载链接】zeroclawFast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platform — deploy anywhere, swap anything 🦀项目地址: https://gitcode.com/gh_mirrors/ze/zeroclaw
ZeroClaw 以 GitHub artifact attestations 作为所有可下载发布资产的规范来源(canonical provenance)机制,为每次稳定发布记录资产摘要(digest)、源码提交与发布工作流身份,形成 SLSA v1.0 Build Level 2 出处证明。本指南完整讲解如何在联网环境中在线验证发布资产、如何在完全断网的环境中借助zeroclaw-vX.Y.Z-verification.tar.gz离线归档完成引导式信任验证,以及如何核对 SPDX/CycloneDX 双格式 SBOM 与 cosign 签名的 GHCR 容器镜像。读完本文,你将掌握 ZeroClaw 从"下载即信任"升级为"可独立核验来源"的完整实操路径,并理解其证明边界与威胁模型。
验证机制概览:出处证明能证明什么、不能证明什么
ZeroClaw 的发布管线以 release-stable-manual.yml 中的publish任务为核心,通过actions/attest(当前锁定v4.2.2)为每个发布载荷生成 SLSA v1.0 Build Level 2 出处证明,并记录在 GitHub 的 artifact-attestation API 中。完整的威胁模型与验证路径定义见 docs/security/slsa-provenance.md。
一次成功的验证能够确立:
- 本地文件与签名证明(attestation)中的摘要一致;
- 该证明是为 ZeroClaw 仓库签发的;
release-stable-manual.yml是签名工作流(signer workflow);- 证明指向预期的源码提交(source commit)。
它确立的是构建来源与记录的构建指令,但不能证明源码经过人工评审、依赖是安全的,也不能排除维护者账号、GitHub 托管 runner 或 GitHub 控制平面被攻陷的可能。完整威胁模型如下表(源自 slsa-provenance.md):
| 威胁 | 是否覆盖 | 说明 |
|---|---|---|
| 发布页写入权限被滥用、替换载荷 | 是 | 被替换的文件与已签名摘要不匹配,验证失败 |
| 本地构建被伪装成官方 CI 构建 | 是 | 签名工作流与源码摘要检查失败 |
| 开发者机器被攻陷 | 部分 | 本地构建的替代物无法通过验证,但被窃取的维护者凭证仍可能授权仓库变更 |
| 恶意或有漏洞的依赖 | 否 | 出处只记录来源,内容安全由 SBOM 与漏洞分析负责 |
| GitHub 托管 runner 被攻陷 | 否 | runner 可在证明步骤之前篡改输入 |
| 维护者账号被攻陷 | 否 | 授权账号可改动源码或工作流指令 |
| GitHub OIDC 或控制平面被攻陷 | 否 | GitHub 是签名与托管证明存储的信任根 |
| 缺失 Phase A 证明 | 否 | 尽力而为(best-effort)的失败会在发布说明中披露,消费方不得把"缺失"当作"成功" |
发布工作流当前把证明视为尽力而为的 Phase A 输出(continue-on-error: true)。因此在使用验证材料之前,务必先查阅发布说明(release notes):说明中会明确本次是否产出了在线出处证明与离线归档。若某项证明步骤失败,发布仍会继续,但发布说明必须披露缺口并链接到对应的工作流运行。
在线验证:直连 GitHub 核验资产
联网环境下验证最简单。安装 GitHub CLI,下载资产,然后对照发布工作流与源码提交执行验证:
VERSION=vX.Y.Z SOURCE_DIGEST=<40-character-release-commit> ASSET=zeroclaw-x86_64-unknown-linux-gnu.tar.gz gh release download "$VERSION" --repo zeroclaw-labs/zeroclaw \ --pattern "$ASSET" gh attestation verify "$ASSET" \ --repo zeroclaw-labs/zeroclaw \ --signer-workflow zeroclaw-labs/zeroclaw/.github/workflows/release-stable-manual.yml \ --source-digest "$SOURCE_DIGEST"要点说明:
SOURCE_DIGEST应使用发布 tag 所指向的完整 40 位提交哈希,而不是缩写或 tag 名本身;--signer-workflow必须精确匹配release-stable-manual.yml的完整仓库路径,签名身份绑定在该工作流上;- 验证成功时,命令会打印已核验的证明与主题(subject)摘要;
- 同样的命令适用于
install.sh、SHA256SUMS、两个 SBOM 文件以及验证归档(verification archive)。
从实现侧看,publish任务仅在作业级别授予id-token: write与attestations: write权限(见 release-stable-manual.yml),工作流级不授予 OIDC 权限,因此validate、build等非签名作业无法铸造 OIDC 令牌——这是最小权限原则在签名链路上的体现。
离线验证:通过验证归档实现断网信任
由合并后的发布工作流产出且 Phase A 输出完整的发布,会额外发布一个归档:zeroclaw-vX.Y.Z-verification.tar.gz。其中包含:
- 每个发布载荷对应的一个
<artifact>.attestation.jsonl离线证明包; trusted_root.jsonl:GitHub 与 Sigstore 的信任根材料;ATTESTATION-BUNDLES.md:工件名、SHA-256 摘要与包名的索引。
注意一个结构性问题:归档无法包含对自身的证明,否则会形成循环摘要(改动归档内容必然改变其被证明的摘要)。因此信任引导必须在联网时完成——先在线验证归档与最终校验和文件,再将工件、归档与校验和文件一并转移到离线环境。
连网暂存步骤(Connected staging)
VERSION=vX.Y.Z SOURCE_DIGEST=<40-character-release-commit> ASSET=zeroclaw-x86_64-unknown-linux-gnu.tar.gz VERIFY_ARCHIVE="zeroclaw-${VERSION}-verification.tar.gz" gh release download "$VERSION" --repo zeroclaw-labs/zeroclaw \ --pattern "$ASSET" \ --pattern SHA256SUMS \ --pattern "$VERIFY_ARCHIVE" gh attestation verify "$VERIFY_ARCHIVE" \ --repo zeroclaw-labs/zeroclaw \ --signer-workflow zeroclaw-labs/zeroclaw/.github/workflows/release-stable-manual.yml \ --source-digest "$SOURCE_DIGEST" gh attestation verify SHA256SUMS \ --repo zeroclaw-labs/zeroclaw \ --signer-workflow zeroclaw-labs/zeroclaw/.github/workflows/release-stable-manual.yml \ --source-digest "$SOURCE_DIGEST" awk -v file="$VERIFY_ARCHIVE" '$2 == file { print }' SHA256SUMS | sha256sum -c - mkdir verification tar -xzf "$VERIFY_ARCHIVE" -C verification迁移前还应将工件摘要与SHA256SUMS中的对应行做一次比对:
awk -v file="$ASSET" '$2 == file { print }' SHA256SUMS | sha256sum -c -断网验证步骤(Disconnected verification)
当--bundle与--custom-trusted-root均指向暂存好的验证材料时,不需要任何网络请求:
gh attestation verify "$ASSET" \ --repo zeroclaw-labs/zeroclaw \ --signer-workflow zeroclaw-labs/zeroclaw/.github/workflows/release-stable-manual.yml \ --source-digest "$SOURCE_DIGEST" \ --bundle "verification/${ASSET}.attestation.jsonl" \ --custom-trusted-root verification/trusted_root.jsonlgh attestation verify在提供了--bundle和--custom-trusted-root后即可完全离线执行,这是断网环境下完成密钥级(keyless)验证的关键。SHA256SUMS与验证归档属于"在线引导元数据",在归档内部没有对应包;而归档构建之前已存在的所有载荷(包括install.sh和两个 SBOM)都包含各自的离线包。
从实现看,归档的构建逻辑严格遵循"先证明、后打包"的顺序(见 release-stable-manual.yml):先对release-assets/*执行attest_payloads,再下载每个离线包并逐一用gh attestation verify校验(--bundle指向下载的包、--custom-trusted-root指向刚抓取的信任根),随后生成ATTESTATION-BUNDLES.md索引并打包。gh attestation trusted-root抓取信任根,且脚本兼容冒号与连字符两种 bundle 文件名形式(部分平台文件系统拒绝冒号)。最终SHA256SUMS只在归档存在后生成(先find后xargs sha256sum,排除自身),并且不得在元数据证明之后修改——任何修改都会让SHA256SUMS与verification archive的证明失效,这正是 release-attestation-runbook.md 强调"不要把校验和生成挪到归档创建之前、也不要在证明后编辑 SHA256SUMS"的原因。
SBOM:双格式、带校验和、可验证
每次发布都会发布两个经校验和与证明的 SBOM 文件:
| 文件 | 格式 |
|---|---|
zeroclaw-vX.Y.Z-sbom.spdx.json | SPDX JSON |
zeroclaw-vX.Y.Z-sbom.cdx.json | CycloneDX JSON |
对任一 SBOM 使用与二进制资产完全相同的在线或离线证明命令即可核验,之后可交给 Syft、Grype 等工具进一步审查其内容。SBOM 由sbom作业中的anchore/sbom-action(锁定v0.24.2)分别以spdx-json与cyclonedx-json格式生成(见 release-stable-manual.yml),两个文件都会进入发布资产与验证归档。
需要留意的是,SBOM 生成属于发布管线的硬性前置:任一 SBOM 生成步骤失败都会在发布前终止流程,避免发布"部分覆盖"或"半成品"的物料清单(见 release-attestation-runbook.md 的失败症状表)。
容器镜像:cosign 按摘要签名验证
GHCR 容器镜像独立于 GitHub 可下载资产证明路径,仍由 cosign 按摘要(digest)签名,二者互不替代。验证命令:
IMAGE=ghcr.io/zeroclaw-labs/zeroclaw TAG=vX.Y.Z cosign verify \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ --certificate-identity-regexp "^https://github.com/zeroclaw-labs/zeroclaw/" \ "${IMAGE}:${TAG}"对于固定版本部署,建议先解析出不可变摘要,再验证${IMAGE}@${DIGEST},而不是验证可变的 tag。工作流侧,docker作业同样只在作业级授予id-token: write(cosign 无密钥 OIDC 签名所必需,见 release-stable-manual.yml),并通过sigstore/cosign-installer(锁定v3.8.1)执行cosign sign;发布后的演练检查清单要求两个 GHCR 镜像变体均能以不可变摘要通过 cosign 验证。
发布后的检查清单与演练要求
正式发布后,维护者应确认以下资产形态(源自 release-runbook.md 的 Step 6):
[ ] GitHub Release 存在且标记为 Latest [ ] Release notes 非空 [ ] SHA256SUMS 资产存在且非空 [ ] SPDX 与 CycloneDX 两个 SBOM 资产均存在 [ ] 恰好一个 zeroclaw-vX.Y.Z-verification.tar.gz 资产存在 [ ] 不存在散落的 *.bundle、*.attestation.jsonl 或 *.intoto.jsonl 资产 [ ] 至少一个二进制归档可下载(抽查 linux x86_64) [ ] Docker 预构建与生成矩阵作业均绿色任何涉及发布证明的工作流变更之后,必须在关闭追踪 issue 前由人工维护者完整执行一遍在线与断网验证演练(命令见 release-attestation-runbook.md),并将发布 tag、工作流运行 URL、精确命令与脱敏输出记录在实现 PR 中。仅做工作流 lint 或act本地模拟不能替代该演练——两者都无法铸造 GitHub 生产环境的 OIDC 证明。
从实现到消费:publish 作业的证明流水线
publish作业(权限contents: write、id-token: write、attestations: write)按固定顺序执行证明相关操作(见 release-stable-manual.yml 与 release-attestation-runbook.md):
- 生成 SPDX 与 CycloneDX 两个 SBOM;
- 收集全部发布载荷,包括
install.sh与两个 SBOM; - 通过 GitHub 对这些载荷执行证明(
attest_payloads,continue-on-error: true); - 下载并本地核验每个离线包(
gh attestation download+gh attestation verify,失败重试 5 次); - 将包、信任根与索引打包成一个验证归档;
- 生成最终
SHA256SUMS(包含验证归档); - 对
SHA256SUMS与验证归档分别证明(attest_checksums、attest_verification_archive); - 从
release-assets/*创建 GitHub Release。
值得注意的失败语义:Attest release payloads失败时发布继续(此时任何下载载荷都没有可信出处,需在发布说明披露);Package offline verification archive失败时在线验证仍然可用但无离线归档;SBOM 生成失败则发布在发布前停止。HTTP 401/429/5xx、OIDC token 或 GitHub API 故障属于服务性问题,可查 GitHub Status 后在服务恢复时重试;而缺失id-token: write或attestations: write权限属于工作流回归而非瞬时故障。关键约束是:证明依赖工作流运行签发的 GitHub OIDC 令牌,事后无法从维护者工作站重建。
实践建议与验证边界
- 始终先读发布说明:确认本次发布是否声明产出了在线出处证明与离线归档;Phase A 尽力而为模式下,"没有证明"不等于"验证通过"。
- 离线场景走完整引导链:先在线验证归档与
SHA256SUMS,再迁移载荷与解包材料到断网环境,最后用--bundle+--custom-trusted-root完成零网络验证。 - 固定部署用摘要:容器镜像与二进制资产都优先以不可变摘要校验,而非可变 tag。
- 理解证明边界:SLSA Build Level 2 证明回答的是"在哪里、由谁构建",不回答"代码是否安全";内容安全交由 SBOM 与漏洞扫描工具处理。
相关仓库证据:验证命令的规范来源是 release-verification.md;威胁模型与验证路径见 slsa-provenance.md;管线实现见 release-stable-manual.yml;维护者演练要求见 release-attestation-runbook.md;完整发布流程见 release-runbook.md。
【免费下载链接】zeroclawFast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platform — deploy anywhere, swap anything 🦀项目地址: https://gitcode.com/gh_mirrors/ze/zeroclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考