Skip to content

fix(ci): restore SLSA Build L3 image provenance (reusable workflow)#1558

Merged
mchmarny merged 1 commit into
mainfrom
fix/slsa-l3-reusable-attest
Jun 30, 2026
Merged

fix(ci): restore SLSA Build L3 image provenance (reusable workflow)#1558
mchmarny merged 1 commit into
mainfrom
fix/slsa-l3-reusable-attest

Conversation

@mchmarny

Copy link
Copy Markdown
Member

Summary

Restore SLSA Build Level 3 for AICR container-image provenance by generating the attestation from a dedicated reusable workflow, and re-assert the (previously qualified) L3 wording across the docs.

Motivation / Context

Image attestations regressed to Build L2 when the attest step was inlined into the on-tag.yaml release job. GitHub issues Build L2 for attestations generated in a caller workflow and Build L3 only when they are generated from a reusable workflow (the isolated, vetted builder identity). This was diagnosed on #1536: the v0.16.0 ghcr.io/nvidia/aicr provenance has builder.id = .../on-tag.yaml (the caller), and gh attestation verify --signer-workflow .../build.yaml fails — both confirming L2.

Fixes: #1536
Related: #1547 (qualified the L3 docs to "build level under review" pending this fix)

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Documentation update
  • Build/CI/tooling

Component(s) Affected

  • Docs/examples (docs/, examples/)
  • Other: release CI (.github/workflows/on-tag.yaml, new .github/workflows/attest-images.yaml)

Implementation Notes

  • New reusable workflow .github/workflows/attest-images.yaml (on: workflow_call, input tag) holds the image-attestation steps. on-tag.yaml's attest job now calls it via uses:. The provenance builder identity becomes the reusable workflow, so gh attestation verify --signer-workflow NVIDIA/aicr/.github/workflows/attest-images.yaml is the L3 acceptance test.
  • Because sbom-and-attest (image SBOM Cosign attestation and attest-build-provenance) runs inside the reusable workflow, both the image build-provenance signer and the image SBOM Cosign --certificate-identity-regexp move to attest-images.yaml. All image-verification references across SECURITY.md, RELEASING.md, docs/integrator/supply-chain-verification.md, and the provenance demos were repointed accordingly.
  • Binary attestations are unchanged (Build L2, cosign attest-blob signed from on-tag.yaml). Their verification references (cli-reference.md, bundle-attestation.*, and the aicr verify-blob-attestation) intentionally still pin on-tag.yaml. The SECURITY.md table reflects this split: images = Build Level 3, binaries = Build Provenance v1.
  • Added a "Why image provenance is Build Level 3" explanation to SECURITY.md.

Testing

actionlint .github/workflows/attest-images.yaml .github/workflows/on-tag.yaml   # exit 0
yamllint   .github/workflows/attest-images.yaml .github/workflows/on-tag.yaml   # exit 0
bash -n    demos/provenance-demo.sh                                             # syntax OK

No Go sources changed. The end-to-end L3 outcome can only be confirmed by a tagged release (attestations are produced on tag); the documented acceptance test is:

gh attestation verify "oci://ghcr.io/nvidia/aicr@<digest>" --repo NVIDIA/aicr \
  --signer-workflow NVIDIA/aicr/.github/workflows/attest-images.yaml

Risk Assessment

  • Medium — Touches the release pipeline; fully verifiable only at the next tag.

Rollout notes: The restored L3 wording is accurate as of the first release built with this workflow; v0.16.0 and earlier image attestations remain L2 (signed by on-tag.yaml) and will not verify against the new --signer-workflow. No consumer migration required.

Checklist

  • Tests pass locally (make test with -race) — N/A (no Go changes); workflows lint clean
  • Linter passes (make lint) — actionlint + yamllint clean on changed workflows
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality — N/A (CI workflow; verified by gh attestation verify at release)
  • I updated docs if user-facing behavior changed
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S)

Image attestations regressed to Build L2 when the attest step was inlined
into the on-tag.yaml release job. GitHub issues Build L2 for attestations
generated in a caller workflow and Build L3 only when they are generated
from a reusable workflow.

