Skip to content

Commit b2393c1

Browse files
feat: attest individual and multiplatform images
1 parent bddbe01 commit b2393c1

File tree

1 file changed

+61
-21
lines changed

1 file changed

+61
-21
lines changed
Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2-
name: Build
2+
name: CI
33

44
on:
55
push:
@@ -473,7 +473,8 @@ jobs:
473473
outputs:
474474
application_name: ${{ steps.variables.outputs.application_name }}
475475
description: ${{ steps.variables.outputs.description }}
476-
full_image_name: ${{ steps.variables.outputs.full_image_name }}
476+
full_image_name_remote_registry: ${{ steps.variables.outputs.full_image_name_remote_registry }}
477+
full_image_name_local_registry: ${{ steps.variables.outputs.full_image_name_local_registry }}
477478
registry: ${{ steps.variables.outputs.registry }}
478479
unique_tag: ${{ steps.variables.outputs.unique_tag }}
479480
runs-on: ${{ matrix.runs-on }}
@@ -585,10 +586,15 @@ jobs:
585586
registry=${registry,,}
586587
echo "registry=${registry}" >> ${GITHUB_OUTPUT}
587588
588-
# The full image name, which is the registry, the owner and the repo name
589+
# The final full image name, which is the registry, the owner and the repo name
589590
image_name=${{ env.IMAGE_NAME }}
590591
image_name=${image_name,,}
591-
echo "full_image_name=${registry}/${image_name}" >> ${GITHUB_OUTPUT}
592+
echo "full_image_name_remote_registry=${registry}/${image_name}" >> ${GITHUB_OUTPUT}
593+
594+
# The local registry to which we'll push
595+
local_registry=localhost:5000
596+
local_registry=${local_registry,,}
597+
echo "full_image_name_local_registry=${local_registry}/${image_name}" >> ${GITHUB_OUTPUT}
592598
593599
# The application's description, from Cargo.toml
594600
description=$(cargo get package.description)
@@ -605,7 +611,7 @@ jobs:
605611
org.opencontainers.image.revision=${{ github.event.pull_request.base.sha }}-${{ github.event.pull_request.head.sha }}
606612
org.opencontainers.image.source=${{ github.event.pull_request.html_url }}
607613
org.opencontainers.image.version=pr-${{ github.event.number }}
608-
images: ${{ steps.variables.outputs.full_image_name }}
614+
images: ${{ steps.variables.outputs.full_image_name_local_registry }}
609615
tags: |
610616
type=raw,value=${{ steps.variables.outputs.unique_tag_arch }}
611617
@@ -624,16 +630,14 @@ jobs:
624630

