fix(ci): mirror runnable OCI images without unsupported referrers (#1012)

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-10-25 15:14:14 +08:00 • committed by GitHub
parent b85629239c
commit e7e38d7304
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 120 additions and 11 deletions

View file

@ -28,6 +28,7 @@ on:
- '.github/workflows/pr-helm-chart.yml'
- '.github/workflows/pr-tests.yml'
- '.github/workflows/publish-chart.yml'
- '.github/workflows/publish-images.yml'
- '.github/workflows/security.yml'
- '.github/workflows/pr-scripts.yml'
- '.github/workflows/migration-preflight.yml'

View file

@ -150,9 +150,16 @@ jobs:
echo "enabled=false" >> "$GITHUB_OUTPUT"
fi
- name: Set up Docker Buildx
- name: Install pinned registry copy tool
if: ${{ steps.mirror.outputs.enabled == 'true' }}
uses: docker/setup-buildx-action@v3
run: |
# Buildx automatically copies OCI referrers rejected by some mirrors.
curl -fsSL --retry 3 \
https://github.com/regclient/regclient/releases/download/v0.11.7/regctl-linux-amd64 \
-o "$RUNNER_TEMP/regctl"
echo "3737fbbdd791e04e7a831640b681f3397a376498e80e2ad9b1b2d27296f239bc $RUNNER_TEMP/regctl" | sha256sum -c -
chmod +x "$RUNNER_TEMP/regctl"
echo "$RUNNER_TEMP" >> "$GITHUB_PATH"
- name: Log in to mirror registry
if: ${{ steps.mirror.outputs.enabled == 'true' }}

View file

@ -2,6 +2,8 @@
set -euo pipefail
# The publishing workflow installs the checksum-pinned regctl used below.
# Python 3 is used only to select descriptors from the public source metadata.
IMAGES_FILE="${1:-deploy/runtime-mirror-images.txt}"
: "${MIRROR_REGISTRY:?MIRROR_REGISTRY is required}"
@ -19,11 +21,61 @@ while read -r source target; do
exit 1
fi
if docker buildx imagetools inspect "${target_prefix}/${target}" >/dev/null 2>&1; then
if regctl manifest head "${target_prefix}/${target}" >/dev/null 2>&1; then
echo "Skipping existing image ${target_prefix}/${target}"
continue
fi
echo "Mirroring ${source} -> ${target_prefix}/${target}"
docker buildx imagetools create --tag "${target_prefix}/${target}" "${source}"
manifest="$(regctl manifest get "${source}" --format raw-body)"
# Copy immutable runnable children, not the index's attestations: some mirror
# registries reject their application/vnd.oci.empty.v1+json config media type.
# Keep every image platform (including variants), rather than hardcoding amd64.
sources="$(printf '%s' "$manifest" | python3 -c '
import json, sys
source = sys.argv[1]
index = json.load(sys.stdin)
media_type = index.get("mediaType")
print(media_type)
if "manifests" not in index:
if index.get("artifactType") or media_type not in (
"application/vnd.oci.image.manifest.v1+json",
"application/vnd.docker.distribution.manifest.v2+json",
):
sys.exit("Source is not a runnable image manifest")
print(source)
else:
if media_type not in ("application/vnd.oci.image.index.v1+json",
"application/vnd.docker.distribution.manifest.list.v2+json"):
sys.exit("Source has an unsupported image index media type")
refs = []
for item in index["manifests"]:
if (item.get("annotations", {}).get("vnd.docker.reference.type") == "attestation-manifest"
or item.get("artifactType")):
continue
platform = item.get("platform", {})
if any(platform.get(key) in (None, "", "unknown") for key in ("os", "architecture")):
sys.exit("Source contains an unclassified descriptor; refusing to drop a platform")
digest = item.get("digest")
if not isinstance(digest, str) or ":" not in digest or any(c.isspace() for c in digest):
sys.exit("Source contains an invalid image digest")
refs.append(source.split("@", 1)[0] + "@" + digest)
if not refs:
sys.exit("Source contains no runnable image manifests")
print("\n".join(refs))
' "$source")"
mapfile -t source_refs <<<"$sources"
source_media_type="${source_refs[0]}"
source_refs=("${source_refs[@]:1}")
# Buildx also discovers and copies referrers even with explicit child sources.
# regctl can copy the original image blobs without adding those artifacts.
if [[ ${#source_refs[@]} -eq 1 && "${source_refs[0]}" == "$source" ]]; then
regctl image copy --referrers=false "$source" "${target_prefix}/${target}"
else
mirror_args=(index create "${target_prefix}/${target}" --media-type "$source_media_type" --referrers=false)
for source_ref in "${source_refs[@]}"; do
mirror_args+=(--ref "$source_ref")
done
regctl "${mirror_args[@]}"
fi
done < "${IMAGES_FILE}"

View file

@ -4,23 +4,72 @@ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
mkdir "$work/bin"
cat >"$work/bin/docker" <<'STUB'
cat >"$work/bin/regctl" <<'STUB'
#!/usr/bin/env bash
printf '%s\n' "$*" >>"$MIRROR_COMMAND_LOG"
case "$*" in
'buildx imagetools inspect '*) [[ "${TARGET_EXISTS:-false}" == true ]] ;;
'buildx imagetools create '*) exit 0 ;;
'manifest get '*)
[[ "${INSPECT_EXIT:-0}" == 0 ]] || exit "$INSPECT_EXIT"
case "${SOURCE_KIND:-index}" in
index)
printf '%s\n' '{"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[
{"digest":"sha256:aaa","platform":{"os":"linux","architecture":"amd64"}},
{"digest":"sha256:bbb","platform":{"os":"linux","architecture":"arm64","variant":"v8"}},
{"digest":"sha256:ccc","platform":{"os":"linux","architecture":"riscv64"}},
{"digest":"sha256:attestation","platform":{"os":"unknown","architecture":"unknown"},"annotations":{"vnd.docker.reference.type":"attestation-manifest"}},
{"digest":"sha256:artifact","artifactType":"application/vnd.example.signature"}]}' ;;
single) printf '%s\n' '{"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{}}' ;;
empty) printf '%s\n' '{"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[]}' ;;
unknown) printf '%s\n' '{"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[{"digest":"sha256:unknown","platform":{"os":"unknown","architecture":"unknown"}}]}' ;;
malformed) printf '%s\n' 'not-json' ;;
esac ;;
'manifest head '*) [[ "${TARGET_EXISTS:-false}" == true ]] ;;
'index create '*|'image copy '*)
if [[ "$*" == *'@sha256:abc'* && "${SOURCE_KIND:-index}" == index ]]; then
echo 'denied: unknown manifest class for application/vnd.oci.empty.v1+json' >&2
exit 42
fi
exit "${CREATE_EXIT:-0}" ;;
*) exit 2 ;;
esac
STUB
chmod +x "$work/bin/docker"
chmod +x "$work/bin/regctl"
export PATH="$work/bin:$PATH" MIRROR_COMMAND_LOG="$work/commands"
export MIRROR_REGISTRY=registry.example.test MIRROR_NAMESPACE=skillhub
printf '%s\n' 'docker.io/rustfs/rustfs@sha256:abc rustfs:immutable-test' >"$work/images"
TARGET_EXISTS=true bash "$REPO_ROOT/scripts/mirror-runtime-images.sh" "$work/images" >"$work/output"
if grep -q 'imagetools create' "$work/commands"; then echo 'FAIL: existing target was refreshed' >&2; exit 1; fi
if grep -Eq '^index create|^image copy' "$work/commands"; then echo 'FAIL: existing target was refreshed' >&2; exit 1; fi
TARGET_EXISTS=false bash "$REPO_ROOT/scripts/mirror-runtime-images.sh" "$work/images" >"$work/output"
grep -q 'imagetools create --tag registry.example.test/skillhub/rustfs:immutable-test docker.io/rustfs/rustfs@sha256:abc' "$work/commands"
grep -Fxq 'index create registry.example.test/skillhub/rustfs:immutable-test --media-type application/vnd.oci.image.index.v1+json --referrers=false --ref docker.io/rustfs/rustfs@sha256:aaa --ref docker.io/rustfs/rustfs@sha256:bbb --ref docker.io/rustfs/rustfs@sha256:ccc' "$work/commands"
if grep '^index create' "$work/commands" | grep -Eq 'attestation|artifact'; then
echo 'FAIL: artifact descriptors were copied' >&2; exit 1
fi
SOURCE_KIND=single TARGET_EXISTS=false bash "$REPO_ROOT/scripts/mirror-runtime-images.sh" "$work/images" >"$work/output"
grep -Fxq 'image copy --referrers=false docker.io/rustfs/rustfs@sha256:abc registry.example.test/skillhub/rustfs:immutable-test' "$work/commands"
for kind in empty unknown malformed; do
: >"$work/commands"
if SOURCE_KIND="$kind" TARGET_EXISTS=false bash "$REPO_ROOT/scripts/mirror-runtime-images.sh" "$work/images" >"$work/output" 2>&1; then
echo "FAIL: invalid source $kind was accepted" >&2; exit 1
fi
if grep -Eq '^index create|^image copy' "$work/commands"; then
echo "FAIL: invalid source $kind reached the registry write" >&2; exit 1
fi
done
for stage in inspect create; do
expected=23
if [[ "$stage" == inspect ]]; then
if INSPECT_EXIT="$expected" TARGET_EXISTS=false bash "$REPO_ROOT/scripts/mirror-runtime-images.sh" "$work/images" >"$work/output" 2>&1; then
echo 'FAIL: inspection failure was swallowed' >&2; exit 1
else [[ $? == "$expected" ]]; fi
else
if CREATE_EXIT="$expected" TARGET_EXISTS=false bash "$REPO_ROOT/scripts/mirror-runtime-images.sh" "$work/images" >"$work/output" 2>&1; then
echo 'FAIL: registry copy failure was swallowed' >&2; exit 1
else [[ $? == "$expected" ]]; fi
fi
done
grep -q '^docker.io/pgsty/silo:RELEASE.2026-09-16T00-00-00Z minio:latest$' "$REPO_ROOT/deploy/runtime-mirror-images.txt"
grep -Fxq 'docker.io/pgsty/silo:RELEASE.2026-10-18T00-00-00Z@sha256:2636fc4155d9a7e41ff58cdb65ddd13ba9304e67184e13c25bc5cb34016269d7 silo:20261018-2636fc4155d9' "$REPO_ROOT/deploy/runtime-mirror-images.txt"
echo 'Storage mirror skip and legacy alias tests passed'
grep -Fq 'https://github.com/regclient/regclient/releases/download/v0.11.7/regctl-linux-amd64' "$REPO_ROOT/.github/workflows/publish-images.yml"
grep -Fq '3737fbbdd791e04e7a831640b681f3397a376498e80e2ad9b1b2d27296f239bc' "$REPO_ROOT/.github/workflows/publish-images.yml"
grep -Fq "'.github/workflows/publish-images.yml'" "$REPO_ROOT/.github/workflows/pr-scripts.yml"
echo 'Storage mirror platform filtering, skip, failure propagation and legacy alias tests passed'