Move image attestation into a reusable workflow (attest-images.yaml) called
by on-tag.yaml, so the provenance builder identity becomes the reusable
workflow — verifiable with 'gh attestation verify --signer-workflow'.
Restore the L3 wording across SECURITY.md, README, docs, and RELEASING
(qualified to 'under review' in #1547), add a 'why it is L3' explanation to
SECURITY.md, and repoint every image verification reference (signer-workflow
and Cosign identity) to attest-images.yaml. Binary attestations are
unchanged (Build L2, signed from on-tag.yaml).

Fixes #1536

Signed-off-by: Mark Chmarny <[email protected]>
@github-actions

Copy link
Copy Markdown
Contributor

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A new reusable GitHub Actions workflow attest-images.yaml is introduced to generate SLSA/SBOM attestations for all container images (aicr, aicrd, validator variants, and the gate image). The attest job in on-tag.yaml is refactored to invoke this reusable workflow instead of running attestation steps inline. All documentation, demo scripts, and admission-policy examples (SECURITY.md, RELEASING.md, docs/integrator/supply-chain-verification.md, demos/provenance.md, etc.) are updated to reference attest-images.yaml as the signer workflow and to assert SLSA Build Level 3 image provenance, removing previous "level under review" wording.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #1536 (Reconcile SLSA Build Level claim): This PR directly resolves the issue by moving image attestation into a dedicated reusable workflow (attest-images.yaml), satisfying the GitHub SLSA Build Level 3 isolation requirement, and updating all documentation to assert Level 3 accordingly.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main change: restoring SLSA L3 image provenance via a reusable workflow.
Description check ✅ Passed The description matches the PR scope, explaining the provenance fix and the accompanying documentation updates.
Linked Issues check ✅ Passed The PR satisfies #1536 by moving image attestation into a reusable workflow, which addresses the L3 isolation requirement.
Out of Scope Changes check ✅ Passed The changes stay within scope, covering the workflow refactor plus the related provenance documentation and demo updates.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/slsa-l3-reusable-attest

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/attest-images.yaml:
- Around line 51-55: The workflow permissions block needs inline justification
for each elevated scope so the image attestation setup is auditable. Update the
permissions section in the attest-images workflow to add brief rationale
comments beside `packages: write`, `id-token: write`, and `attestations: write`,
and keep the comments tied to the attestation/release steps they support. Use
the workflow’s permissions block as the reference point so it’s clear why these
non-read-only permissions are required.

In @.github/workflows/on-tag.yaml:
- Around line 453-457: The workflow permissions block for the release job
includes sensitive token scopes without explanation; add inline rationale next
to the permissions in on-tag.yaml so future maintainers understand why contents:
read, packages: write, id-token: write, and attestations: write are required and
keep least privilege intact. Use the existing permissions section in the release
workflow to document the purpose of these scopes directly where they are
declared.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 2cf0fcd8-d5ab-4abf-b29a-34d2dd33ad64

📥 Commits

Reviewing files that changed from the base of the PR and between 0479638 and 88984d1.

📒 Files selected for processing (11)
  • .github/workflows/attest-images.yaml
  • .github/workflows/on-tag.yaml
  • README.md
  • RELEASING.md
  • SECURITY.md
  • demos/provenance-demo-slides.html
  • demos/provenance-demo.sh
  • demos/provenance.md
  • docs/README.md
  • docs/integrator/supply-chain-verification.md
  • docs/user/installation.md

Comment thread .github/workflows/attest-images.yaml
Comment thread .github/workflows/on-tag.yaml
@mchmarny mchmarny enabled auto-merge (squash) June 30, 2026 12:50
@mchmarny mchmarny merged commit 6205cf0 into main Jun 30, 2026
35 of 36 checks passed
@mchmarny mchmarny deleted the fix/slsa-l3-reusable-attest branch June 30, 2026 12:54
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report ✅

Metric Value
Coverage 78.0%
Threshold 75%
Status Pass
Coverage Badge
![Coverage](https://img.shields.io/badge/coverage-78.0%25-green)

No Go source files changed in this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci area/docs size/L theme/supply-chain SLSA, SBOM, Sigstore, and provenance verification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reconcile SLSA Build Level claim (docs say L3; build architecture looks like L2)

2 participants