Skip to content

Commit 6e34bcf

Browse files
committed
feat: allow namespace override per image (#4725)
1 parent fdd79cf commit 6e34bcf

File tree

2 files changed

+87
-7
lines changed

2 files changed

+87
-7
lines changed

internal/utils/docker.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,49 @@ func GetRegistry() string {
194194
return strings.ToLower(registry)
195195
}
196196

197-
func GetRegistryImageUrl(imageName string) string {
197+
// GetRegistryImageUrl builds a fully-qualified image reference.
198+
//
199+
// Expected input format:
200+
//
201+
// NAMESPACE/IMAGE:TAG
202+
//
203+
// Behavior:
204+
// - Uses the configured registry (via GetRegistry()).
205+
// - Allows per-image namespace overrides via
206+
// INTERNAL_IMAGE_NAMESPACE_"IMAGE_NAME".
207+
// - Falls back to the "supabase" namespace for non-docker.io registries
208+
// when no override is configured.
209+
func GetRegistryImageUrl(imageRef string) string {
198210
registry := GetRegistry()
199-
if registry == "docker.io" {
200-
return imageName
211+
212+
// Split path segments (supports nested namespaces)
213+
parts := strings.Split(imageRef, "/")
214+
if len(parts) < 2 {
215+
return imageRef // invalid format
216+
}
217+
218+
imageWithTag := parts[len(parts)-1]
219+
namespace := strings.Join(parts[:len(parts)-1], "/")
220+
221+
// Split image and tag
222+
imageParts := strings.SplitN(imageWithTag, ":", 2)
223+
if len(imageParts) != 2 {
224+
return imageRef // invalid format
201225
}
202-
// Configure mirror registry
203-
parts := strings.Split(imageName, "/")
204-
imageName = parts[len(parts)-1]
205-
return registry + "/supabase/" + imageName
226+
227+
imageName := imageParts[0]
228+
imageTag := imageParts[1]
229+
230+
// Check for per-image namespace override
231+
overrideKey := "INTERNAL_IMAGE_NAMESPACE_" + strings.ToUpper(imageName)
232+
if override := viper.GetString(overrideKey); override != "" {
233+
namespace = override
234+
} else if registry != "docker.io" {
235+
// Default namespace for non-docker.io registries
236+
namespace = "supabase"
237+
}
238+
239+
return fmt.Sprintf("%s/%s/%s:%s", registry, namespace, imageName, imageTag)
206240
}
207241

208242
func DockerImagePull(ctx context.Context, imageTag string, w io.Writer) error {

internal/utils/docker_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,49 @@ func TestExecOnce(t *testing.T) {
306306

307307
// TODO: mock tcp hijack
308308
}
309+
310+
func TestGetRegistryImageUrl(t *testing.T) {
311+
t.Run("docker.io keeps provided namespace (library)", func(t *testing.T) {
312+
viper.Set("INTERNAL_IMAGE_REGISTRY", "docker.io")
313+
314+
got := GetRegistryImageUrl("library/kong:2.8.1")
315+
assert.Equal(t, "docker.io/library/kong:2.8.1", got)
316+
})
317+
318+
t.Run("non-docker.io defaults namespace to supabase when no override", func(t *testing.T) {
319+
viper.Set("INTERNAL_IMAGE_REGISTRY", "ghcr.io")
320+
321+
got := GetRegistryImageUrl("library/kong:2.8.1")
322+
assert.Equal(t, "ghcr.io/supabase/kong:2.8.1", got)
323+
})
324+
325+
t.Run("supabase namespace remains supabase on non-docker.io registry", func(t *testing.T) {
326+
viper.Set("INTERNAL_IMAGE_REGISTRY", "ghcr.io")
327+
328+
got := GetRegistryImageUrl("supabase/postgres:17.6.1.074")
329+
assert.Equal(t, "ghcr.io/supabase/postgres:17.6.1.074", got)
330+
})
331+
332+
t.Run("namespace override gets applied", func(t *testing.T) {
333+
viper.Set("INTERNAL_IMAGE_REGISTRY", "ghcr.io")
334+
viper.Set("INTERNAL_IMAGE_NAMESPACE_POSTGREST", "custom")
335+
336+
got := GetRegistryImageUrl("postgrest/postgrest:v14.3")
337+
assert.Equal(t, "ghcr.io/custom/postgrest:v14.3", got)
338+
})
339+
340+
t.Run("invalid image format returns as-is", func(t *testing.T) {
341+
viper.Set("INTERNAL_IMAGE_REGISTRY", "docker.io")
342+
343+
got := GetRegistryImageUrl("postgrest")
344+
assert.Equal(t, "postgrest", got)
345+
})
346+
347+
t.Run("overrides kong namespace to docker/library on public.ecr.aws", func(t *testing.T) {
348+
viper.Set("INTERNAL_IMAGE_REGISTRY", "public.ecr.aws")
349+
viper.Set("INTERNAL_IMAGE_NAMESPACE_KONG", "docker/library")
350+
351+
got := GetRegistryImageUrl("library/kong:2.8.1")
352+
assert.Equal(t, "public.ecr.aws/docker/library/kong:2.8.1", got)
353+
})
354+
}

0 commit comments

Comments
 (0)