From b9e6b90eeda4f01e7b6314cbcbc9beaccdeb78ce Mon Sep 17 00:00:00 2001 From: Andy Waller <76787794+AndyW22@users.noreply.github.com> Date: Tue, 15 Sep 2026 15:51:41 +0200 Subject: [PATCH 1/3] publish to VCR on merge --- .github/workflows/publish-images.yml | 93 ++++++++++++++++++++++++++++ .github/workflows/publish.yml | 4 +- images/docker-bake.hcl | 32 +++++++--- 3 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/publish-images.yml diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml new file mode 100644 index 00000000..e92b5132 --- /dev/null +++ b/.github/workflows/publish-images.yml @@ -0,0 +1,93 @@ +name: Publish Images to VCR + +on: + workflow_dispatch: + push: + branches: [main] + paths: + - images/** + - .github/workflows/publish-images.yml + +permissions: + contents: read + +concurrency: + group: publish-images-vcr + cancel-in-progress: false + +jobs: + prepare: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.images.outputs.matrix }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Generate image matrix + id: images + uses: docker/bake-action/subaction/matrix@v7 + with: + workdir: images + target: default + + publish: + name: Publish ${{ matrix.target }} + needs: prepare + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: read + id-token: write + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(needs.prepare.outputs.matrix) }} + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to VCR with OIDC + uses: vercel/vcr-action/login@v1 + with: + team: ${{ vars.VERCEL_TEAM_ID }} + + - name: Build and push staging tags + id: bake + uses: docker/bake-action@v7 + with: + source: images + targets: ${{ matrix.target }} + vars: | + TAG_SUFFIX=-staging + PUSH=true + + - name: Select a staging tag for this image + id: staging + env: + STAGING_IMAGES: ${{ fromJSON(steps.bake.outputs.metadata)[matrix.target]['image.name'] }} + run: echo "image=${STAGING_IMAGES%%,*}" >> "$GITHUB_OUTPUT" + + - name: Wait for image optimization + id: optimized + uses: vercel/vcr-action/wait-for-optimized-image@v1 + timeout-minutes: 11 + with: + image: ${{ steps.staging.outputs.image }} + timeout-seconds: 600 + + - name: Promote the optimized image to its final tags + env: + STAGING_IMAGES: ${{ fromJSON(steps.bake.outputs.metadata)[matrix.target]['image.name'] }} + DIGEST: ${{ steps.optimized.outputs.digest }} + run: | + IFS=, read -r -a images <<< "$STAGING_IMAGES" + for image in "${images[@]}"; do + docker buildx imagetools create \ + --prefer-index=false \ + --tag "${image%-staging}" \ + "${image%:*}@$DIGEST" + done diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 69b89af0..7c15b46b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -51,6 +51,8 @@ jobs: with: source: images targets: ${{ matrix.target }} + push: false + vars: PUSH=false publish: @@ -101,4 +103,4 @@ jobs: permissions: contents: read steps: - - run: echo "Done" \ No newline at end of file + - run: echo "Done" diff --git a/images/docker-bake.hcl b/images/docker-bake.hcl index 9050463d..de8195fa 100644 --- a/images/docker-bake.hcl +++ b/images/docker-bake.hcl @@ -2,6 +2,14 @@ variable "REGISTRY" { default = "vcr.vercel.com/vercel/sandbox" } +variable "TAG_SUFFIX" { + default = "" +} + +variable "PUSH" { + default = false +} + group "default" { targets = ["runtimes", "vmi"] } @@ -16,15 +24,19 @@ group "vmi" { target "_common" { platforms = ["linux/amd64"] + attest = [ + "type=provenance,disabled=true", + "type=sbom,disabled=true" + ] output = [ - "type=image,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true" + "type=image,push=${PUSH},oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true" ] } target "ubuntu" { inherits = ["_common"] context = "ubuntu" - tags = ["${REGISTRY}/ubuntu:latest"] + tags = ["${REGISTRY}/ubuntu:latest${TAG_SUFFIX}"] } target "node" { @@ -49,8 +61,8 @@ target "node" { inherits = ["_common"] context = "node" tags = [ - "${REGISTRY}/node:${node.major}", - "${REGISTRY}/node:${node.version}", + "${REGISTRY}/node:${node.major}${TAG_SUFFIX}", + "${REGISTRY}/node:${node.version}${TAG_SUFFIX}", ] contexts = { @@ -65,7 +77,7 @@ target "node" { target "python" { inherits = ["_common"] context = "python" - tags = ["${REGISTRY}/python:3.14"] + tags = ["${REGISTRY}/python:3.14${TAG_SUFFIX}"] contexts = { base = "target:ubuntu" @@ -79,7 +91,7 @@ target "python" { target "universal" { inherits = ["_common"] context = "universal" - tags = ["${REGISTRY}/universal:latest"] + tags = ["${REGISTRY}/universal:latest${TAG_SUFFIX}"] contexts = { base = "target:ubuntu" @@ -94,7 +106,7 @@ target "universal" { target "arch" { inherits = ["_common"] context = "arch" - tags = ["${REGISTRY}/arch:latest"] + tags = ["${REGISTRY}/arch:latest${TAG_SUFFIX}"] } target "al-builder-base" { @@ -138,8 +150,8 @@ target "al-node" { context = "al-node" dockerfile = "Dockerfile" tags = [ - "${REGISTRY}/node:al-${node.major}", - "${REGISTRY}/node:al-${node.version}", + "${REGISTRY}/node:al-${node.major}${TAG_SUFFIX}", + "${REGISTRY}/node:al-${node.version}${TAG_SUFFIX}", ] contexts = { @@ -157,7 +169,7 @@ target "al-python" { inherits = ["_common"] context = "al-python" dockerfile = "Dockerfile" - tags = ["${REGISTRY}/python:al-3.13.1"] + tags = ["${REGISTRY}/python:al-3.13.1${TAG_SUFFIX}"] contexts = { builder-base = "target:al-builder-base" From 1b2dd9d3e569bef133bc75ec5472b022fe064aa1 Mon Sep 17 00:00:00 2001 From: Andy Waller <76787794+AndyW22@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:09:16 +0200 Subject: [PATCH 2/3] only target main --- .github/workflows/publish-images.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml index e92b5132..0483475c 100644 --- a/.github/workflows/publish-images.yml +++ b/.github/workflows/publish-images.yml @@ -17,6 +17,7 @@ concurrency: jobs: prepare: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest outputs: matrix: ${{ steps.images.outputs.matrix }} @@ -33,6 +34,7 @@ jobs: publish: name: Publish ${{ matrix.target }} + if: github.ref == 'refs/heads/main' needs: prepare runs-on: ubuntu-latest timeout-minutes: 60 From c8cfc1ea89dafaedcea2118f6dcaaa6c1a5d2b90 Mon Sep 17 00:00:00 2001 From: Andy Waller <76787794+AndyW22@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:44:54 +0200 Subject: [PATCH 3/3] update staging suffix to use github run id --- .github/workflows/publish-images.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml index 0483475c..69e65bf7 100644 --- a/.github/workflows/publish-images.yml +++ b/.github/workflows/publish-images.yml @@ -38,6 +38,8 @@ jobs: needs: prepare runs-on: ubuntu-latest timeout-minutes: 60 + env: + STAGING_SUFFIX: -staging-${{ github.run_id }} permissions: contents: read id-token: write @@ -64,7 +66,7 @@ jobs: source: images targets: ${{ matrix.target }} vars: | - TAG_SUFFIX=-staging + TAG_SUFFIX=${{ env.STAGING_SUFFIX }} PUSH=true - name: Select a staging tag for this image @@ -90,6 +92,6 @@ jobs: for image in "${images[@]}"; do docker buildx imagetools create \ --prefer-index=false \ - --tag "${image%-staging}" \ + --tag "${image%"$STAGING_SUFFIX"}" \ "${image%:*}@$DIGEST" done