The registry path is lowercase, so the capitalized owner made skopeo inspect fail and every cosign .sig tag was deleted. Lowercase the owner and, if no digest resolves, keep all signature tags instead of deleting them.
77 lines
2.6 KiB
Bash
Executable File
77 lines
2.6 KiB
Bash
Executable File
#!/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-<digest>.sig) for each kept image.
|
|
#
|
|
# Usage:
|
|
# REGISTRY_TOKEN=<write:package> REGISTRY_USERNAME=<user> \
|
|
# ./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}"
|
|
# Registry paths are lowercase (the Gitea API owner is not).
|
|
IMAGE_REF="${REGISTRY_HOST}/$(printf '%s' "${OWNER}" | tr '[:upper:]' '[:lower:]')/${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. If no digest could be
|
|
# resolved, keep every signature tag rather than risk deleting a needed one.
|
|
resolved=0
|
|
for tag in "${!keep[@]}"; do
|
|
[[ "${tag}" == sha256-* ]] && continue
|
|
digest="$(skopeo inspect --authfile "${AUTHFILE}" --format '{{.Digest}}' \
|
|
"docker://${IMAGE_REF}:${tag}" 2>/dev/null || true)"
|
|
if [[ -n "${digest}" ]]; then
|
|
keep["sha256-${digest#sha256:}.sig"]=1
|
|
resolved=1
|
|
fi
|
|
done
|
|
if [[ "${resolved}" -eq 0 ]]; then
|
|
echo "WARNING: could not resolve any image digest; keeping all signature tags"
|
|
while IFS= read -r v; do
|
|
[[ "${v}" == sha256-* ]] && keep["${v}"]=1
|
|
done <<< "${versions}"
|
|
fi
|
|
|
|
# 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."
|