ci: refuse to re-publish an existing image tag (zegit#262) #14
@@ -78,13 +78,31 @@ jobs:
|
|||||||
# A master push VALIDATES that the Dockerfile still builds on both arches
|
# A master push VALIDATES that the Dockerfile still builds on both arches
|
||||||
# but publishes nothing; only an explicit dispatch names a tag and pushes.
|
# but publishes nothing; only an explicit dispatch names a tag and pushes.
|
||||||
# Guessing a tag from a branch push would silently mint versions.
|
# Guessing a tag from a branch push would silently mint versions.
|
||||||
|
#
|
||||||
|
# Tags are immutable (zegit#262): consumers pin tag@digest, and the
|
||||||
|
# registry drops the old manifest when a tag moves, so re-publishing a
|
||||||
|
# tag breaks every pin on it. A build refuses an existing tag; sign_only
|
||||||
|
# refuses a tag that does not exist.
|
||||||
- id: meta
|
- id: meta
|
||||||
|
env:
|
||||||
|
EVENT: ${{ github.event_name }}
|
||||||
|
INPUT_TAG: ${{ inputs.tag }}
|
||||||
|
SIGN_ONLY: ${{ inputs.sign_only }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
if [ "$EVENT" = "workflow_dispatch" ]; then
|
||||||
|
pull=$(curl -fsS "https://${REGISTRY}/v2/token?scope=repository:${IMAGE_PATH}:pull&service=container_registry" | python3 -c 'import json,sys; print(json.load(sys.stdin)["token"])')
|
||||||
|
tags=$(curl -fsS -H "Authorization: Bearer ${pull}" "https://${REGISTRY}/v2/${IMAGE_PATH}/tags/list?n=10000" | python3 -c 'import json,sys; print("\n".join(json.load(sys.stdin).get("tags") or []))')
|
||||||
|
if printf '%s\n' "$tags" | grep -qxF "$INPUT_TAG"; then
|
||||||
|
if [ "$SIGN_ONLY" != "true" ]; then
|
||||||
|
echo "::error::${IMAGE_PATH}:${INPUT_TAG} already exists; tags are immutable, so nothing is overwritten (to sign it, dispatch with sign_only)"; exit 1
|
||||||
|
fi
|
||||||
|
elif [ "$SIGN_ONLY" = "true" ]; then
|
||||||
|
echo "::error::${IMAGE_PATH}:${INPUT_TAG} is not published; nothing to sign"; exit 1
|
||||||
|
fi
|
||||||
echo "push=true" >> "$GITHUB_OUTPUT"
|
echo "push=true" >> "$GITHUB_OUTPUT"
|
||||||
echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
|
echo "tag=${INPUT_TAG}" >> "$GITHUB_OUTPUT"
|
||||||
echo "sign_only=${{ inputs.sign_only }}" >> "$GITHUB_OUTPUT"
|
echo "sign_only=${SIGN_ONLY}" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "push=false" >> "$GITHUB_OUTPUT"
|
echo "push=false" >> "$GITHUB_OUTPUT"
|
||||||
echo "tag=ci-validation" >> "$GITHUB_OUTPUT"
|
echo "tag=ci-validation" >> "$GITHUB_OUTPUT"
|
||||||
|
|||||||
Reference in new issue
Block a user