From 8d93bbbc220b28fc6249c5729ffd668644bbebb1 Mon Sep 17 00:00:00 2001 From: Atharva Joshi Date: Sat, 12 Sep 2026 17:45:43 +0530 Subject: [PATCH] fix: validate capability configuration before cluster creation Signed-off-by: Atharva Joshi --- pkg/cfn/builder/capability.go | 9 +++++++ pkg/cfn/builder/capability_test.go | 42 ++++++++++++++++++++++++++++++ pkg/ctl/cmdutils/configfile.go | 7 ++++- 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 pkg/cfn/builder/capability_test.go diff --git a/pkg/cfn/builder/capability.go b/pkg/cfn/builder/capability.go index 9b70206b19..ce8d776bf2 100644 --- a/pkg/cfn/builder/capability.go +++ b/pkg/cfn/builder/capability.go @@ -1,6 +1,8 @@ package builder import ( + "fmt" + gfneks "github.com/weaveworks/eksctl/pkg/goformation/cloudformation/eks" gfnt "github.com/weaveworks/eksctl/pkg/goformation/cloudformation/types" @@ -100,6 +102,13 @@ func convertConfiguration(config *api.CapabilityConfiguration) (*gfneks.Capabili } } + if config.ArgoCD.AWSIDC == nil { + // A typo in the config file (e.g. `awsIDC` instead of `awsIdc`) leaves + // AWSIDC nil because YAML is decoded case-sensitively via the JSON + // serializer; dereferencing it would panic instead of failing cleanly. + // See https://github.com/eksctl-io/eksctl/issues/8701. + return nil, fmt.Errorf("awsIdc configuration is required for ARGOCD capability") + } req.ArgoCd.AWSIDC = &gfneks.ArgoCDAWSIDC{ IDCInstanceARN: gfnt.NewString(config.ArgoCD.AWSIDC.IDCInstanceARN), } diff --git a/pkg/cfn/builder/capability_test.go b/pkg/cfn/builder/capability_test.go new file mode 100644 index 0000000000..f895c8ee76 --- /dev/null +++ b/pkg/cfn/builder/capability_test.go @@ -0,0 +1,42 @@ +package builder_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/cfn/builder" +) + +var _ = Describe("Capability", func() { + Describe("CapabilityResourceSet", func() { + var capability api.Capability + + BeforeEach(func() { + capability = api.Capability{ + Name: "my-capability", + Type: "ARGOCD", + Configuration: &api.CapabilityConfiguration{ + ArgoCD: &api.ArgoCDConfiguration{ + Namespace: "argocd", + }, + }, + } + }) + + It("renders AWSIDC configuration when provided", func() { + capability.Configuration.ArgoCD.AWSIDC = &api.ArgoCDAWSIDC{ + IDCInstanceARN: "arn:aws:sso:::instance/ssoins-123", + IDCRegion: "us-west-2", + } + rs := builder.NewCapabilityResourceSet("my-cluster", capability) + Expect(rs.AddAllResources()).To(Succeed()) + }) + + It("returns a clean error instead of panicking when AWSIDC is missing", func() { + rs := builder.NewCapabilityResourceSet("my-cluster", capability) + err := rs.AddAllResources() + Expect(err).To(MatchError(ContainSubstring("awsIdc configuration is required for ARGOCD capability"))) + }) + }) +}) diff --git a/pkg/ctl/cmdutils/configfile.go b/pkg/ctl/cmdutils/configfile.go index 0710d96bc6..197c57ff5d 100644 --- a/pkg/ctl/cmdutils/configfile.go +++ b/pkg/ctl/cmdutils/configfile.go @@ -313,6 +313,11 @@ func NewCreateClusterLoader(cmd *Cmd, ngFilter *filter.NodeGroupFilter, ng *api. return err } } + for _, capability := range clusterConfig.Capabilities { + if err := capability.Validate(); err != nil { + return err + } + } if clusterConfig.IsAutoModeEnabled() { if len(clusterConfig.NodeGroups) > 0 || len(clusterConfig.ManagedNodeGroups) > 0 { return errors.New("creation of managed or self-managed nodegroups is not supported during cluster creation " + @@ -1186,7 +1191,7 @@ func emptyConfigField(v reflect.Value) bool { return v.Uint() == 0 case reflect.String: return v.String() == "" - case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface, reflect.Chan: + case reflect.Pointer, reflect.Slice, reflect.Map, reflect.Interface, reflect.Chan: return v.IsNil() case reflect.Bool: return !v.Bool()