diff --git a/internal/builder/mirror.go b/internal/builder/mirror.go index 3a5b4db..83307fe 100644 --- a/internal/builder/mirror.go +++ b/internal/builder/mirror.go @@ -180,6 +180,20 @@ func (r Registry) MirrorImage(ctx context.Context, from, repository string) (str if err != nil { return "", err } + // **Already held is already mirrored.** A base is named by digest, and a digest this registry + // holds under the module's repository is the same bytes whatever upstream would say — so + // upstream is not asked. Asked every build, the public hub's anonymous pull limit was reached + // on the first merge that rebuilt a whole catalogue (2026-09-28), and every module whose base + // lives there failed on a copy it did not need. + if strings.HasPrefix(where.reference, "sha256:") { + held, err := r.has(ctx, "http://"+r.Address+"/v2/"+repository+"/manifests/"+where.reference) + if err != nil { + return "", fmt.Errorf("asking %s whether it holds %s: %w", r.Address, from, err) + } + if held { + return r.Address + "/" + repository + "@" + where.reference, nil + } + } src := &source{client: r.client()} digest, err := r.copyManifest(ctx, src, where, where.reference, repository) if err != nil { diff --git a/internal/builder/mirror_test.go b/internal/builder/mirror_test.go index 6a2749c..7f8adbd 100644 --- a/internal/builder/mirror_test.go +++ b/internal/builder/mirror_test.go @@ -103,6 +103,12 @@ func (m *theMeshsRegistry) handler() http.Handler { m.mu.Lock() defer m.mu.Unlock() switch { + case r.Method == http.MethodHead && strings.Contains(r.URL.Path, "/manifests/"): + if _, ok := m.manifests[r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]]; ok { + w.WriteHeader(http.StatusOK) + } else { + w.WriteHeader(http.StatusNotFound) + } case r.Method == http.MethodHead && strings.Contains(r.URL.Path, "/blobs/"): if _, ok := m.blobs[r.URL.Path[strings.LastIndex(r.URL.Path, "/")+1:]]; ok { w.WriteHeader(http.StatusOK) @@ -219,3 +225,27 @@ func TestATagBeforeTheDigestIsNotPartOfTheRepository(t *testing.T) { t.Fatalf("got %+v", got) } } + +// A base this registry already holds by digest is not asked of upstream at all: the public hub +// limits anonymous pulls, and a catalogue rebuilt on one merge asked it once per module. +func TestABaseAlreadyHeldIsNotAskedOfUpstream(t *testing.T) { + src, indexDigest, _ := anUpstreamRegistry(t) + dst := &theMeshsRegistry{blobs: map[string][]byte{}, manifests: map[string][]byte{}} + dstServer := httptest.NewServer(dst.handler()) + defer dstServer.Close() + address := strings.TrimPrefix(dstServer.URL, "http://") + r := Registry{Address: address, HTTP: src.Client()} + host := strings.TrimPrefix(src.URL, "http://") + if _, err := r.MirrorImage(context.Background(), host+"/library/thing:latest", "hello-web/server"); err != nil { + t.Fatal(err) + } + // Upstream gone: the pinned base is answered from what the mesh holds. + src.Close() + reference, err := r.MirrorImage(context.Background(), host+"/library/thing@"+indexDigest, "hello-web/server") + if err != nil { + t.Fatalf("a base the registry holds was asked of an upstream that is gone: %v", err) + } + if reference != address+"/hello-web/server@"+indexDigest { + t.Fatalf("pinned as %q", reference) + } +}