Skip to content

Commit c5a9af2

Browse files
author
ElasticClaw
committed
fix(registry): preserve blocked and insecure registries when converting v1 registries.conf
Previously the legacy v1 fallback wrote an empty v2 registries.conf, which discarded host blocked-registry and insecure-registry policy. Now we parse the host v1 file, convert it to v2, and validate the result, falling back to an empty file only if the v1 file has no settings or conversion fails.
1 parent 7eb9a50 commit c5a9af2

2 files changed

Lines changed: 125 additions & 0 deletions

File tree

pkg/docker/registry/registriesconf.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"path/filepath"
66
"sync"
77

8+
"github.com/BurntSushi/toml"
89
"github.com/pkg/errors"
910
"go.podman.io/image/v5/pkg/sysregistriesv2"
1011
"go.podman.io/image/v5/types"
@@ -52,6 +53,14 @@ func findDefaultRegistriesConfPath() (string, error) {
5253
if isValidV2RegistriesConf(hostPath) {
5354
return hostPath, nil
5455
}
56+
// Host has a v1 or otherwise invalid config. Try to preserve its
57+
// blocked/insecure/search registry settings by converting to v2.
58+
convertedPath, err := convertHostRegistriesConfToV2(hostPath)
59+
if err == nil {
60+
return convertedPath, nil
61+
}
62+
// If conversion fails, fall back to an empty v2 file rather than
63+
// letting the operation fail entirely.
5564
}
5665

5766
return writeDefaultRegistriesConf()
@@ -63,6 +72,52 @@ func isValidV2RegistriesConf(path string) bool {
6372
return err == nil
6473
}
6574

