diff --git a/.github/workflows/base-images.yml b/.github/workflows/base-images.yml index 13abecdad7..2c23246de3 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 78f63a552a..88e568e50a 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