Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion .github/workflows/buildah.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,66 @@ jobs:
tags: latest ${{ github.sha }}
registry: ghcr.io/makeitworkcloud
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ secrets.GITHUB_TOKEN }}

attest:
name: attest ${{ matrix.image }}
permissions:
contents: read
packages: write
attestations: write
artifact-metadata: write
id-token: write
needs: [build, detect]
if: >-
needs.build.result == 'success' &&
((github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'workflow_dispatch' && inputs.mode == 'build & push'))
runs-on: ubuntu-latest
strategy:
matrix:
image: ${{ fromJson(needs.detect.outputs.images) }}

steps:
- name: Install skopeo
run: |
sudo apt-get update
sudo apt-get install -y skopeo

- name: Resolve published image digest
id: image
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
image_name="ghcr.io/makeitworkcloud/${{ matrix.image }}"
echo "$GITHUB_TOKEN" | skopeo login ghcr.io --username "${{ github.actor }}" --password-stdin
digest="$(skopeo inspect --format '{{.Digest}}' "docker://${image_name}:${GITHUB_SHA}")"
printf 'name=%s\n' "$image_name" >> "$GITHUB_OUTPUT"
printf 'digest=%s\n' "$digest" >> "$GITHUB_OUTPUT"

- name: Generate SBOM
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0
with:
image: ${{ steps.image.outputs.name }}@${{ steps.image.outputs.digest }}
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
output-file: ${{ matrix.image }}.spdx.json
format: spdx-json
syft-version: v1.51.1
upload-artifact: false

- name: Attest build provenance
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
with:
subject-name: ${{ steps.image.outputs.name }}
subject-digest: ${{ steps.image.outputs.digest }}
push-to-registry: true

- name: Attest SBOM
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
with:
subject-name: ${{ steps.image.outputs.name }}
subject-digest: ${{ steps.image.outputs.digest }}
sbom-path: ${{ matrix.image }}.spdx.json
push-to-registry: true
6 changes: 5 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ production publication.

## Build Workflow (`buildah.yml`)

Single workflow, three jobs, all on `ubuntu-latest`.
Single workflow, four jobs, all on `ubuntu-latest`.

1. **checks** — runs pre-commit, including full-tree Gitleaks scanning,
hadolint, and actionlint, for every `main` push, pull request, and manual
Expand All @@ -39,6 +39,10 @@ Single workflow, three jobs, all on `ubuntu-latest`.
- on `push` to `main`, or `workflow_dispatch` with `mode=build & push`, push to GHCR with tags `latest` and `${{ github.sha }}`

PRs and `workflow_dispatch` with `mode=build` build but do not push.
4. **attest** — after an image is pushed, resolve its immutable GHCR digest,
generate an SPDX SBOM with Syft, and publish both SBOM and build-provenance
attestations. This job runs only for `main` pushes and explicit publishing
dispatches; it must not run for PR builds.

## Makefile

Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ Container image monorepo. Each subdirectory containing a `Containerfile` is buil
## How It Works

```
push to main ─▶ detect changed images ─▶ pre-commit + hadolint ─▶ buildah build ─▶ push to GHCR
push to main ─▶ detect changed images ─▶ pre-commit + hadolint ─▶ buildah build ─▶ push to GHCR ─▶ attest digest
```

`workflow_dispatch` accepts an optional `image` input to rebuild a single image; with no input it builds all images. Manual dispatch defaults to **build & push**; select **build** for a non-publishing validation run.

The detect step uses the `Makefile` (`make changed-images` / `make list-images-json`) to enumerate directories that contain a `Containerfile`.

## Supply-chain attestations

After a publishing build, CI resolves the immutable digest behind the SHA tag,
generates an SPDX JSON SBOM from that digest, and attaches both the SBOM and
build provenance to the GHCR image. PR and non-publishing manual builds do not
publish images or attestations.

## Adding an Image

1. Create `<name>/Containerfile`
Expand Down
Loading