From 735835dbe89936c1d15d527e960fd21c5c62c703 Mon Sep 17 00:00:00 2001 From: pat-s Date: Sat, 18 Apr 2026 10:27:12 +0200 Subject: [PATCH 01/10] add alpine image --- .github/workflows/build-docker.yml | 55 +++++++++++++++++++++--------- Dockerfile | 14 +++++++- docs/integrations.md | 21 +++++++++--- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 2f70398af..55c0d94ea 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -15,6 +15,7 @@ on: env: PREK_BASE_IMG: ghcr.io/${{ github.repository_owner }}/prek + PREK_ALPINE_IMG: ghcr.io/${{ github.repository_owner }}/prek-alpine permissions: contents: read @@ -42,7 +43,7 @@ jobs: fi docker-build: - name: Build Docker image ghcr.io/j178/prek for ${{ matrix.platform }} + name: Build Docker image (${{ matrix.image }}, ${{ matrix.platform }}) needs: plan runs-on: ubuntu-latest environment: @@ -53,6 +54,9 @@ jobs: platform: - linux/amd64 - linux/arm64 + image: + - minimal + - alpine steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: @@ -82,13 +86,21 @@ jobs: echo "Releasing ${version}" fi + - name: Set image name + run: | + if [ "${{ matrix.image }}" = "alpine" ]; then + echo "IMAGE_NAME=${PREK_ALPINE_IMG}" >> "$GITHUB_ENV" + else + echo "IMAGE_NAME=${PREK_BASE_IMG}" >> "$GITHUB_ENV" + fi + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 env: DOCKER_METADATA_ANNOTATIONS_LEVELS: index with: - images: ${{ env.PREK_BASE_IMG }} + images: ${{ env.IMAGE_NAME }} # Defining this makes sure the org.opencontainers.image.version OCI label becomes the actual release version and not the branch name tags: | type=raw,value=dry-run,enable=${{ needs.plan.outputs.publish != 'true' }} @@ -106,10 +118,11 @@ jobs: with: context: . platforms: ${{ matrix.platform }} - cache-from: type=gha,scope=prek-${{ env.PLATFORM_TUPLE }} - cache-to: type=gha,mode=min,scope=prek-${{ env.PLATFORM_TUPLE }} + target: ${{ matrix.image }} + cache-from: type=gha,scope=prek-${{ matrix.image }}-${{ env.PLATFORM_TUPLE }} + cache-to: type=gha,mode=min,scope=prek-${{ matrix.image }}-${{ env.PLATFORM_TUPLE }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=${{ env.PREK_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ needs.plan.outputs.publish == 'true' }} + outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ needs.plan.outputs.publish == 'true' }} - name: Export digests env: @@ -121,13 +134,13 @@ jobs: - name: Upload digests uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: digests-${{ env.PLATFORM_TUPLE }} + name: digests-${{ matrix.image }}-${{ env.PLATFORM_TUPLE }} path: /tmp/digests/* if-no-files-found: error retention-days: 1 docker-publish: - name: Publish Docker image (ghcr.io/j178/prek) + name: Publish Docker image (${{ matrix.image }}) runs-on: ubuntu-latest environment: name: release @@ -140,12 +153,26 @@ jobs: id-token: write attestations: write if: ${{ needs.plan.outputs.publish == 'true' }} + strategy: + fail-fast: false + matrix: + image: + - minimal + - alpine steps: + - name: Set image name + run: | + if [ "${{ matrix.image }}" = "alpine" ]; then + echo "IMAGE_NAME=${PREK_ALPINE_IMG}" >> "$GITHUB_ENV" + else + echo "IMAGE_NAME=${PREK_BASE_IMG}" >> "$GITHUB_ENV" + fi + - name: Download digests uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: /tmp/digests - pattern: digests-* + pattern: digests-${{ matrix.image }}-* merge-multiple: true - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 @@ -156,7 +183,7 @@ jobs: env: DOCKER_METADATA_ANNOTATIONS_LEVELS: index with: - images: ${{ env.PREK_BASE_IMG }} + images: ${{ env.IMAGE_NAME }} # Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version tags: | type=raw,value=${{ fromJson(inputs.plan).announcement_tag }} @@ -171,9 +198,6 @@ jobs: # Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/ - name: Create manifest list and push working-directory: /tmp/digests - # The jq command expands the docker/metadata json "tags" array entry to `-t tag1 -t tag2 ...` for each tag in the array - # The printf will expand the base image with the `@sha256: ...` for each sha256 in the directory - # The final command becomes `docker buildx imagetools create -t tag1 -t tag2 ... @sha256: @sha256: ...` run: | # shellcheck disable=SC2046 readarray -t lines <<< "$DOCKER_METADATA_OUTPUT_ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done @@ -181,17 +205,16 @@ jobs: docker buildx imagetools create \ "${annotations[@]}" \ $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf "${PREK_BASE_IMG}@sha256:%s " *) + $(printf "${IMAGE_NAME}@sha256:%s " *) - name: Export manifest digest id: manifest-digest env: - IMAGE: ${{ env.PREK_BASE_IMG }} VERSION: ${{ steps.meta.outputs.version }} run: | digest="$( docker buildx imagetools inspect \ - "${IMAGE}:${VERSION}" \ + "${IMAGE_NAME}:${VERSION}" \ --format '{{json .Manifest}}' \ | jq -r '.digest' )" @@ -200,5 +223,5 @@ jobs: - name: Generate artifact attestation uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1 with: - subject-name: ${{ env.PREK_BASE_IMG }} + subject-name: ${{ env.IMAGE_NAME }} subject-digest: ${{ steps.manifest-digest.outputs.digest }} diff --git a/Dockerfile b/Dockerfile index 06efff1c6..4814527d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,7 +43,19 @@ RUN cp target/$(cat rust_target.txt)/dist/prek /prek # TODO: Optimize binary size, with a version that also works when cross compiling # RUN strip --strip-all /prek -FROM scratch +FROM scratch AS minimal COPY --from=build /prek / WORKDIR /io ENTRYPOINT ["/prek"] + +FROM alpine:3.23 AS alpine +RUN apk add --no-cache \ + ca-certificates \ + git \ + nodejs \ + npm \ + python3 \ + py3-pip +COPY --from=build /prek /usr/local/bin/prek +WORKDIR /io +ENTRYPOINT ["prek"] diff --git a/docs/integrations.md b/docs/integrations.md index 26ecc59fc..7880a7eb0 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -4,11 +4,16 @@ This page documents common ways to integrate prek into CI and container workflow ## Docker -prek is published as a distroless container image at: +prek publishes two container images: -- `ghcr.io/j178/prek` +| Image | Base | Description | +|-------|------|-------------| +| `ghcr.io/j178/prek` | `scratch` | Minimal distroless image containing only the prek binary | +| `ghcr.io/j178/prek-alpine` | `alpine:3.23` | Alpine image with common hook dependencies pre-installed | -The image is based on `scratch` (no shell, no package manager). It contains the prek binary at `/prek`. +### Minimal (scratch) + +The default image is based on `scratch` (no shell, no package manager). It contains the prek binary at `/prek`. A common pattern is to copy the binary into your own image: @@ -23,9 +28,17 @@ If you prefer, you can also run the distroless image directly: docker run --rm ghcr.io/j178/prek:v0.4.8 --version ``` +### Alpine + +The Alpine image includes `git`, `nodejs`, `npm`, `python3`, and `py3-pip`, covering the most common hook runtimes. + +```bash +docker run --rm ghcr.io/j178/prek-alpine:v0.3.9 --version +``` + ### Verifying Images -Docker images are signed with +Both images are signed with [GitHub Attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) to verify they were built by official prek workflows. Verify using the [GitHub CLI](https://cli.github.com/): From d481755d7638ea82933c8a59e7ab0fbf6e4aa96d Mon Sep 17 00:00:00 2001 From: pat-s Date: Sat, 18 Apr 2026 10:32:05 +0200 Subject: [PATCH 02/10] lint --- docs/integrations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integrations.md b/docs/integrations.md index 7880a7eb0..f5d8a5ca6 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -7,7 +7,7 @@ This page documents common ways to integrate prek into CI and container workflow prek publishes two container images: | Image | Base | Description | -|-------|------|-------------| +| -- | -- | -- | | `ghcr.io/j178/prek` | `scratch` | Minimal distroless image containing only the prek binary | | `ghcr.io/j178/prek-alpine` | `alpine:3.23` | Alpine image with common hook dependencies pre-installed | From cc275c0df5a1a65c2b3b855362f5525348b5fe5e Mon Sep 17 00:00:00 2001 From: pat-s Date: Sat, 18 Apr 2026 10:34:12 +0200 Subject: [PATCH 03/10] chore: address review --- .github/workflows/build-docker.yml | 27 +++++++-------------------- Dockerfile | 10 +++++----- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 55c0d94ea..12d7b01a4 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -86,21 +86,13 @@ jobs: echo "Releasing ${version}" fi - - name: Set image name - run: | - if [ "${{ matrix.image }}" = "alpine" ]; then - echo "IMAGE_NAME=${PREK_ALPINE_IMG}" >> "$GITHUB_ENV" - else - echo "IMAGE_NAME=${PREK_BASE_IMG}" >> "$GITHUB_ENV" - fi - - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 env: DOCKER_METADATA_ANNOTATIONS_LEVELS: index with: - images: ${{ env.IMAGE_NAME }} + images: ${{ matrix.image == 'alpine' && env.PREK_ALPINE_IMG || env.PREK_BASE_IMG }} # Defining this makes sure the org.opencontainers.image.version OCI label becomes the actual release version and not the branch name tags: | type=raw,value=dry-run,enable=${{ needs.plan.outputs.publish != 'true' }} @@ -122,7 +114,7 @@ jobs: cache-from: type=gha,scope=prek-${{ matrix.image }}-${{ env.PLATFORM_TUPLE }} cache-to: type=gha,mode=min,scope=prek-${{ matrix.image }}-${{ env.PLATFORM_TUPLE }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ needs.plan.outputs.publish == 'true' }} + outputs: type=image,name=${{ matrix.image == 'alpine' && env.PREK_ALPINE_IMG || env.PREK_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ needs.plan.outputs.publish == 'true' }} - name: Export digests env: @@ -160,14 +152,6 @@ jobs: - minimal - alpine steps: - - name: Set image name - run: | - if [ "${{ matrix.image }}" = "alpine" ]; then - echo "IMAGE_NAME=${PREK_ALPINE_IMG}" >> "$GITHUB_ENV" - else - echo "IMAGE_NAME=${PREK_BASE_IMG}" >> "$GITHUB_ENV" - fi - - name: Download digests uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -183,7 +167,7 @@ jobs: env: DOCKER_METADATA_ANNOTATIONS_LEVELS: index with: - images: ${{ env.IMAGE_NAME }} + images: ${{ matrix.image == 'alpine' && env.PREK_ALPINE_IMG || env.PREK_BASE_IMG }} # Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version tags: | type=raw,value=${{ fromJson(inputs.plan).announcement_tag }} @@ -198,6 +182,8 @@ jobs: # Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/ - name: Create manifest list and push working-directory: /tmp/digests + env: + IMAGE_NAME: ${{ matrix.image == 'alpine' && env.PREK_ALPINE_IMG || env.PREK_BASE_IMG }} run: | # shellcheck disable=SC2046 readarray -t lines <<< "$DOCKER_METADATA_OUTPUT_ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done @@ -210,6 +196,7 @@ jobs: - name: Export manifest digest id: manifest-digest env: + IMAGE_NAME: ${{ matrix.image == 'alpine' && env.PREK_ALPINE_IMG || env.PREK_BASE_IMG }} VERSION: ${{ steps.meta.outputs.version }} run: | digest="$( @@ -223,5 +210,5 @@ jobs: - name: Generate artifact attestation uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1 with: - subject-name: ${{ env.IMAGE_NAME }} + subject-name: ${{ matrix.image == 'alpine' && env.PREK_ALPINE_IMG || env.PREK_BASE_IMG }} subject-digest: ${{ steps.manifest-digest.outputs.digest }} diff --git a/Dockerfile b/Dockerfile index 4814527d6..d812cb4c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,11 +43,6 @@ RUN cp target/$(cat rust_target.txt)/dist/prek /prek # TODO: Optimize binary size, with a version that also works when cross compiling # RUN strip --strip-all /prek -FROM scratch AS minimal -COPY --from=build /prek / -WORKDIR /io -ENTRYPOINT ["/prek"] - FROM alpine:3.23 AS alpine RUN apk add --no-cache \ ca-certificates \ @@ -59,3 +54,8 @@ RUN apk add --no-cache \ COPY --from=build /prek /usr/local/bin/prek WORKDIR /io ENTRYPOINT ["prek"] + +FROM scratch AS minimal +COPY --from=build /prek / +WORKDIR /io +ENTRYPOINT ["/prek"] From 42539ef801102f5ca60559e349817b427038ff35 Mon Sep 17 00:00:00 2001 From: Patrick Schratz Date: Thu, 9 Jul 2026 11:20:11 +0200 Subject: [PATCH 04/10] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docs/integrations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integrations.md b/docs/integrations.md index f5d8a5ca6..b1ba2c59a 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -33,7 +33,7 @@ docker run --rm ghcr.io/j178/prek:v0.4.8 --version The Alpine image includes `git`, `nodejs`, `npm`, `python3`, and `py3-pip`, covering the most common hook runtimes. ```bash -docker run --rm ghcr.io/j178/prek-alpine:v0.3.9 --version +docker run --rm ghcr.io/j178/prek-alpine:v0.4.8 --version ``` ### Verifying Images From 5cabc06298d1f54faa5eb57d2d6234ea33252f16 Mon Sep 17 00:00:00 2001 From: Patrick Schratz Date: Thu, 9 Jul 2026 11:20:34 +0200 Subject: [PATCH 05/10] Update Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d812cb4c7..d6900beac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,7 +43,7 @@ RUN cp target/$(cat rust_target.txt)/dist/prek /prek # TODO: Optimize binary size, with a version that also works when cross compiling # RUN strip --strip-all /prek -FROM alpine:3.23 AS alpine +FROM alpine:3.24 AS alpine RUN apk add --no-cache \ ca-certificates \ git \ From 87ec28202dd772366713a6ea5502756f0180b87d Mon Sep 17 00:00:00 2001 From: Patrick Schratz Date: Thu, 9 Jul 2026 11:31:40 +0200 Subject: [PATCH 06/10] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docs/integrations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integrations.md b/docs/integrations.md index b1ba2c59a..ec187c45b 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -9,7 +9,7 @@ prek publishes two container images: | Image | Base | Description | | -- | -- | -- | | `ghcr.io/j178/prek` | `scratch` | Minimal distroless image containing only the prek binary | -| `ghcr.io/j178/prek-alpine` | `alpine:3.23` | Alpine image with common hook dependencies pre-installed | +| `ghcr.io/j178/prek-alpine` | `alpine:3.24` | Alpine image with common hook dependencies pre-installed | ### Minimal (scratch) From eee1f2e041893809661965f8673a3788a1723240 Mon Sep 17 00:00:00 2001 From: pat-s Date: Thu, 9 Jul 2026 09:32:49 +0000 Subject: [PATCH 07/10] fix(docker): use absolute path for alpine entrypoint --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d6900beac..17c62f870 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,7 +53,7 @@ RUN apk add --no-cache \ py3-pip COPY --from=build /prek /usr/local/bin/prek WORKDIR /io -ENTRYPOINT ["prek"] +ENTRYPOINT ["/usr/local/bin/prek"] FROM scratch AS minimal COPY --from=build /prek / From 233a2b871abe6536ef1af16196d9e9678f4bbf0a Mon Sep 17 00:00:00 2001 From: pat-s Date: Thu, 9 Jul 2026 09:38:01 +0000 Subject: [PATCH 08/10] feat(docker): add curl to alpine image --- Dockerfile | 1 + docs/integrations.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 17c62f870..5196692fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,6 +46,7 @@ RUN cp target/$(cat rust_target.txt)/dist/prek /prek FROM alpine:3.24 AS alpine RUN apk add --no-cache \ ca-certificates \ + curl \ git \ nodejs \ npm \ diff --git a/docs/integrations.md b/docs/integrations.md index ec187c45b..85c7ee868 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -30,7 +30,7 @@ docker run --rm ghcr.io/j178/prek:v0.4.8 --version ### Alpine -The Alpine image includes `git`, `nodejs`, `npm`, `python3`, and `py3-pip`, covering the most common hook runtimes. +The Alpine image includes `curl`, `git`, `nodejs`, `npm`, `python3`, and `py3-pip`, covering the most common hook runtimes. ```bash docker run --rm ghcr.io/j178/prek-alpine:v0.4.8 --version From 0457262a0d4f8e4c48797bee904b290bc400f2c0 Mon Sep 17 00:00:00 2001 From: pat-s Date: Thu, 9 Jul 2026 09:48:21 +0000 Subject: [PATCH 09/10] fix(docker): register QEMU for arm64 alpine build and fix verify example tag --- .github/workflows/build-docker.yml | 4 ++++ docs/integrations.md | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 12d7b01a4..689eb47e9 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -62,6 +62,10 @@ jobs: with: persist-credentials: false + # QEMU is required to run the target-arch `RUN` steps in the Alpine stage + # when cross-building linux/arm64 on an amd64 runner. + - uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 + - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 diff --git a/docs/integrations.md b/docs/integrations.md index 85c7ee868..6a0c15861 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -44,8 +44,8 @@ to verify they were built by official prek workflows. Verify using the [GitHub CLI](https://cli.github.com/): ```console -$ gh attestation verify --owner j178 oci://ghcr.io/j178/prek:latest -Loaded digest sha256:xxxx... for oci://ghcr.io/j178/prek:latest +$ gh attestation verify --owner j178 oci://ghcr.io/j178/prek:v0.4.8 +Loaded digest sha256:xxxx... for oci://ghcr.io/j178/prek:v0.4.8 Loaded 1 attestation from GitHub API ✓ Verification succeeded! From ac73e8d2aa84a6522767bc2d643d84ec0d033563 Mon Sep 17 00:00:00 2001 From: pat-s Date: Thu, 9 Jul 2026 14:22:12 +0000 Subject: [PATCH 10/10] fix(docker): gate QEMU setup on alpine leg and clarify image verification docs --- .github/workflows/build-docker.yml | 4 +++- docs/integrations.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 689eb47e9..92589552a 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -63,8 +63,10 @@ jobs: persist-credentials: false # QEMU is required to run the target-arch `RUN` steps in the Alpine stage - # when cross-building linux/arm64 on an amd64 runner. + # when cross-building linux/arm64 on an amd64 runner. The minimal (scratch) + # image only copies the cross-compiled binary, so it needs no emulation. - uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 + if: ${{ matrix.image == 'alpine' }} - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 diff --git a/docs/integrations.md b/docs/integrations.md index 6a0c15861..d05c90fad 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -40,7 +40,9 @@ docker run --rm ghcr.io/j178/prek-alpine:v0.4.8 --version Both images are signed with [GitHub Attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) -to verify they were built by official prek workflows. Verify using the +to verify they were built by official prek workflows. +Each image is verified separately; the example below verifies the minimal image, and the Alpine image is verified the same way by substituting `prek-alpine` for `prek`. +Verify using the [GitHub CLI](https://cli.github.com/): ```console