Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions internal/utils/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,49 @@ func GetRegistry() string {
return strings.ToLower(registry)
}

func GetRegistryImageUrl(imageName string) string {
// GetRegistryImageUrl builds a fully-qualified image reference.
//
// Expected input format:
//
// NAMESPACE/IMAGE:TAG
//
// Behavior:
// - Uses the configured registry (via GetRegistry()).
// - Allows per-image namespace overrides via
// INTERNAL_IMAGE_NAMESPACE_"IMAGE_NAME".
// - Falls back to the "supabase" namespace for non-docker.io registries
// when no override is configured.
func GetRegistryImageUrl(imageRef string) string {
registry := GetRegistry()
if registry == "docker.io" {
return imageName

// Split path segments (supports nested namespaces)
parts := strings.Split(imageRef, "/")
if len(parts) < 2 {
return imageRef // invalid format
}

imageWithTag := parts[len(parts)-1]
namespace := strings.Join(parts[:len(parts)-1], "/")

// Split image and tag
imageParts := strings.SplitN(imageWithTag, ":", 2)
if len(imageParts) != 2 {
return imageRef // invalid format
}
// Configure mirror registry
parts := strings.Split(imageName, "/")
imageName = parts[len(parts)-1]
return registry + "/supabase/" + imageName

imageName := imageParts[0]
imageTag := imageParts[1]

// Check for per-image namespace override
overrideKey := "INTERNAL_IMAGE_NAMESPACE_" + strings.ToUpper(imageName)
if override := viper.GetString(overrideKey); override != "" {
namespace = override
} else if registry != "docker.io" {
// Default namespace for non-docker.io registries
namespace = "supabase"
}

return fmt.Sprintf("%s/%s/%s:%s", registry, namespace, imageName, imageTag)
}

func DockerImagePull(ctx context.Context, imageTag string, w io.Writer) error {
Expand Down
46 changes: 46 additions & 0 deletions internal/utils/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,49 @@ func TestExecOnce(t *testing.T) {

// TODO: mock tcp hijack
}

func TestGetRegistryImageUrl(t *testing.T) {
t.Run("docker.io keeps provided namespace (library)", func(t *testing.T) {
viper.Set("INTERNAL_IMAGE_REGISTRY", "docker.io")

got := GetRegistryImageUrl("library/kong:2.8.1")
assert.Equal(t, "docker.io/library/kong:2.8.1", got)
})

t.Run("non-docker.io defaults namespace to supabase when no override", func(t *testing.T) {
viper.Set("INTERNAL_IMAGE_REGISTRY", "ghcr.io")

got := GetRegistryImageUrl("library/kong:2.8.1")
assert.Equal(t, "ghcr.io/supabase/kong:2.8.1", got)
})

t.Run("supabase namespace remains supabase on non-docker.io registry", func(t *testing.T) {
viper.Set("INTERNAL_IMAGE_REGISTRY", "ghcr.io")

got := GetRegistryImageUrl("supabase/postgres:17.6.1.074")
assert.Equal(t, "ghcr.io/supabase/postgres:17.6.1.074", got)
})

t.Run("namespace override gets applied", func(t *testing.T) {
viper.Set("INTERNAL_IMAGE_REGISTRY", "ghcr.io")
viper.Set("INTERNAL_IMAGE_NAMESPACE_POSTGREST", "custom")

got := GetRegistryImageUrl("postgrest/postgrest:v14.3")
assert.Equal(t, "ghcr.io/custom/postgrest:v14.3", got)
})

t.Run("invalid image format returns as-is", func(t *testing.T) {
viper.Set("INTERNAL_IMAGE_REGISTRY", "docker.io")

got := GetRegistryImageUrl("postgrest")
assert.Equal(t, "postgrest", got)
})

t.Run("overrides kong namespace to docker/library on public.ecr.aws", func(t *testing.T) {
viper.Set("INTERNAL_IMAGE_REGISTRY", "public.ecr.aws")
viper.Set("INTERNAL_IMAGE_NAMESPACE_KONG", "docker/library")

got := GetRegistryImageUrl("library/kong:2.8.1")
assert.Equal(t, "public.ecr.aws/docker/library/kong:2.8.1", got)
})
}
Loading