From 035e71010d54b3daa41652e4e62f690ffc2edd5e Mon Sep 17 00:00:00 2001 From: Saadi Myftija Date: Thu, 13 Aug 2026 18:22:50 +0200 Subject: [PATCH] feat(base-images): immutable per-publish image tags (#4607) Every publish now also pushes an immutable per-publish tag alongside the mutable one, named after the snapshot date and commit (e.g. `22-bookworm-20260812-45444a7`), so previously published digests stay tag-referenced after republishes. Shipped CLI releases pin those digests, so they must remain resolvable indefinitely. Merging triggers a republish; the fresh tag-protected digests will then be pinned by #4602 before it merges. --- .github/workflows/base-images.yml | 13 +++++++++++-- base-images/README.md | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/base-images.yml b/.github/workflows/base-images.yml index 13abecdad..2c23246de 100644 --- a/.github/workflows/base-images.yml +++ b/.github/workflows/base-images.yml @@ -39,6 +39,7 @@ jobs: build_packages: ${{ steps.config.outputs.build_packages }} suite: ${{ steps.config.outputs.suite }} snapshot: ${{ steps.config.outputs.snapshot }} + publish_id: ${{ steps.config.outputs.publish_id }} source_date_epoch: ${{ steps.config.outputs.source_date_epoch }} push: ${{ steps.config.outputs.push }} steps: @@ -52,6 +53,7 @@ jobs: SNAPSHOT_INPUT: ${{ inputs.debian_snapshot }} EVENT_NAME: ${{ github.event_name }} REF: ${{ github.ref }} + SHA: ${{ github.sha }} run: | PACKAGES="$(jq -er '.packages' base-images/images.json)" BUILD_PACKAGES="$(jq -er '.buildPackages' base-images/images.json)" @@ -89,6 +91,7 @@ jobs: echo "build_packages=$BUILD_PACKAGES" echo "suite=$SUITE" echo "snapshot=$SNAPSHOT" + echo "publish_id=${SNAPSHOT:0:8}-${SNAPSHOT:9:6}-${SHA:0:7}" echo "source_date_epoch=$EPOCH" echo "push=$PUSH" } >> "$GITHUB_OUTPUT" @@ -164,7 +167,11 @@ jobs: platforms: linux/amd64,linux/arm64 provenance: false outputs: type=image,push=true,rewrite-timestamp=true - tags: triggerdotdev/${{ matrix.image.repo }}:${{ matrix.image.tag }} + # The dated tag is immutable and keeps every published digest + # tag-referenced forever; shipped CLI releases pin these digests + tags: | + triggerdotdev/${{ matrix.image.repo }}:${{ matrix.image.tag }} + triggerdotdev/${{ matrix.image.repo }}:${{ matrix.image.tag }}-${{ needs.setup.outputs.publish_id }} build-args: | BASE_IMAGE=${{ matrix.image.base }} DEBIAN_SNAPSHOT=${{ needs.setup.outputs.snapshot }} @@ -187,7 +194,9 @@ jobs: platforms: linux/amd64,linux/arm64 provenance: false outputs: type=image,push=true,rewrite-timestamp=true - tags: triggerdotdev/${{ matrix.image.repo }}:${{ matrix.image.tag }}-build + tags: | + triggerdotdev/${{ matrix.image.repo }}:${{ matrix.image.tag }}-build + triggerdotdev/${{ matrix.image.repo }}:${{ matrix.image.tag }}-build-${{ needs.setup.outputs.publish_id }} build-args: | BASE_IMAGE=${{ matrix.image.base }} DEBIAN_SNAPSHOT=${{ needs.setup.outputs.snapshot }} diff --git a/base-images/README.md b/base-images/README.md index 78f63a552..88e568e50 100644 --- a/base-images/README.md +++ b/base-images/README.md @@ -14,7 +14,10 @@ images derived from these behave like their upstream bases. ## Tags and pinning Tags are mutable and rebuilt in place on demand; each rebuild picks up Debian -security updates published up to its snapshot date. The +security updates published up to its snapshot date. Every publish also pushes +an immutable per-publish tag (snapshot timestamp plus commit, e.g. `22-bookworm-20260812-000000-45444a7`) so previously +published digests stay tag-referenced; never delete these, since shipped CLI +releases pin their digests. The runtime itself (the node or bun binaries from the upstream base) only moves when the base digests in `images.json` are bumped. When bumping a base digest, keep the snapshot at least as new as the upstream image's own archive