Skip to content

Commit 4f665de

Browse files
robnester-rhclaude
andcommitted
fix(EC-1778): use scheme-based dispatch to avoid misrouting bare hostnames
The OCI Matcher matches localhost/127.0.0.1 as known registries, which misroutes git-over-HTTP sources hosted on localhost in acceptance tests. Dispatch to custom gatherers only for explicit oci:// or http(s):// scheme prefixes; bare hostnames fall through to the registry where git matchers are checked before OCI matchers. reference: EC-1778 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e859dcd commit 4f665de

2 files changed

Lines changed: 21 additions & 17 deletions

File tree

internal/downloader/downloader.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,23 @@ var (
5252
var gatherFunc = func(ctx context.Context, source, destination string) (metadata.Metadata, error) {
5353
initialize()
5454

55+
// Dispatch to custom gatherers only for unambiguous scheme prefixes.
56+
// Bare hostnames (e.g. quay.io/..., 127.0.0.1/...) fall through to
57+
// the registry, which checks git matchers before OCI matchers.
5558
switch {
56-
case ociGatherer.Matcher(source):
59+
case strings.HasPrefix(source, "oci://") || strings.HasPrefix(source, "oci::"):
5760
return ociGatherer.Gather(ctx, source, destination)
58-
case httpGatherer.Matcher(source):
59-
return httpGatherer.Gather(ctx, source, destination)
60-
default:
61-
g, err := registry.GetGatherer(source)
62-
if err != nil {
63-
return nil, err
61+
case strings.HasPrefix(source, "https://") || strings.HasPrefix(source, "http://"):
62+
if httpGatherer.Matcher(source) {
63+
return httpGatherer.Gather(ctx, source, destination)
6464
}
65-
return g.Gather(ctx, source, destination)
6665
}
66+
67+
g, err := registry.GetGatherer(source)
68+
if err != nil {
69+
return nil, err
70+
}
71+
return g.Gather(ctx, source, destination)
6772
}
6873

6974
var _initialize = func() {

internal/downloader/downloader_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ func TestOCITracing(t *testing.T) {
159159
t.Cleanup(trace.Stop)
160160

161161
log.Level = logrus.TraceLevel
162-
initialize = _initialize // we want it to re-execute for the test
163162
t.Cleanup(func() {
164163
log.Level = logrus.InfoLevel
165164
initialize = sync.OnceFunc(_initialize)
@@ -179,7 +178,12 @@ func TestOCITracing(t *testing.T) {
179178
require.NoError(t, err)
180179
require.NoError(t, remote.Push(ref, img))
181180

182-
_, err = gatherFunc(context.Background(), ref.String(), t.TempDir())
181+
// Initialize directly then call ociGatherer.Gather to test the OCI
182+
// tracing path. Bare localhost refs fall through to the registry's
183+
// default gatherer (no tracing), so we invoke the gatherer directly.
184+
_initialize()
185+
186+
_, err = ociGatherer.Gather(context.Background(), ref.String(), t.TempDir())
183187
require.NoError(t, err)
184188

185189
trace.Stop()
@@ -215,6 +219,7 @@ func TestHTTPTracing(t *testing.T) {
215219
t.Cleanup(trace.Stop)
216220

217221
log.Level = logrus.TraceLevel
222+
initialize = _initialize
218223
t.Cleanup(func() {
219224
log.Level = logrus.InfoLevel
220225
initialize = sync.OnceFunc(_initialize)
@@ -228,13 +233,7 @@ func TestHTTPTracing(t *testing.T) {
228233
}))
229234
t.Cleanup(server.Close)
230235

231-
// Initialize directly to set up tracing transport, then call
232-
// httpGatherer.Gather to test the HTTP path specifically.
233-
// (127.0.0.1 matches the OCI registry pattern, so gatherFunc
234-
// would dispatch to the OCI gatherer instead of HTTP.)
235-
_initialize()
236-
237-
_, err := httpGatherer.Gather(context.Background(), fmt.Sprintf("%s/foo", server.URL), path.Join(t.TempDir(), "dl"))
236+
_, err := gatherFunc(context.Background(), fmt.Sprintf("%s/foo", server.URL), path.Join(t.TempDir(), "dl"))
238237
require.NoError(t, err)
239238

240239
trace.Stop()

0 commit comments

Comments
 (0)