attested-delivery/attested-pipeline-template

GitHub: attested-delivery/attested-pipeline-template

语言无关的 GitHub Actions 发布流水线模板,通过 SLSA 来源证明、SBOM、安全门禁签名和失败阻断验证,确保仅经过完整校验的制品被发布。

Stars: 0 | Forks: 0

# attested-pipeline-template 一个与语言无关的 GitHub 仓库模板,演示了**经过验证的发布架构**(attested release architecture):到达消费者手中的每一个制品(artifact)都与经过验证的版本在字节上完全一致,携带 SLSA 来源(provenance)和 SBOM 证明(attestations),并在每个环节重新验证,且发布过程在验证失败时会阻断(fail-closed)。 标签(tag)不会发布任何未经验证的内容。 ## 不变量 ``` build → attest-provenance → generate+attest-SBOM → fail-closed-verify → [tag-gated] publish ``` 没有步骤可以跳过。如果 `verify` 失败,`publish` 将不会运行 —— GitHub Actions 通过 `needs:` 依赖图来强制执行这一点。 ## 此模板包含的内容 ``` .github/ workflows/ release.yml # The attested release pipeline (see below) ci.yml # CI + mandatory action-pin check SECURITY.md # Verification instructions for consumers README.md # This file LICENSE # Apache-2.0 ``` ### `release.yml` — 经过验证的发布流水线 | Job(作业) | 功能描述 | 关键权限 | |---|---|---| | `meta` | 从 git ref 解析制品名称 + 版本 | `contents: read` | | `build` | 构建制品,证明(attest) SLSA 构建来源,暴露主体摘要(subject digest) | `id-token: write`, `attestations: write` | | `sbom` | 通过 Syft 生成 CycloneDX SBOM,并进行证明 | `id-token: write`, `attestations: write` | | `gate-sast` / `attest-sast` | SAST (CodeQL) → 对主体生成 seam-sign 判定 (`sast/v1`) | `security-events: write` / `attestations: write` | | `gate-sca` / `attest-sca` | SCA (OSV) → 对主体生成 seam-sign 判定 (`sca/v1`) | `security-events: write` / `attestations: write` | | `gate-trivy` / `attest-iac-license` | IaC/license (Trivy) → 生成 seam-sign 判定 (`iac-license/v1`) | `security-events: write` / `attestations: write` | | `vex` | OpenVEX 处置,自签名(`reusable-vex.yml`,`openvex.dev/ns/v0.2.0`)应用于主体 | `id-token: write`, `attestations: write` | | `verify` | **失败阻断(Fail-closed)**:验证来源 + SBOM + 每一项 seam 判定 (sast/sca/iac-license) + VEX | `attestations: read` | | `publish` | 创建带有校验和的 GitHub Release | `contents: write` — 仅在推送 tag 时触发,且仅在 `verify` 通过时运行 | 该流水线支持将 `workflow_dispatch` 作为试运行(dry-run):完整的 构建 → 证明 → 验证链条会运行,但 `publish` 会被跳过(受 tag 限制)。 **制品判定在发布时被签名并验证。** 每一个用于描述已发布制品的 gate 判定 —— SAST (CodeQL)、SCA (OSV)、IaC/license (Trivy)、container-scan (Trivy image) 和 DAST (ZAP) —— 都会在发布时被签名并验证,通过摘要绑定到发布主体上。SAST 分析的是确切要发布的源代码,因此它的判定会像其他判定一样伴随发布一同传递。供应链安全态势(Scorecard)是一个仓库级别的信号,而不是 制品判定。此模板是一个**完整的验证参考**:`release.yml` 中包含 SAST + SCA + IaC/license + VEX,`dast.yml` 中包含 DAST,`quality-gates.yml` 中包含合并时的 SAST/SCA/Scorecard/Trivy。Container-scan (Trivy image) 在此 不适用(此模板发布的是 tarball,而不是 image);有关容器化的变体,请参见 `attested-delivery/rust-template`。 ### `quality-gates.yml` — 合并时的 gate 这是针对中心化 SAST (CodeQL)、SCA (OSV)、安全态势 (Scorecard) 以及 IaC/license (Trivy) 可复用工作流的轻量级调用方。每一个都以 SARIF 进行标准化,并显示在 仓库的 Security 标签页下;您可以将 "Code scanning results" 设置为必需的状态检查(status check), 使其成为合并 gate。安全态势(Scorecard)在此作为仓库级别的信号存在。 ### `ci.yml`` — CI + Pin 检查 包含一个强制性的 `pin-check` 作业 —— 它是中心化的 `attested-delivery/.github` **`pin-check.yml`** 可复用工作流的轻量级调用方(通过 `.github` 仓库的 commit SHA 进行锁定),符合 CLAUDE.md 第 2/3 节的要求(使用中心化的可复用工作流,绝不 重复造轮子)。如果任何 `uses:` 通过 tag 或 分支而不是完整的 40 个字符的 commit SHA 引用 action,它将失败并阻断。 ### `dast.yml` — 经过验证的 DAST (ZAP) 具体的 DAST 示例:将中心化的 `reusable-zap.yml` 指向一个**正在运行** 的目标(`workflow_dispatch` 输入 `target`,默认为组织已部署的站点), 然后 `attest-dast` 对判定进行 seam-sign 签名,作为绑定到主体摘要上的 `dast/v1`, 并且一个失败阻断的 `verify` 作业会对其重新检查。请搭建您自己已部署的 preview/staging 环境并传入其 URL。要求组织 Actions 允许列表(allow-list)必须允许 单个 action `zaproxy/action-full-scan@*`(或其确切锁定的 SHA)—— 而不是 `zaproxy/*` 拥有者通配符 —— 因为 `reusable-zap.yml` 会拉取 `zaproxy/action-full-scan`。 ## 适配此模板 ### 1. 将此作为模板仓库使用 在 GitHub 上点击 **"Use this template"** 以创建一个新仓库。 ### 2. 替换构建步骤 在 `release.yml` 中,找到 `build` 作业中的 `# ADAPT THIS STEP` 块: ``` - name: Build artifact run: | # Replace this with your toolchain's build command. # Output MUST land under dist/ git archive --format=tar.gz ... ``` 按不同语言的示例: **Go:** ``` - name: Build artifact run: | mkdir -p dist GOOS=linux GOARCH=amd64 go build -o dist/${NAME}-${VERSION}-linux-amd64 ./cmd/... ``` **Rust:** ``` - name: Build artifact run: | cargo build --release --locked mkdir -p dist cp target/release/mybinary dist/${NAME}-${VERSION}-linux-amd64 ``` **Node.js:** ``` - name: Build artifact run: | npm ci npm run build mkdir -p dist tar -czf dist/${NAME}-${VERSION}.tar.gz --exclude=node_modules . ``` **Docker:** 将 `actions/attest-build-provenance` 与指向 `docker buildx build --iidfile` 输出的 image digest 的 `subject-digest` 配合使用。 ### 3. 更新 action 的 SHA 此模板中的 action SHA 是在 **2026-06-18** 解析的。定期轮换它们: ``` gh api repos/actions/checkout/commits/v4 --jq .sha gh api repos/actions/attest-build-provenance/commits/v2 --jq .sha gh api repos/actions/attest-sbom/commits/v2 --jq .sha gh api repos/anchore/sbom-action/commits/v0 --jq .sha gh api repos/softprops/action-gh-release/commits/v2 --jq .sha gh api repos/actions/upload-artifact/commits/v4 --jq .sha gh api repos/actions/download-artifact/commits/v4 --jq .sha ``` 更新工作流文件中的 SHA 以及末尾的 `# vX.Y.Z` 注释。 ### 4. 更新 SECURITY.md 中的仓库引用 将 `attested-delivery/attested-pipeline-template` 替换为您的组织/仓库(org/repo)。 ### 5. 发布 ``` git tag v1.0.0 git push origin v1.0.0 ``` 发布流水线将自动触发。在此处查看: `https://github.com///actions` ### 6. 验证发布制品 ``` gh attestation verify \ --repo / \ --predicate-type "https://slsa.dev/provenance/v1" ``` 完整的验证指南请参见 [SECURITY.md](SECURITY.md)。 ## 已锁定的 Actions 参考 所有 actions 都锁定到了完整的 40 字符 SHA(于 2026-06-18 解析): | Action | Tag | SHA | |---|---|---| | `actions/checkout` | v4.2.2 | `34e114876b0b11c390a56381ad16ebd13914f8d5` | | `actions/attest-build-provenance` | v2.4.0 | `e8998f949152b193b063cb0ec769d69d929409be` | | `actions/attest-sbom` | v2.3.0 | `bd218ad0dbcb3e146bd073d1d9c6d78e08aa8a0b` | | `anchore/sbom-action` | v0.24.0 | `e22c389904149dbc22b58101806040fa8d37a610` | | `softprops/action-gh-release` | v2.2.2 | `3bb12739c298aeb8a4eeaf626c5b8d85266b0e65` | | `actions/upload-artifact` | v4.6.2 | `ea165f8d65b6e75b540449e92b4886f43607fa02` | | `actions/download-artifact` | v4.3.0 | `d3f86a106a0bac45b974a628896c90dbdf5c8093` | ## 架构说明 ### 为什么需要失败阻断(fail-closed)验证? 一个提供证明但不进行验证的构建流水线会给人一种虚假的 安全感。能够在构建后篡改制品的攻击者(例如,被入侵的 制品存储库)将会生成一个其证明 验证会失败的制品。失败阻断的 `verify` 作业会在发布前捕获此问题。 ### 为什么需要 SHA 锁定的 action? 像 `actions/checkout@v4` 这样的 tag 是可变的 —— 仓库所有者可以随时将该 tag 移动到 不同的 commit 上。而像 `actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5` 这样的 SHA 是不可变的。 针对 CI/CD 工具的供应链攻击(例如,tj-actions/changed-files、 reviewdog)正是利用了可变的 action 引用。 ### 为什么需要 SLSA 来源? SLSA (Supply-chain Levels for Software Artifacts) 来源证明 以加密方式将制品与生成它的 workflow 运行绑定在一起, 包括源代码 commit SHA、workflow 文件路径和 runner 环境。这可以防止替换攻击,即不同的构建 产生出同名但内容不同的制品。 ### 没有 tag 的试运行(dry-run) ``` gh workflow run release.yml ``` 这将执行完整的 构建流程 → 证明 → 验证链条。`publish` 作业 会被跳过,因为 `startsWith(github.ref, 'refs/tags/')` 的结果为 false。 ## License Apache-2.0。参见 [LICENSE](LICENSE)。
标签:DevSecOps, GitHub Actions, SBOM, SLSA认证, 上游代理, 硬件无关, 自动笔记