From 711a4eaf40a911b0864a01b99f59f62817443003 Mon Sep 17 00:00:00 2001 From: sergiochan Date: Tue, 10 Mar 2026 17:52:55 -0700 Subject: [PATCH] fix(action): avoid nil REST client getter panic when installing CRDs Signed-off-by: sergiochan --- pkg/action/install.go | 48 ++++++++++++++++++++------------------ pkg/action/install_test.go | 22 +++++++++++++++++ 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index f8f740005..8ae84a699 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -186,32 +186,34 @@ func (i *Install) installCRDs(crds []chart.CRD) error { return err } - // If we have already gathered the capabilities, we need to invalidate - // the cache so that the new CRDs are recognized. This should only be - // the case when an action configuration is reused for multiple actions, - // as otherwise it is later loaded by ourselves when getCapabilities - // is called later on in the installation process. - if i.cfg.Capabilities != nil { - discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() + if i.cfg.RESTClientGetter != nil { + // If we have already gathered the capabilities, we need to invalidate + // the cache so that the new CRDs are recognized. This should only be + // the case when an action configuration is reused for multiple actions, + // as otherwise it is later loaded by ourselves when getCapabilities + // is called later on in the installation process. + if i.cfg.Capabilities != nil { + discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() + if err != nil { + return err + } + if discoveryClient != nil { + i.cfg.Log("Clearing discovery cache") + discoveryClient.Invalidate() + _, _ = discoveryClient.ServerGroups() + } + } + + // Invalidate the REST mapper, since it will not have the new CRDs + // present. + restMapper, err := i.cfg.RESTClientGetter.ToRESTMapper() if err != nil { return err } - - i.cfg.Log("Clearing discovery cache") - discoveryClient.Invalidate() - - _, _ = discoveryClient.ServerGroups() - } - - // Invalidate the REST mapper, since it will not have the new CRDs - // present. - restMapper, err := i.cfg.RESTClientGetter.ToRESTMapper() - if err != nil { - return err - } - if resettable, ok := restMapper.(meta.ResettableRESTMapper); ok { - i.cfg.Log("Clearing REST mapper cache") - resettable.Reset() + if resettable, ok := restMapper.(meta.ResettableRESTMapper); ok { + i.cfg.Log("Clearing REST mapper cache") + resettable.Reset() + } } } return nil diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 300091eac..8f4cb4c5d 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -894,6 +894,28 @@ func TestNameAndChartGenerateName(t *testing.T) { } } +func TestInstallCRDsWithNilRESTClientGetter(t *testing.T) { + config := actionConfigFixture(t) + failingKubeClient := kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: io.Discard}, BuildDummy: true} + config.KubeClient = &failingKubeClient + config.RESTClientGetter = nil + instAction := NewInstall(config) + + crds := []chart.CRD{{ + Name: "test-crd", + File: &chart.File{ + Name: "crds/test-crd.yaml", + Data: []byte("kind: CustomResourceDefinition"), + }, + }} + + var err error + require.NotPanics(t, func() { + err = instAction.installCRDs(crds) + }) + require.NoError(t, err) +} + func TestInstallWithLabels(t *testing.T) { is := assert.New(t) instAction := installAction(t)