From 4455fe6dc0a6cd2e31da019a330df60d4d717b0b Mon Sep 17 00:00:00 2001 From: Justin Miron Date: Tue, 17 Mar 2026 14:33:13 -0500 Subject: [PATCH] Add ReportResolvedSourceReference to copy.Options When registry mirrors are configured via registries.conf, callers of copy.Image have no way to discover which endpoint was actually contacted. The source's Reference() always returns the logical (user-requested) reference. Introduce a ResolvedImageSource interface in types/ that ImageSource implementations can satisfy to expose the physical endpoint. The docker transport implements this by returning its internal physicalRef. copy.Image populates the new ReportResolvedSourceReference option pointer when the source satisfies the interface, giving callers like CRI-O access to the resolved registry for metrics and diagnostics. Signed-off-by: Justin Miron --- image/copy/copy.go | 14 ++++++++++++++ image/docker/docker_image_src.go | 5 +++++ image/docker/docker_image_src_test.go | 6 ++++++ image/types/types.go | 10 ++++++++++ 4 files changed, 35 insertions(+) diff --git a/image/copy/copy.go b/image/copy/copy.go index 5d70482519..e5ba48f541 100644 --- a/image/copy/copy.go +++ b/image/copy/copy.go @@ -157,6 +157,13 @@ type Options struct { // WARNING: It is unspecified whether the reference also contains a reference.Named element. ReportResolvedReference *types.ImageReference + // ReportResolvedSourceReference, if non-nil, will be populated by + // copy.Image with the source's "resolved" reference — the actual + // endpoint contacted, which may differ from the requested reference + // when registry mirrors are configured. It is left nil when the + // source transport does not report a resolved reference. + ReportResolvedSourceReference *types.ImageReference + // DestinationTimestamp, if set, will force timestamps of content created in the destination to this value. // Most transports don't support this. // @@ -262,6 +269,13 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef, rawSource := imagesource.FromPublic(publicRawSource) defer safeClose("src", rawSource) + if options.ReportResolvedSourceReference != nil { + *options.ReportResolvedSourceReference = nil + if resolver, ok := publicRawSource.(types.ResolvedImageSource); ok { + *options.ReportResolvedSourceReference = resolver.ResolvedReference() + } + } + // If reportWriter is not a TTY (e.g., when piping to a file), do not // print the progress bars to avoid long and hard to parse output. // Instead use printCopyInfo() to print single line "Copying ..." messages. diff --git a/image/docker/docker_image_src.go b/image/docker/docker_image_src.go index 4003af5d27..e6de78cd7d 100644 --- a/image/docker/docker_image_src.go +++ b/image/docker/docker_image_src.go @@ -203,6 +203,11 @@ func (s *dockerImageSource) Reference() types.ImageReference { return s.logicalRef } +// ResolvedReference implements types.ResolvedImageSource. +func (s *dockerImageSource) ResolvedReference() types.ImageReference { + return s.physicalRef +} + // Close removes resources associated with an initialized ImageSource, if any. func (s *dockerImageSource) Close() error { return s.c.Close() diff --git a/image/docker/docker_image_src_test.go b/image/docker/docker_image_src_test.go index 4d81bde7e0..9ef6375083 100644 --- a/image/docker/docker_image_src_test.go +++ b/image/docker/docker_image_src_test.go @@ -74,6 +74,12 @@ location = "@REGISTRY@/with-mirror" // The observable behavior assert.Equal(t, "//"+c.input, src.Reference().StringWithinTransport(), c.input) assert.Equal(t, ref.StringWithinTransport(), src.Reference().StringWithinTransport(), c.input) + // Verify ResolvedReference() returns the physical ref through the public interface + resolver, ok := src.(types.ResolvedImageSource) + require.True(t, ok, c.input) + resolved := resolver.ResolvedReference() + assert.Equal(t, "//"+c.physical, resolved.StringWithinTransport(), c.input) + // Also peek into internal state src2, ok := src.(*dockerImageSource) require.True(t, ok, c.input) diff --git a/image/types/types.go b/image/types/types.go index 1c0007e6e4..9108cc0768 100644 --- a/image/types/types.go +++ b/image/types/types.go @@ -702,6 +702,16 @@ type SystemContext struct { CompressionLevel *int } +// ResolvedImageSource is an optional interface that ImageSource implementations +// can satisfy to report the actual endpoint used when the source was resolved +// through mirrors or redirects. +type ResolvedImageSource interface { + // ResolvedReference returns the reference to the actual endpoint that + // was contacted, which may differ from Reference() when registry + // mirrors are configured. + ResolvedReference() ImageReference +} + // ProgressEvent is the type of events a progress reader can produce // Warning: new event types may be added any time. type ProgressEvent uint