75+
func convertHostRegistriesConfToV2(hostPath string) (string, error) {
76+
data, err := os.ReadFile(hostPath)
77+
if err != nil {
78+
return "", errors.Wrap(err, "failed to read host registries.conf")
79+
}
80+
81+
var v1 sysregistriesv2.V1RegistriesConf
82+
if err := toml.Unmarshal(data, &v1); err != nil {
83+
return "", errors.Wrap(err, "failed to parse v1 registries.conf")
84+
}
85+
if !v1.Nonempty() {
86+
// Nothing to preserve; use the empty fallback.
87+
return "", errors.New("v1 registries.conf is empty")
88+
}
89+
90+
v2, err := v1.ConvertToV2()
91+
if err != nil {
92+
return "", errors.Wrap(err, "failed to convert v1 registries.conf to v2")
93+
}
94+
95+
dir, err := os.MkdirTemp("", "kots-registries-conf")
96+
if err != nil {
97+
return "", errors.Wrap(err, "failed to create registries.conf temp dir")
98+
}
99+
path := filepath.Join(dir, "registries.conf")
100+
101+
f, err := os.Create(path)
102+
if err != nil {
103+
return "", errors.Wrap(err, "failed to create converted registries.conf")
104+
}
105+
defer f.Close()
106+
107+
enc := toml.NewEncoder(f)
108+
if err := enc.Encode(v2); err != nil {
109+
return "", errors.Wrap(err, "failed to encode converted registries.conf")
110+
}
111+
112+
// Validate that the generated v2 file can be loaded by the library.
113+
ctx := &types.SystemContext{SystemRegistriesConfPath: path}
114+
if _, err := sysregistriesv2.TryUpdatingCache(ctx); err != nil {
115+
return "", errors.Wrap(err, "generated v2 registries.conf is invalid")
116+
}
117+
118+
return path, nil
119+
}
120+
66121
func writeDefaultRegistriesConf() (string, error) {
67122
dir, err := os.MkdirTemp("", "kots-registries-conf")
68123
if err != nil {

pkg/docker/registry/registriesconf_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package registry
33
import (
44
"os"
55
"path/filepath"
6+
"strings"
67
"testing"
78

89
"github.com/stretchr/testify/assert"
910
"github.com/stretchr/testify/require"
11+
"go.podman.io/image/v5/pkg/sysregistriesv2"
1012
"go.podman.io/image/v5/types"
1113
)
1214

@@ -44,6 +46,74 @@ registries = ['registry.access.redhat.com']
4446
require.NoError(t, SetSystemRegistriesConfPath(sys))
4547
assert.NotEqual(t, hostPath, sys.SystemRegistriesConfPath)
4648
assert.NotEmpty(t, sys.SystemRegistriesConfPath)
49+
50+
// Verify the generated v2 file preserves the search registry.
51+
ctx := &types.SystemContext{SystemRegistriesConfPath: sys.SystemRegistriesConfPath}
52+
v2, err := sysregistriesv2.TryUpdatingCache(ctx)
53+
require.NoError(t, err)
54+
assert.Contains(t, v2.UnqualifiedSearchRegistries, "registry.access.redhat.com")
55+
}
56+
57+
func TestSetSystemRegistriesConfPath_PreservesV1BlockedAndInsecureRegistries(t *testing.T) {
58+
resetRegistriesConfPathOnce()
59+
60+
dir := t.TempDir()
61+
hostPath := filepath.Join(dir, "registries.conf")
62+
content := `[registries.search]
63+
registries = ['registry.access.redhat.com']
64+
65+
[registries.block]
66+
registries = ['docker.io', 'registry.hub.docker.com']
67+
68+
[registries.insecure]
69+
registries = ['insecure-registry.example.com']
70+
`
71+
require.NoError(t, os.WriteFile(hostPath, []byte(content), 0644))
72+
73+
t.Setenv("CONTAINERS_REGISTRIES_CONF", hostPath)
74+
75+
sys := &types.SystemContext{}
76+
require.NoError(t, SetSystemRegistriesConfPath(sys))
77+
assert.NotEqual(t, hostPath, sys.SystemRegistriesConfPath)
78+
assert.NotEmpty(t, sys.SystemRegistriesConfPath)
79+
80+
ctx := &types.SystemContext{SystemRegistriesConfPath: sys.SystemRegistriesConfPath}
81+
82+
reg, err := sysregistriesv2.FindRegistry(ctx, "docker.io/library/busybox")
83+
require.NoError(t, err)
84+
require.NotNil(t, reg)
85+
assert.True(t, reg.Blocked, "expected docker.io to be blocked")
86+
87+
reg, err = sysregistriesv2.FindRegistry(ctx, "insecure-registry.example.com/app:latest")
88+
require.NoError(t, err)
89+
require.NotNil(t, reg)
90+
assert.True(t, reg.Insecure, "expected insecure-registry.example.com to be insecure")
91+
92+
v2, err := sysregistriesv2.TryUpdatingCache(ctx)
93+
require.NoError(t, err)
94+
assert.Contains(t, v2.UnqualifiedSearchRegistries, "registry.access.redhat.com")
95+
}
96+
97+
func TestSetSystemRegistriesConfPath_FallsBackToEmptyV2WhenV1ConfigIsEmpty(t *testing.T) {
98+
resetRegistriesConfPathOnce()
99+
100+
dir := t.TempDir()
101+
hostPath := filepath.Join(dir, "registries.conf")
102+
content := `[registries.search]
103+
registries = []
104+
`
105+
require.NoError(t, os.WriteFile(hostPath, []byte(content), 0644))
106+
107+
t.Setenv("CONTAINERS_REGISTRIES_CONF", hostPath)
108+
109+
sys := &types.SystemContext{}
110+
require.NoError(t, SetSystemRegistriesConfPath(sys))
111+
assert.NotEqual(t, hostPath, sys.SystemRegistriesConfPath)
112+
assert.NotEmpty(t, sys.SystemRegistriesConfPath)
113+
114+
data, err := os.ReadFile(sys.SystemRegistriesConfPath)
115+
require.NoError(t, err)
116+
assert.Empty(t, strings.TrimSpace(string(data)))
47117
}
48118

49119
func TestSetSystemRegistriesConfPath_FallsBackWhenHostConfigMissing(t *testing.T) {

0 commit comments

Comments
 (0)