Skip to content
4 changes: 4 additions & 0 deletions io.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func parseRegistriesFromDir(dir string) []Registry {

}

// Skip registries without auth strategy, as they are considered public
if registry.AuthStrategy == "" {
return nil
}
if mapRegistriesByHost[registry.RegistryHost] {

panic(fmt.Sprintf("Duplicated registry %s", registry.RegistryHost))
Expand Down
82 changes: 80 additions & 2 deletions types.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,88 @@
package main

import "encoding/json"

type Registry struct {
Name string `yaml:"name" json:"name"`
RegistryHost string `yaml:"registry" json:"registry"`
AuthStrategy string `yaml:"auth_strategy" json:"auth_strategy"`
RegistryHost string `yaml:"url,omitempty" json:"registry,omitempty"`
AuthStrategy string `yaml:"auth_strategy" json:"auth_strategy,omitempty"`
Default bool `yaml:"default" json:"default"`
Comment thread
jalvarezit marked this conversation as resolved.
ImageTypes []string `yaml:"image_types" json:"image_types"`
BasePaths map[string]string `yaml:"base_paths" json:"base_paths"`
Comment thread
jalvarezit marked this conversation as resolved.
}

// Custom YAML unmarshaling to support both 'registry' and 'url' mapping to RegistryHost
func (r *Registry) UnmarshalYAML(unmarshal func(interface{}) error) error {
Comment thread
jalvarezit marked this conversation as resolved.
var aux map[string]interface{}
if err := unmarshal(&aux); err != nil {
return err
}
if name, ok := aux["name"].(string); ok {
r.Name = name
}
if reg, ok := aux["registry"].(string); ok {
r.RegistryHost = reg
} else if url, ok := aux["url"].(string); ok {
r.RegistryHost = url
}
Comment on lines +23 to +27
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UnmarshalYAML accepts both registry and url, but if both keys are present it silently prefers registry and discards url. That means the schema’s oneOf mutual-exclusion rule won’t actually be enforced (the validator never sees both). If the intent is “exactly one of these keys”, detect this during YAML unmarshal and return an error when both are set.

Copilot uses AI. Check for mistakes.
if auth, ok := aux["auth_strategy"].(string); ok {
r.AuthStrategy = auth
}
if def, ok := aux["default"].(bool); ok {
r.Default = def
}
if img, ok := aux["image_types"].([]interface{}); ok {
r.ImageTypes = make([]string, len(img))
for i, v := range img {
if s, ok := v.(string); ok {
r.ImageTypes[i] = s
}
}
}
if bp, ok := aux["base_paths"].(map[string]interface{}); ok {
r.BasePaths = make(map[string]string)
for k, v := range bp {
if s, ok := v.(string); ok {
r.BasePaths[k] = s
}
}
}
return nil
}

// Custom JSON unmarshaling to support both 'registry' and 'url' mapping to Url
func (r *Registry) UnmarshalJSON(data []byte) error {
var aux map[string]interface{}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if name, ok := aux["name"].(string); ok {
r.Name = name
}
if reg, ok := aux["registry"].(string); ok {
r.RegistryHost = reg
}
Comment thread
jalvarezit marked this conversation as resolved.
if auth, ok := aux["auth_strategy"].(string); ok {
r.AuthStrategy = auth
}
if def, ok := aux["default"].(bool); ok {
r.Default = def
}
if img, ok := aux["image_types"].([]interface{}); ok {
r.ImageTypes = make([]string, len(img))
for i, v := range img {
if s, ok := v.(string); ok {
r.ImageTypes[i] = s
}
}
}
if bp, ok := aux["base_paths"].(map[string]interface{}); ok {
r.BasePaths = make(map[string]string)
for k, v := range bp {
if s, ok := v.(string); ok {
r.BasePaths[k] = s
}
}
}
Comment thread
jalvarezit marked this conversation as resolved.
return nil
}
8 changes: 4 additions & 4 deletions validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@ const SCHEMA = `{
"properties": {
"name": { "type": "string" },
"registry": { "type": "string" },
"url": { "type": "string" },
"image_types": {
"type": "array",
"type": ["array", "null"],
"items": { "type": "string", "enum": ["snapshots", "releases"] }
},
"default": { "type": "boolean" },
"auth_strategy": {
"type": "string",
"enum": ["aws_oidc", "azure_oidc", "generic", "ghcr", "dockerhub"]
},
"base_paths": {
"type": "object",
"type": ["object", "null"],
"properties": {
"services": { "type": "string" },
"charts": { "type": "string" }
},
"required": ["services", "charts"]
}
},
"required": ["name", "registry", "image_types", "default", "auth_strategy", "base_paths"]
"required": ["name", "registry"]
}`

func validate() {
Expand Down
Loading