#!/usr/bin/env bash ## index-platforms.sh REF ## Prints "index ..." (real platforms only, attestation children ## excluded) when REF is an image index / manifest list, or "single" when it is ## a plain single-platform manifest. Exit 3 = REF not found, 1 = any other ## failure (fail closed). Used by lsphp-source-emergency.yaml to refuse to ## replace a multi-arch tag with an amd64-only one. ## Env: IMAGETOOLS overrides "docker buildx imagetools" (tests use a stub). set -euo pipefail IMAGETOOLS=${IMAGETOOLS:-docker buildx imagetools} ref=${1:?usage: index-platforms.sh REF} err=$(mktemp); trap 'rm -f "$err"' EXIT rc=0 # shellcheck disable=SC2086 raw=$($IMAGETOOLS inspect --raw "$ref" 2>"$err") || rc=$? if [ "$rc" -ne 0 ]; then if grep -qiE 'not found|manifest unknown|name unknown|: 404' "$err"; then echo "index-platforms: $ref not found" >&2; exit 3; fi echo "index-platforms: imagetools failed: $(head -c 300 "$err" | tr '\n' ' ')" >&2; exit 1 fi printf '%s' "$raw" | python3 -I -c ' import json, sys try: d = json.load(sys.stdin) except Exception as e: sys.stderr.write("index-platforms: not JSON: %s\n" % e); sys.exit(1) if isinstance(d, dict) and isinstance(d.get("manifests"), list): ps = [] for m in d["manifests"]: p = m.get("platform") if isinstance(m, dict) else None if not isinstance(p, dict) or "vnd.docker.reference.type" in (m.get("annotations") or {}): continue if p.get("os") in (None, "", "unknown") or p.get("architecture") in (None, "", "unknown"): continue ps.append("%s/%s" % (p["os"], p["architecture"])) print("index " + " ".join(sorted(set(ps)))) elif isinstance(d, dict) and isinstance(d.get("config"), dict): print("single") else: sys.stderr.write("index-platforms: neither index nor image manifest\n"); sys.exit(1) '