mirror of
https://github.com/helmfile/helmfile.git
synced 2026-10-19 15:53:15 +02:00
fix: ensure OCI registry login when SkipRepos is set (#2701)
* fix: ensure OCI registry login when SkipRepos is set (#1847) Commands like build, status, list, and show-dag set SkipRepos: true to avoid slow helm repo add/update for classic repos. However, this also skipped helm registry login for OCI registries, causing 401 Unauthorized errors when pulling OCI charts. Add a variadic SyncOption parameter (backward compatible) with WithOCIOnly() that limits repo processing to OCI registries only. When skipRepos is true, callers now pass WithOCIOnly() so that OCI authentication still happens before chart pulls. Signed-off-by: yxxhero <aiopsclub@163.com> * fix: reword OCI login comments per review feedback RegistryLogin is a no-op when credentials are not configured, so the word 'always' was misleading. Clarify that login is only needed when credentials are present. Signed-off-by: yxxhero <aiopsclub@163.com> * fix: skip OCI login for commands that don't pull charts Commands like 'list' and 'write-values' skip chart preparation entirely, so OCI registry login is unnecessary for them. Extract the skip-command list into a shared variable and use it to gate OCI-only login in WithPreparedCharts. Signed-off-by: yxxhero <aiopsclub@163.com> * docs: clarify commandsSkipChartPrep comment per review feedback Clarify that these commands only skip OCI login when skipRepos is true; when skipRepos is false, SyncReposOnce still runs normally for all repos. Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
+25
-1
@@ -758,13 +758,37 @@ type RepoUpdater interface {
|
||||
RegistryLogin(name, username, password, caFile, certFile, keyFile string, skipTLSVerify bool) error
|
||||
}
|
||||
|
||||
func (st *HelmState) SyncRepos(helm RepoUpdater, shouldSkip map[string]bool) ([]string, error) {
|
||||
// SyncOption configures SyncRepos behavior.
|
||||
type SyncOption func(*syncConfig)
|
||||
|
||||
type syncConfig struct {
|
||||
ociOnly bool
|
||||
}
|
||||
|
||||
// WithOCIOnly limits repo processing to OCI registries (helm registry login),
|
||||
// skipping classic repo add/update. This allows callers that skip classic repos
|
||||
// to still authenticate with OCI registries before chart pulls (issue #1847).
|
||||
func WithOCIOnly() SyncOption {
|
||||
return func(c *syncConfig) {
|
||||
c.ociOnly = true
|
||||
}
|
||||
}
|
||||
|
||||
func (st *HelmState) SyncRepos(helm RepoUpdater, shouldSkip map[string]bool, opts ...SyncOption) ([]string, error) {
|
||||
cfg := syncConfig{}
|
||||
for _, o := range opts {
|
||||
o(&cfg)
|
||||
}
|
||||
|
||||
var updated []string
|
||||
|
||||
for _, repo := range st.Repositories {
|
||||
if shouldSkip[repo.Name] {
|
||||
continue
|
||||
}
|
||||
if cfg.ociOnly && !repo.OCI {
|
||||
continue
|
||||
}
|
||||
username, password := gatherUsernamePassword(repo.Name, repo.Username, repo.Password)
|
||||
var err error
|
||||
if repo.OCI {
|
||||
|
||||
@@ -4421,6 +4421,80 @@ func TestHelmState_SyncRepos_OCI(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelmState_SyncRepos_OCIOnly(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repos []RepositorySpec
|
||||
opts []SyncOption
|
||||
wantRegistryLoginHost string
|
||||
wantRepoSet bool
|
||||
}{
|
||||
{
|
||||
name: "WithOCIOnly logs into OCI registry",
|
||||
repos: []RepositorySpec{
|
||||
{
|
||||
Name: "ociregistry",
|
||||
URL: "quay.io/myorg",
|
||||
OCI: true,
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
},
|
||||
},
|
||||
opts: []SyncOption{WithOCIOnly()},
|
||||
wantRegistryLoginHost: "quay.io",
|
||||
wantRepoSet: false,
|
||||
},
|
||||
{
|
||||
name: "WithOCIOnly skips non-OCI repo",
|
||||
repos: []RepositorySpec{
|
||||
{
|
||||
Name: "stable",
|
||||
URL: "https://charts.helm.sh/stable",
|
||||
},
|
||||
},
|
||||
opts: []SyncOption{WithOCIOnly()},
|
||||
wantRegistryLoginHost: "",
|
||||
wantRepoSet: false,
|
||||
},
|
||||
{
|
||||
name: "without options processes non-OCI repo via AddRepo",
|
||||
repos: []RepositorySpec{
|
||||
{
|
||||
Name: "stable",
|
||||
URL: "https://charts.helm.sh/stable",
|
||||
},
|
||||
},
|
||||
opts: nil,
|
||||
wantRegistryLoginHost: "",
|
||||
wantRepoSet: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
helm := &exectest.Helm{}
|
||||
state := &HelmState{
|
||||
ReleaseSetSpec: ReleaseSetSpec{
|
||||
Repositories: tt.repos,
|
||||
},
|
||||
}
|
||||
_, err := state.SyncRepos(helm, map[string]bool{}, tt.opts...)
|
||||
if err != nil {
|
||||
t.Errorf("SyncRepos() error = %v", err)
|
||||
return
|
||||
}
|
||||
if tt.wantRegistryLoginHost != "" && helm.RegistryLoginHost != tt.wantRegistryLoginHost {
|
||||
t.Errorf("RegistryLogin host = %q, want %q", helm.RegistryLoginHost, tt.wantRegistryLoginHost)
|
||||
}
|
||||
if tt.wantRegistryLoginHost == "" && helm.RegistryLoginHost != "" {
|
||||
t.Errorf("RegistryLogin should not have been called, got host = %q", helm.RegistryLoginHost)
|
||||
}
|
||||
if len(helm.Repo) > 0 != tt.wantRepoSet {
|
||||
t.Errorf("AddRepo called = %v, want %v", len(helm.Repo) > 0, tt.wantRepoSet)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateOutputFilePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
envName string
|
||||
|
||||
Reference in New Issue
Block a user