fix(ci): mirror index copy works on Gitea - pinned buildx [skip ci] #18

Merged
jknapp merged 1 commits from fix/mirror-index-gitea-compat into main 2026-11-12 01:03:16 +00:00
Owner

Fixes the mirror workflow that failed in run 5156 (PUT .../manifests/<tag>-staging: 404).

Root cause (reproduced on real Gitea with scratch zz-compat-* packages). Gitea rejects an index PUT unless every child manifest is already stored as a by-digest version (MANIFEST_BLOB_UNKNOWN, shown as 404). buildx <= 0.20.x, including the runner's distro buildx 0.15.1, pushes the children of a copied index to the tag path. That works on registry:2, not on Gitea, and it leaves a stray single-manifest <tag>-staging version. buildx >= 0.24 pushes children by digest and works.

Gitea facts measured. It accepts OCI indexes, Docker manifest lists, unknown/unknown attestation children, and 14-16 children. It preserves the index digest byte-for-byte, so the digest-equality assertion still holds. docker pull --platform linux/arm64 selects the right child.

Changes

  • Workflow: install a sha256-verified pinned buildx v0.28.0 (imagetools needs no builder, so setup-buildx-action is dropped) and pass it as $BUILDX.
  • mirror-index-copy.sh: MIN_BUILDX guard (default 0.24.0) refuses an old buildx before any registry traffic, so no stray version is created. The digest is now the sha256 of the raw index bytes, because buildx 0.28 ignores inspect --format here.
  • Test: new attestation-children case and old-buildx guard case (10/10 pass against a local registry:2).

Proven on real Gitea (scratch names, since deleted): the full script with buildx 0.28.0 copied the real python:3.12-slim index (16 children), replaced a pre-existing single-manifest tag, and passed both assertions with digest sha256:5e2bdb1b... preserved. A second run was idempotent.

Merge note: merging to main triggers the HMB image build on any push. Use [skip ci] in the merge title.

Not verified: a live run in Gitea Actions (the runner cannot reach Docker Hub from here; I used the same index from a local registry), and the pinned-buildx download step inside the act runner.

🤖 Generated with Claude Code

https://claude.ai/code/session_0185ukXjXyosSkunDsdWz3mb

Fixes the mirror workflow that failed in run 5156 (`PUT .../manifests/<tag>-staging: 404`). **Root cause (reproduced on real Gitea with scratch `zz-compat-*` packages).** Gitea rejects an index PUT unless every child manifest is already stored as a by-digest version (`MANIFEST_BLOB_UNKNOWN`, shown as 404). buildx <= 0.20.x, including the runner's distro buildx 0.15.1, pushes the children of a copied index to the tag path. That works on registry:2, not on Gitea, and it leaves a stray single-manifest `<tag>-staging` version. buildx >= 0.24 pushes children by digest and works. **Gitea facts measured.** It accepts OCI indexes, Docker manifest lists, `unknown/unknown` attestation children, and 14-16 children. It preserves the index digest byte-for-byte, so the digest-equality assertion still holds. `docker pull --platform linux/arm64` selects the right child. **Changes** - Workflow: install a sha256-verified pinned buildx v0.28.0 (imagetools needs no builder, so setup-buildx-action is dropped) and pass it as `$BUILDX`. - `mirror-index-copy.sh`: `MIN_BUILDX` guard (default 0.24.0) refuses an old buildx before any registry traffic, so no stray version is created. The digest is now the sha256 of the raw index bytes, because buildx 0.28 ignores `inspect --format` here. - Test: new attestation-children case and old-buildx guard case (10/10 pass against a local registry:2). **Proven on real Gitea** (scratch names, since deleted): the full script with buildx 0.28.0 copied the real python:3.12-slim index (16 children), replaced a pre-existing single-manifest tag, and passed both assertions with digest sha256:5e2bdb1b... preserved. A second run was idempotent. **Merge note:** merging to main triggers the HMB image build on any push. Use `[skip ci]` in the merge title. Not verified: a live run in Gitea Actions (the runner cannot reach Docker Hub from here; I used the same index from a local registry), and the pinned-buildx download step inside the act runner. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0185ukXjXyosSkunDsdWz3mb
jknapp added 1 commit 2026-11-12 01:01:18 +00:00
Run 5156 failed copying python:3.12-slim / golang:1.25 into Gitea:
`PUT .../manifests/<tag>-staging: 404`, leaving a stray single-manifest
<tag>-staging version. Reproduced on real Gitea with scratch packages:
buildx <= 0.20.x (runner distro buildx is 0.15.1) pushes the children of a
copied index to the TAG path; Gitea only records manifests PUT by digest, so
the index PUT is rejected (MANIFEST_BLOB_UNKNOWN -> 404). buildx >= 0.24
pushes children by digest and works; Gitea then preserves the index digest, so
the digest-equality assertion stays.

- workflow: install a sha256-verified pinned buildx (v0.28.0) instead of
  setup-buildx-action (imagetools needs no builder) and pass it as $BUILDX
- mirror-index-copy.sh: BUILDX/MIN_BUILDX guard refuses buildx < 0.24 before
  any registry traffic; digest computed as sha256 of the raw index bytes
  (buildx 0.28 ignores `inspect --format` here)
- test: attestation-children index and old-buildx guard cases

Merge with [skip ci] in the merge title: any push to main triggers the HMB
image build.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185ukXjXyosSkunDsdWz3mb
jknapp merged commit 48edc09e8d into main 2026-11-12 01:03:16 +00:00
jknapp deleted branch fix/mirror-index-gitea-compat 2026-11-12 01:03:17 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: cloud-hosting-platform/haproxy-manager-base#18