diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 2b7d3e40a..08f0d3232 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -736,31 +736,50 @@ func (m *Manager) findChartURL(name, version, repoURL, repoName string, repos ma // First, try to look up the repository by name. This ensures correct // credentials are used when multiple repositories share the same URL. + // When a repo name is provided and exists in the repos map, the lookup + // is authoritative: if the chart is not found or URL resolution fails, + // an error is returned rather than silently falling back to URL-based + // scanning. If the named repo is not in the repos map (e.g. repos from + // ensureMissingRepos are not persisted to repositories.yaml), we fall + // through to URL-based scanning for backward compatibility. if repoName != "" { if cr, ok := repos[repoName]; ok { var entry repo.ChartVersions entry, err = findEntryByName(name, cr) - if err == nil { - var ve *repo.ChartVersion - ve, err = findVersionedEntry(version, entry) - if err == nil { - url, err = repo.ResolveReferenceURL(cr.Config.URL, ve.URLs[0]) - if err == nil { - username = cr.Config.Username - password = cr.Config.Password - passCredentialsAll = cr.Config.PassCredentialsAll - insecureSkipTLSVerify = cr.Config.InsecureSkipTLSVerify - caFile = cr.Config.CAFile - certFile = cr.Config.CertFile - keyFile = cr.Config.KeyFile - return - } - } + if err != nil { + err = fmt.Errorf("chart %q not found in repository %q", name, repoName) + return + } + + var ve *repo.ChartVersion + ve, err = findVersionedEntry(version, entry) + if err != nil { + err = fmt.Errorf("chart %q version %q not found in repository %q", name, version, repoName) + return } + + url, err = repo.ResolveReferenceURL(cr.Config.URL, ve.URLs[0]) + if err != nil { + return + } + + username = cr.Config.Username + password = cr.Config.Password + passCredentialsAll = cr.Config.PassCredentialsAll + insecureSkipTLSVerify = cr.Config.InsecureSkipTLSVerify + caFile = cr.Config.CAFile + certFile = cr.Config.CertFile + keyFile = cr.Config.KeyFile + return } + // Repo name provided but not in the repos map. + // Fall through to URL-based scanning for backward compatibility + // (handles repos generated by ensureMissingRepos). } - // Fall back to scanning repos by URL for backward compatibility. + // Fall back to scanning repos by URL for backward compatibility + // (only when no repo name was specified, or the named repo is not in + // the repos map). for _, cr := range repos { if urlutil.Equal(repoURL, cr.Config.URL) { var entry repo.ChartVersions diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index 0b1c4db9a..cd51b645a 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -202,9 +202,6 @@ repositories: t.Fatal(err) } - // Find with repo-alias-1 and a repoURL that differs from cr.Config.URL - // (no trailing slash vs with trailing slash). Should still resolve correctly - // because it uses cr.Config.URL as the base for relative chart URLs. repoURL := "http://example.com/charts" name := "alpine" version := "0.1.0" @@ -261,6 +258,29 @@ repositories: if username == "" { t.Error("Expected non-empty username from URL-based fallback") } + + // --- Authoritative name-based lookup: error cases --- + + // Repo name provided but not in repos map: falls through to URL scan + // (backward compatibility for repos generated by ensureMissingRepos). + _, _, _, _, _, _, _, _, err = m.findChartURL(name, version, repoURL, "nonexistent", repos) + if err != nil { + t.Errorf("Expected fallback to URL scan for repo not in map, got error: %v", err) + } + + // Repo name valid but chart not found in that specific repo: must error, + // must not fall through to URL-based scanning. + _, _, _, _, _, _, _, _, err = m.findChartURL("nonexistent-chart", version, repoURL, "repo-alias-1", repos) + if err == nil { + t.Error("Expected error for nonexistent chart in named repo, got nil") + } + + // Repo name valid, chart exists, but version not found: must error, + // must not fall through to URL-based scanning. + _, _, _, _, _, _, _, _, err = m.findChartURL(name, "99.99.99", repoURL, "repo-alias-1", repos) + if err == nil { + t.Error("Expected error for nonexistent version in named repo, got nil") + } } func TestGetRepoNames(t *testing.T) {