Skip to content

task: Add SLSA build provenance attestations to all artifact pipelines #229

Description

@nexus49

Overview

SLSA build provenance is a verifiable attestation that records how, where, and from what source a software artifact was built. It proves that a given image or chart was built from the claimed source, on the claimed platform, via the claimed workflow. OpenSSF Scorecard checks for this under the Signed-Releases and Token-Permissions criteria.

Related: #227 (OpenSSF Scorecard)

Current State

Artifact Type Signing Build Provenance
Docker images (job-docker-build-push.yml) Cosign ✅ ❌ Not implemented
Helm charts (job-release-chart.yml) ❌ Not implemented
OCM components (job-image-ocm.yml, job-chart-ocm.yml) OCM signing ✅ ❌ Not implemented
Custom images (build-ocmbuilder.yml) attest-build-provenance@v4
NPM packages (job-node-publish.yml) npm publish --provenance

Only custom-images/build-ocmbuilder.yml currently produces GitHub-native build provenance. The main shared Docker build workflow and Helm chart release workflow do not.

What Needs to Change

1. Add attestation to job-docker-build-push.yml

This is the highest-impact change — all operator/service images flow through this reusable workflow.

Required permission additions:

permissions:
  contents: write
  packages: write
  id-token: write
  attestations: write  # ← NEW

Add after the cosign signing step:

      - name: Attest build provenance
        if: ${{ (github.head_ref || github.ref) == format('refs/heads/{0}',inputs.release_branch) }}
        uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4
        with:
          subject-name: ${{ inputs.imageTagName }}
          subject-digest: ${{ steps.build.outputs.digest }}
          push-to-registry: true

Reference implementation: custom-images/.github/workflows/build-ocmbuilder.yml (lines 76–81) already does this.

2. Add attestation to job-release-chart.yml

Helm charts pushed as OCI artifacts can also receive provenance attestations. This requires a different approach since bsord/helm-push doesn't output a digest. Options:

  • Option A: After pushing, resolve the chart digest via helm pull + crane digest, then attest.
  • Option B: Switch to helm push directly (outputs to stdout), capture the digest, then attest.

Example (Option A):

      - name: Get chart digest
        id: chart_digest
        run: |
          digest=$(crane digest oci://ghcr.io/${{ github.repository }}/<chart-name>:${{ steps.chart_version.outputs.version }})
          echo "digest=$digest" >> "$GITHUB_OUTPUT"

      - name: Attest chart provenance
        uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4
        with:
          subject-name: ghcr.io/${{ github.repository }}/<chart-name>
          subject-digest: ${{ steps.chart_digest.outputs.digest }}
          push-to-registry: true

3. Propagate attestations: write permission to caller workflows

All pipelines that call these reusable workflows need to add attestations: write to their permissions block. This affects every operator/service pipeline (security-operator, account-operator, platform-mesh-operator, extension-manager-operator, etc.).

Example change in caller pipelines:

permissions:
  contents: write
  id-token: write
  issues: write
  packages: write
  pull-requests: write
  attestations: write  # ← NEW

Verification

After implementation, verify attestations with:

# Verify image attestation
gh attestation verify oci://ghcr.io/platform-mesh/<repo>/<image>:<tag> --owner platform-mesh

# Verify chart attestation
gh attestation verify oci://ghcr.io/platform-mesh/<repo>/<chart>:<version> --owner platform-mesh

Scope

  • Add attest-build-provenance to job-docker-build-push.yml
  • Add attestations: write to all caller pipelines
  • Add provenance to job-release-chart.yml (including CRD charts)
  • Add provenance to upstream-images workflows (Keycloak, PostgreSQL)
  • Verify attestations on at least one image and one chart
  • Document verification commands in the handbook

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Blocked/Waiting
Status
Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions