diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 9ed7a35..add4905 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -135,10 +135,20 @@ jobs: GITEA_REPO: Misthios/bootc-images steps: - name: Install tools - run: dnf install -y nodejs jq curl + run: dnf install -y nodejs jq curl skopeo - name: Checkout uses: actions/checkout@v4 - name: Prune old releases env: RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} run: ./prune-releases.sh fedora-cosmic + - name: Prune old registry tags + env: + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + set -xeuo pipefail + authfile=/tmp/prune-auth.json + echo "${REGISTRY_TOKEN}" | skopeo login -u "${REGISTRY_USERNAME}" \ + --password-stdin --authfile "${authfile}" git.plabble.org + AUTHFILE="${authfile}" ./prune-registry.sh fedora-cosmic Misthios 44 rawhide diff --git a/prune-registry.sh b/prune-registry.sh new file mode 100644 index 0000000..862fbe5 --- /dev/null +++ b/prune-registry.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# Prune old container image versions (tags) for an image in the Gitea registry. +# +# Keeps the moving tag (e.g. "44") and the newest versioned tag per distro, +# plus the cosign signature tag (sha256-.sig) for each kept image. +# +# Usage: +# REGISTRY_TOKEN= REGISTRY_USERNAME= \ +# ./prune-registry.sh [image] [owner] [distro...] +set -euo pipefail + +IMAGE="${1:-fedora-cosmic}"; shift || true +OWNER="${1:-Misthios}"; shift || true +DISTROS=("$@"); [[ ${#DISTROS[@]} -gt 0 ]] || DISTROS=(44 rawhide) + +GITEA_URL="${GITEA_URL:-https://git.plabble.org}" +REGISTRY_HOST="${REGISTRY_HOST:-$(printf '%s' "${GITEA_URL}" | sed -E 's#https?://##')}" +TOKEN="${REGISTRY_TOKEN:?REGISTRY_TOKEN (write:package) is required}" +AUTHFILE="${AUTHFILE:-${HOME}/.docker/config.json}" +API="${GITEA_URL%/}/api/v1/packages/${OWNER}/container/${IMAGE}" +IMAGE_REF="${REGISTRY_HOST}/${OWNER}/${IMAGE}" + +# Collect all versions (paginated). +versions="" +page=1 +while :; do + page_json="$(curl -fsSL -H "Authorization: token ${TOKEN}" \ + "${API}?limit=50&page=${page}")" || break + [[ "$(jq 'length' <<< "${page_json}")" -eq 0 ]] && break + versions+="$(jq -r '.[].version' <<< "${page_json}")"$'\n' + page=$((page + 1)) + [[ "${page}" -gt 40 ]] && break +done + +# Decide what to keep. +declare -A keep=() +for d in "${DISTROS[@]}"; do + keep["${d}"]=1 + newest="$(grep -E "^${d}\.[0-9]+\.[0-9]+$" <<< "${versions}" \ + | sort -t. -k2,2n -k3,3n | tail -1)" + [[ -n "${newest}" ]] && keep["${newest}"]=1 +done + +# Keep the cosign signature of each kept image tag. +for tag in "${!keep[@]}"; do + [[ "${tag}" == sha256-* ]] && continue + digest="$(skopeo inspect --authfile "${AUTHFILE}" --format '{{.Digest}}' \ + "docker://${IMAGE_REF}:${tag}" 2>/dev/null || true)" + [[ -n "${digest}" ]] && keep["sha256-${digest#sha256:}.sig"]=1 +done + +# Delete everything else. +while IFS= read -r v; do + [[ -z "${v}" ]] && continue + if [[ -n "${keep[${v}]:-}" ]]; then + echo "keep ${v}" + else + echo "remove ${v}" + curl -fsSL -X DELETE -H "Authorization: token ${TOKEN}" \ + "${API}/${v}" >/dev/null || echo " (failed to delete ${v})" + fi +done <<< "${versions}" + +echo "Pruned ${IMAGE} registry versions."