Skip to content

Add artifact attestations for GHCR CI images #2003

@maxpetrusenkoagent

Description

@maxpetrusenkoagent

Summary

GStack publishes/reuses GitHub Container Registry CI images, but the image-producing workflows do not generate GitHub artifact attestations. That leaves maintainers without a first-party provenance record tying ghcr.io/garrytan/gstack/ci:* images back to the workflow run, commit, and build inputs that produced them.

GitHub's artifact attestation flow is designed for this exact build-provenance gap: GitHub Actions can generate attestations for binaries and container images, and the action requires explicit OIDC/attestation permissions (id-token: write, attestations: write).

Repo-local evidence

  • origin/main:.github/workflows/ci-image.yml builds and pushes the reusable CI image:
    • packages: write at line 21
    • docker/build-push-action@v6 at line 34
    • push: true at line 38
    • tags ghcr.io/${{ github.repository }}/ci:latest and ghcr.io/${{ github.repository }}/ci:${{ github.sha }} at lines 40-41
  • origin/main:.github/workflows/evals.yml and origin/main:.github/workflows/evals-periodic.yml can also build/push the cached eval image when it is missing:
    • packages: write at line 21 in both workflows
    • docker/build-push-action@v6 at line 49 in both workflows
    • push: true at line 53 in both workflows
  • Repo grep found no artifact-attestation wiring in the current default branch:
    • git grep -n -E 'attest-build-provenance|artifact attestation|attestation|provenance|id-token: write|attestations: write' origin/main -- .github package.json bun.lock README.md CONTRIBUTING.md docs
    • Only unrelated design-doc uses of the word provenance were returned.
  • The existing security backlog already covers adjacent checks, not this one:

Expected impact

Suggested fix

Add artifact attestation to image-producing workflows, starting with .github/workflows/ci-image.yml and then mirroring into the on-demand image build path in evals.yml / evals-periodic.yml if maintainers want those images attested too.

Concrete shape:

  1. Add least-privilege attestation permissions to the image build job:
    permissions:
      contents: read
      packages: write
      id-token: write
      attestations: write
  2. Give docker/build-push-action an id so the pushed digest can be referenced.
  3. Add actions/attest-build-provenance after the push, pinned to a full commit SHA in the same style requested by CI hardening: provider API keys exposed on pull_request (evals.yml) + third-party actions pinned to mutable tags #1948, with subject-name: ghcr.io/${{ github.repository }}/ci and subject-digest from the build step.
  4. Keep it non-blocking only if the repository plan/permissions do not support attestations yet; otherwise fail the image build if provenance generation fails.

Duplicate check performed

Commands/files inspected

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions