Repository: helm/helm
Pull request #10547 (2022-01-13 02:29:02)

Fix panic with OCI for install, upgrade, and show
When range support for OCI went in via #10527 it created a situation
where some lookups for a chart could cause a panic. This change
makes sure the registry client is available to lookup OCI charts

<!--  Thanks for sending a pull request!  Here are some tips for you:
1. Make sure to read the Contributing Guide before submitting your PR: https://github.com/helm/helm/blob/main/CONTRIBUTING.md
2. If this PR closes another issue, add 'closes #<issue number>' somewhere in the PR summary. GitHub will automatically close that issue when this PR gets merged. Alternatively, adding 'refs #<issue number>' will not close the issue, but help provide the reviewer more context.-->

**What this PR does / why we need it**:

**Special notes for your reviewer**:

**If applicable**:
- [ ] this PR contains documentation
- [ ] this PR contains unit tests
- [x] this PR has been tested for backwards compatibility



Patch:
diff --git a/cmd/helm/root.go b/cmd/helm/root.go
index be72bbb84..2888d14e2 100644
--- a/cmd/helm/root.go
+++ b/cmd/helm/root.go
@@ -165,7 +165,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
 		newCreateCmd(out),
 		newDependencyCmd(actionConfig, out),
 		newPullCmd(actionConfig, out),
-		newShowCmd(out),
+		newShowCmd(actionConfig, out),
 		newLintCmd(out),
 		newPackageCmd(out),
 		newRepoCmd(out),
diff --git a/cmd/helm/show.go b/cmd/helm/show.go
index 4640b3ccf..a479ccda5 100644
--- a/cmd/helm/show.go
+++ b/cmd/helm/show.go
@@ -56,8 +56,8 @@ This command inspects a chart (directory, file, or URL) and displays the content
 of the CustomResourceDefinition files
 `
 
-func newShowCmd(out io.Writer) *cobra.Command {
-	client := action.NewShow(action.ShowAll)
+func newShowCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
+	client := action.NewShowWithConfig(action.ShowAll, cfg)
 
 	showCommand := &cobra.Command{
 		Use:               "show",
diff --git a/pkg/action/install.go b/pkg/action/install.go
index 250dfae95..f0bbb5cb0 100644
--- a/pkg/action/install.go
+++ b/pkg/action/install.go
@@ -117,13 +117,20 @@ type ChartPathOptions struct {
 	Username              string // --username
 	Verify                bool   // --verify
 	Version               string // --version
+
+	// registryClient provides a registry client but is not added with
+	// options from a flag
+	registryClient *registry.Client
 }
 
 // NewInstall creates a new Install object with the given configuration.
 func NewInstall(cfg *Configuration) *Install {
-	return &Install{
+	in := &Install{
 		cfg: cfg,
 	}
+	in.ChartPathOptions.registryClient = cfg.RegistryClient
+
+	return in
 }
 
 func (i *Install) installCRDs(crds []chart.CRD) error {
@@ -662,6 +669,12 @@ OUTER:
 //
 // If 'verify' was set on ChartPathOptions, this will attempt to also verify the chart.
 func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (string, error) {
+	// If there is no registry client and the name is in an OCI registry return
+	// an error and a lookup will not occur.
+	if registry.IsOCI(name) && c.registryClient == nil {
+		return "", fmt.Errorf("unable to lookup chart %q, missing registry client", name)
+	}
+
 	name = strings.TrimSpace(name)
 	version := strings.TrimSpace(c.Version)
 
@@ -692,12 +705,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
 		},
 		RepositoryConfig: settings.RepositoryConfig,
 		RepositoryCache:  settings.RepositoryCache,
-	}
-
-	if registry.IsOCI(name) {
-		if version != "" {
-			dl.Options = append(dl.Options, getter.WithTagName(version))
-		}
+		RegistryClient:   c.registryClient,
 	}
 
 	if c.Verify {
diff --git a/pkg/action/show.go b/pkg/action/show.go
index 1e3da3bdc..9ba85234d 100644
--- a/pkg/action/show.go
+++ b/pkg/action/show.go
@@ -64,12 +64,24 @@ type Show struct {
 }
 
 // NewShow creates a new Show object with the given configuration.
+// Deprecated: Use NewShowWithConfig
+// TODO Helm 4: Fold NewShowWithConfig back into NewShow
 func NewShow(output ShowOutputFormat) *Show {
 	return &Show{
 		OutputFormat: output,
 	}
 }
 
+// NewShowWithConfig creates a new Show object with the given configuration.
+func NewShowWithConfig(output ShowOutputFormat, cfg *Configuration) *Show {
+	sh := &Show{
+		OutputFormat: output,
+	}
+	sh.ChartPathOptions.registryClient = cfg.RegistryClient
+
+	return sh
+}
+
 // Run executes 'helm show' against the given release.
 func (s *Show) Run(chartpath string) (string, error) {
 	if s.chart == nil {
diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go
index 1e7054118..e228f52dc 100644
--- a/pkg/action/upgrade.go
+++ b/pkg/action/upgrade.go
@@ -112,9 +112,12 @@ type resultMessage struct {
 
 // NewUpgrade creates a new Upgrade object with the given configuration.
 func NewUpgrade(cfg *Configuration) *Upgrade {
-	return &Upgrade{
+	up := &Upgrade{
 		cfg: cfg,
 	}
+	up.ChartPathOptions.registryClient = cfg.RegistryClient
+
+	return up
 }
 
 // Run executes the upgrade on the given release.


Test patch:
diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go
index 983bcfe05..8b617ea85 100644
--- a/pkg/action/show_test.go
+++ b/pkg/action/show_test.go
@@ -23,7 +23,8 @@ import (
 )
 
 func TestShow(t *testing.T) {
-	client := NewShow(ShowAll)
+	config := actionConfigFixture(t)
+	client := NewShowWithConfig(ShowAll, config)
 	client.chart = &chart.Chart{
 		Metadata: &chart.Metadata{Name: "alpine"},
 		Files: []*chart.File{