625631
- name: Build Docker image
626632
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
627-
env:
628-
BUILDX_NO_DEFAULT_ATTESTATIONS: true
629633
with:
630634
build-args: |
631635
APPLICATION_NAME=${{ steps.variables.outputs.application_name }}
632636
context: .
633637
# this container is THE PR's artifact, and we will re-tag it
634638
# once the PR has been accepted
635-
cache-from: type=registry,ref=${{ steps.variables.outputs.full_image_name }}:buildcache-${{ runner.arch }}-${{ steps.variables.outputs.application_name }}-${{ matrix.platform }}
636-
cache-to: type=registry,ref=${{ steps.variables.outputs.full_image_name }}:buildcache-${{ runner.arch }}-${{ steps.variables.outputs.application_name }}-${{ matrix.platform }},mode=max
639+
cache-from: type=registry,ref=${{ steps.variables.outputs.full_image_name_remote_registry }}:buildcache-${{ runner.arch }}-${{ steps.variables.outputs.application_name }}-${{ matrix.platform }}
640+
cache-to: type=registry,ref=${{ steps.variables.outputs.full_image_name_remote_registry }}:buildcache-${{ runner.arch }}-${{ steps.variables.outputs.application_name }}-${{ matrix.platform }},mode=max
637641
labels: ${{ steps.meta.outputs.labels }}
638642
outputs: type=oci,dest=/tmp/${{ steps.variables.outputs.unique_tag_arch }}.tar
639643
platforms: linux/${{ matrix.platform }}
@@ -652,7 +656,14 @@ jobs:
652656
docker-publish:
653657
name: Publish Docker container
654658
runs-on: ubuntu-latest
659+
services:
660+
registry:
661+
image: registry:3
662+
ports:
663+
- 5000:5000
655664
permissions:
665+
attestations: write
666+
id-token: write
656667
packages: write
657668
needs:
658669
- cargo-build
@@ -691,12 +702,12 @@ jobs:
691702
org.opencontainers.image.revision=${{ github.event.pull_request.base.sha }}-${{ github.event.pull_request.head.sha }}
692703
org.opencontainers.image.source=${{ github.event.pull_request.html_url }}
693704
org.opencontainers.image.version=pr-${{ github.event.number }}
694-
images: ${{ needs.docker-build.outputs.full_image_name }}
705+
images: ${{ needs.docker-build.outputs.full_image_name_local_registry }}
695706
tags: |
696707
type=raw,value=${{ needs.docker-build.outputs.unique_tag }}
697708
type=ref,event=pr,suffix=-latest
698709
699-
- name: Download artifact
710+
- name: Download artifacts
700711
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
701712
id: artifact
702713
with:
@@ -709,30 +720,32 @@ jobs:
709720
working-directory: ${{ steps.artifact.outputs.download-path }}
710721
run: |
711722
docker load --input ./${{ needs.docker-build.outputs.unique_tag }}-amd64.tar
712-
docker push ${{ needs.docker-build.outputs.full_image_name }}:${{ needs.docker-build.outputs.unique_tag }}-amd64
723+
echo "Pushing amd64:"
724+
docker push ${{ needs.docker-build.outputs.full_image_name_local_registry }}:${{ needs.docker-build.outputs.unique_tag }}-amd64
713725
714726
docker load --input ./${{ needs.docker-build.outputs.unique_tag }}-arm64.tar
715-
docker push ${{ needs.docker-build.outputs.full_image_name }}:${{ needs.docker-build.outputs.unique_tag }}-arm64
727+
echo "Pushing arm64:"
728+
docker push ${{ needs.docker-build.outputs.full_image_name_local_registry }}:${{ needs.docker-build.outputs.unique_tag }}-arm64
716729
717730
- name: Create multiplatform image
718731
shell: bash
719732
run: |
720-
new_labels=()
721-
while IFS= read -r label; do
722-
new_labels+=(--annotation)
723-
new_labels+=("index:${label}")
724-
done <<< "${{ steps.meta.outputs.labels }}"
725-
726733
new_tags=()
727734
while IFS= read -r tag; do
728735
new_tags+=(--tag)
729736
new_tags+=(${tag})
730737
done <<< "${{ steps.meta.outputs.tags }}"
731738
739+
new_labels=()
740+
while IFS= read -r label; do
741+
new_labels+=(--annotation)
742+
new_labels+=("index:${label}")
743+
done <<< "${{ steps.meta.outputs.labels }}"
744+
732745
# merge the amd64 and arm64 containers in a new multiplatform one
733746
docker buildx imagetools create "${new_tags[@]}" "${new_labels[@]}" \
734-
${{ needs.docker-build.outputs.full_image_name }}:${{ needs.docker-build.outputs.unique_tag }}-amd64 \
735-
${{ needs.docker-build.outputs.full_image_name }}:${{ needs.docker-build.outputs.unique_tag }}-arm64
747+
${{ needs.docker-build.outputs.full_image_name_local_registry }}:${{ needs.docker-build.outputs.unique_tag }}-amd64 \
748+
${{ needs.docker-build.outputs.full_image_name_local_registry }}:${{ needs.docker-build.outputs.unique_tag }}-arm64
736749
737750
for new_tag in $(echo "${{ join(steps.meta.outputs.tags, ' ') }}"); do
738751
echo "${new_tag}:"
@@ -741,6 +754,33 @@ jobs:
741754
echo ""
742755
done
743756
757+
- name: Get digest of multiplatform image in our local registry
758+
shell: bash
759+
id: multiplatform_image
760+
run: |
761+
digest=$(docker buildx imagetools inspect ${{ needs.docker-build.outputs.full_image_name_local_registry }}:${{ needs.docker-build.outputs.unique_tag }} --format "{{json .}}" | jq --raw-output ".manifest.digest")
762+
763+
echo "digest=${digest}" >> ${GITHUB_OUTPUT}
764+
765+
- name: Publish to the actual repo
766+
shell: bash
767+
run: |
768+
docker buildx imagetools create \
769+
--tag ${{ needs.docker-build.outputs.full_image_name_remote_registry }}:${{ needs.docker-build.outputs.unique_tag }} \
770+
${{ needs.docker-build.outputs.full_image_name_local_registry }}:${{ needs.docker-build.outputs.unique_tag }}
771+
772+
# note that we use the digest of the local image
773+
# these digests don't change after pushing, but
774+
# since we deal with tags (mutable), and the way to get a digest is to use the tag, I prefer
775+
# sourcing the digest from the local registry we just spun up (trusted)
776+
- name: Generate artifact attestation
777+
uses: actions/attest-build-provenance@v2
778+
id: attestation
779+
with:
780+
subject-name: ${{ needs.docker-build.outputs.full_image_name_remote_registry }}
781+
subject-digest: ${{ steps.multiplatform_image.outputs.digest }}
782+
push-to-registry: true
783+
744784
all-done:
745785
name: All done
746786
# this is the job that should be marked as required on GitHub. It's the only one that'll reliably trigger

0 commit comments

Comments
 (0)