From 1f5851cff21b39d94b5e95fe0a315505c1e389a4 Mon Sep 17 00:00:00 2001 From: richardsonnick Date: Tue, 16 Jun 2026 18:05:58 +0000 Subject: [PATCH 1/2] Add E2E test for the TLSAdherence openshift/api field --- test/extended/apiserver/tls_adherence.go | 148 +++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 test/extended/apiserver/tls_adherence.go diff --git a/test/extended/apiserver/tls_adherence.go b/test/extended/apiserver/tls_adherence.go new file mode 100644 index 000000000000..78b8689d9c50 --- /dev/null +++ b/test/extended/apiserver/tls_adherence.go @@ -0,0 +1,148 @@ +package apiserver + +import ( + "context" + "fmt" + + g "github.com/onsi/ginkgo/v2" + o "github.com/onsi/gomega" + configv1 "github.com/openshift/api/config/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + exutil "github.com/openshift/origin/test/extended/util" +) + +// tlsAdherenceFeatureGateName is the name of the TLSAdherence feature gate as it +// appears in featuregate/cluster .status.featureGates[].enabled[].name. +const tlsAdherenceFeatureGateName = configv1.FeatureGateName("TLSAdherence") + +// isTLSAdherenceFeatureGateEnabled returns true when the TLSAdherence feature gate is +// listed as enabled in the featuregate/cluster status. +func isTLSAdherenceFeatureGateEnabled(ctx context.Context, oc *exutil.CLI) (bool, error) { + fg, err := oc.AdminConfigClient().ConfigV1().FeatureGates().Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return false, fmt.Errorf("failed to get featuregate/cluster: %w", err) + } + for _, featureGateValues := range fg.Status.FeatureGates { + for _, enabledGate := range featureGateValues.Enabled { + if enabledGate.Name == tlsAdherenceFeatureGateName { + return true, nil + } + } + } + return false, nil +} + +// These tests verify the TLSAdherence feature gate and the spec.tlsAdherence field on +// apiservers/cluster (config.openshift.io/v1). They are gated by [OCPFeatureGate:TLSAdherence] +// for automatic pre-run filtering and include [FeatureGate:TLSAdherence] in each It description +// so the test name matches the pattern queried by the openshift/api verify-feature-promotion +// CI check in Sippy. +var _ = g.Describe("[sig-api-machinery][OCPFeatureGate:TLSAdherence][Feature:TLSAdherence] TLSAdherence apiservers/cluster", func() { + defer g.GinkgoRecover() + + oc := exutil.NewCLI("tls-adherence") + + g.BeforeEach(func(ctx context.Context) { + isMicroShift, err := exutil.IsMicroShiftCluster(oc.AdminKubeClient()) + o.Expect(err).NotTo(o.HaveOccurred()) + isHyperShift, err := exutil.IsHypershift(ctx, oc.AdminConfigClient()) + o.Expect(err).NotTo(o.HaveOccurred()) + if isMicroShift || isHyperShift { + g.Skip("TLSAdherence is not applicable to MicroShift or HyperShift clusters") + } + + enabled, err := isTLSAdherenceFeatureGateEnabled(ctx, oc) + o.Expect(err).NotTo(o.HaveOccurred()) + if !enabled { + g.Skip("TLSAdherence feature gate is not enabled on this cluster") + } + }) + + // Test 1 – verify the feature gate itself is active. + g.It("[FeatureGate:TLSAdherence] should have TLSAdherence listed as enabled in featuregate/cluster status [apigroup:config.openshift.io]", func(ctx context.Context) { + fg, err := oc.AdminConfigClient().ConfigV1().FeatureGates().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to get featuregate/cluster") + + found := false + for _, featureGateValues := range fg.Status.FeatureGates { + for _, enabledGate := range featureGateValues.Enabled { + if enabledGate.Name == tlsAdherenceFeatureGateName { + found = true + break + } + } + if found { + break + } + } + o.Expect(found).To(o.BeTrue(), + "TLSAdherence must appear in featuregate/cluster .status.featureGates[].enabled[].name") + }) + + // Test 2 – verify the API server accepts and reflects StrictAllComponents via dry-run. + g.It("[FeatureGate:TLSAdherence] should accept and reflect spec.tlsAdherence StrictAllComponents on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { + current, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to get apiservers/cluster") + + desired := current.DeepCopy() + desired.Spec.TLSAdherence = configv1.TLSAdherencePolicyStrictAllComponents + + result, err := oc.AdminConfigClient().ConfigV1().APIServers().Update(ctx, desired, metav1.UpdateOptions{ + DryRun: []string{metav1.DryRunAll}, + }) + o.Expect(err).NotTo(o.HaveOccurred(), + "apiservers/cluster should accept spec.tlsAdherence=StrictAllComponents") + o.Expect(result.Spec.TLSAdherence).To( + o.Equal(configv1.TLSAdherencePolicyStrictAllComponents), + "apiservers/cluster should reflect spec.tlsAdherence=StrictAllComponents") + }) + + // Test 3 – verify the API server accepts and reflects LegacyAdheringComponentsOnly via dry-run. + g.It("[FeatureGate:TLSAdherence] should accept and reflect spec.tlsAdherence LegacyAdheringComponentsOnly on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { + current, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to get apiservers/cluster") + + desired := current.DeepCopy() + desired.Spec.TLSAdherence = configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly + + result, err := oc.AdminConfigClient().ConfigV1().APIServers().Update(ctx, desired, metav1.UpdateOptions{ + DryRun: []string{metav1.DryRunAll}, + }) + o.Expect(err).NotTo(o.HaveOccurred(), + "apiservers/cluster should accept spec.tlsAdherence=LegacyAdheringComponentsOnly") + o.Expect(result.Spec.TLSAdherence).To( + o.Equal(configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly), + "apiservers/cluster should reflect spec.tlsAdherence=LegacyAdheringComponentsOnly") + }) + + // Test 4 – verify the current spec.tlsAdherence value (when set) is a recognised valid value. + g.It("[FeatureGate:TLSAdherence] should have a valid spec.tlsAdherence value on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { + apiServer, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to get apiservers/cluster") + + validValues := []configv1.TLSAdherencePolicy{ + configv1.TLSAdherencePolicyNoOpinion, + configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly, + configv1.TLSAdherencePolicyStrictAllComponents, + } + o.Expect(apiServer.Spec.TLSAdherence).To( + o.BeElementOf(validValues), + "apiservers/cluster spec.tlsAdherence must be one of the defined TLSAdherencePolicy values") + }) + + // Test 5 – verify that no cluster operator is degraded when the TLSAdherence feature gate is active. + g.It("[FeatureGate:TLSAdherence] should not have any degraded cluster operators [apigroup:config.openshift.io]", func(ctx context.Context) { + coList, err := oc.AdminConfigClient().ConfigV1().ClusterOperators().List(ctx, metav1.ListOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list clusteroperators") + + for _, co := range coList.Items { + for _, condition := range co.Status.Conditions { + if condition.Type == configv1.OperatorDegraded && condition.Status == configv1.ConditionTrue { + g.Fail(fmt.Sprintf("cluster operator %q is degraded: %s: %s", + co.Name, condition.Reason, condition.Message)) + } + } + } + }) +}) From e65c04c221a89d4a35d3943654131cdf18efbf42 Mon Sep 17 00:00:00 2001 From: richardsonnick Date: Tue, 16 Jun 2026 19:02:37 +0000 Subject: [PATCH 2/2] remove hypershift check --- test/extended/apiserver/tls.go | 17 ++++- test/extended/apiserver/tls_adherence.go | 97 ++++++++---------------- 2 files changed, 44 insertions(+), 70 deletions(-) diff --git a/test/extended/apiserver/tls.go b/test/extended/apiserver/tls.go index 58ac08e1524d..612387341ffa 100644 --- a/test/extended/apiserver/tls.go +++ b/test/extended/apiserver/tls.go @@ -47,7 +47,13 @@ var _ = g.Describe("[sig-api-machinery][Feature:APIServer]", func() { } }) - g.It("TestTLSMinimumVersions", func() { + g.It("TestTLSMinimumVersions [FeatureGate:TLSAdherence] [apigroup:config.openshift.io]", func() { + ctx := context.Background() + enabled, err := isTLSAdherenceFeatureGateEnabled(ctx, oc) + o.Expect(err).NotTo(o.HaveOccurred()) + if !enabled { + g.Skip("TLSAdherence feature gate is not enabled on this cluster") + } g.By("Getting the APIServer configuration") config, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) @@ -111,10 +117,15 @@ var _ = g.Describe("[sig-api-machinery][Feature:APIServer]", func() { o.Expect(err).NotTo(o.HaveOccurred()) }) - g.It("TestTLSDefaults", func() { + g.It("TestTLSDefaults [FeatureGate:TLSAdherence] [apigroup:config.openshift.io]", func() { + enabled, err := isTLSAdherenceFeatureGateEnabled(context.Background(), oc) + o.Expect(err).NotTo(o.HaveOccurred()) + if !enabled { + g.Skip("TLSAdherence feature gate is not enabled on this cluster") + } t := g.GinkgoT() - _, err := e2e.LoadClientset(true) + _, err = e2e.LoadClientset(true) o.Expect(err).NotTo(o.HaveOccurred()) g.By("Getting the APIServer config") diff --git a/test/extended/apiserver/tls_adherence.go b/test/extended/apiserver/tls_adherence.go index 78b8689d9c50..9f2d7865bb6e 100644 --- a/test/extended/apiserver/tls_adherence.go +++ b/test/extended/apiserver/tls_adherence.go @@ -7,6 +7,7 @@ import ( g "github.com/onsi/ginkgo/v2" o "github.com/onsi/gomega" configv1 "github.com/openshift/api/config/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" exutil "github.com/openshift/origin/test/extended/util" @@ -44,14 +45,6 @@ var _ = g.Describe("[sig-api-machinery][OCPFeatureGate:TLSAdherence][Feature:TLS oc := exutil.NewCLI("tls-adherence") g.BeforeEach(func(ctx context.Context) { - isMicroShift, err := exutil.IsMicroShiftCluster(oc.AdminKubeClient()) - o.Expect(err).NotTo(o.HaveOccurred()) - isHyperShift, err := exutil.IsHypershift(ctx, oc.AdminConfigClient()) - o.Expect(err).NotTo(o.HaveOccurred()) - if isMicroShift || isHyperShift { - g.Skip("TLSAdherence is not applicable to MicroShift or HyperShift clusters") - } - enabled, err := isTLSAdherenceFeatureGateEnabled(ctx, oc) o.Expect(err).NotTo(o.HaveOccurred()) if !enabled { @@ -59,79 +52,49 @@ var _ = g.Describe("[sig-api-machinery][OCPFeatureGate:TLSAdherence][Feature:TLS } }) - // Test 1 – verify the feature gate itself is active. - g.It("[FeatureGate:TLSAdherence] should have TLSAdherence listed as enabled in featuregate/cluster status [apigroup:config.openshift.io]", func(ctx context.Context) { - fg, err := oc.AdminConfigClient().ConfigV1().FeatureGates().Get(ctx, "cluster", metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred(), "failed to get featuregate/cluster") - - found := false - for _, featureGateValues := range fg.Status.FeatureGates { - for _, enabledGate := range featureGateValues.Enabled { - if enabledGate.Name == tlsAdherenceFeatureGateName { - found = true - break - } - } - if found { - break - } - } - o.Expect(found).To(o.BeTrue(), - "TLSAdherence must appear in featuregate/cluster .status.featureGates[].enabled[].name") - }) - - // Test 2 – verify the API server accepts and reflects StrictAllComponents via dry-run. - g.It("[FeatureGate:TLSAdherence] should accept and reflect spec.tlsAdherence StrictAllComponents on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { + // Test 1 – verify the API rejects an unrecognised spec.tlsAdherence value. + g.It("[FeatureGate:TLSAdherence] should reject an invalid spec.tlsAdherence value on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { current, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) o.Expect(err).NotTo(o.HaveOccurred(), "failed to get apiservers/cluster") desired := current.DeepCopy() - desired.Spec.TLSAdherence = configv1.TLSAdherencePolicyStrictAllComponents + desired.Spec.TLSAdherence = configv1.TLSAdherencePolicy("InvalidValue") - result, err := oc.AdminConfigClient().ConfigV1().APIServers().Update(ctx, desired, metav1.UpdateOptions{ + _, err = oc.AdminConfigClient().ConfigV1().APIServers().Update(ctx, desired, metav1.UpdateOptions{ DryRun: []string{metav1.DryRunAll}, }) - o.Expect(err).NotTo(o.HaveOccurred(), - "apiservers/cluster should accept spec.tlsAdherence=StrictAllComponents") - o.Expect(result.Spec.TLSAdherence).To( - o.Equal(configv1.TLSAdherencePolicyStrictAllComponents), - "apiservers/cluster should reflect spec.tlsAdherence=StrictAllComponents") + o.Expect(err).To(o.HaveOccurred(), + "apiservers/cluster should reject an invalid spec.tlsAdherence value") + o.Expect(k8serrors.IsInvalid(err)).To(o.BeTrue(), + "error should be a 422 Invalid, got: %v", err) }) - // Test 3 – verify the API server accepts and reflects LegacyAdheringComponentsOnly via dry-run. - g.It("[FeatureGate:TLSAdherence] should accept and reflect spec.tlsAdherence LegacyAdheringComponentsOnly on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { - current, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred(), "failed to get apiservers/cluster") - - desired := current.DeepCopy() - desired.Spec.TLSAdherence = configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly - - result, err := oc.AdminConfigClient().ConfigV1().APIServers().Update(ctx, desired, metav1.UpdateOptions{ - DryRun: []string{metav1.DryRunAll}, - }) - o.Expect(err).NotTo(o.HaveOccurred(), - "apiservers/cluster should accept spec.tlsAdherence=LegacyAdheringComponentsOnly") - o.Expect(result.Spec.TLSAdherence).To( - o.Equal(configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly), - "apiservers/cluster should reflect spec.tlsAdherence=LegacyAdheringComponentsOnly") - }) - - // Test 4 – verify the current spec.tlsAdherence value (when set) is a recognised valid value. - g.It("[FeatureGate:TLSAdherence] should have a valid spec.tlsAdherence value on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { - apiServer, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred(), "failed to get apiservers/cluster") - + // Test 2 – verify the API server accepts and reflects all valid spec.tlsAdherence values via dry-run. + g.It("[FeatureGate:TLSAdherence] should accept and reflect all valid spec.tlsAdherence values on apiservers/cluster [apigroup:config.openshift.io]", func(ctx context.Context) { validValues := []configv1.TLSAdherencePolicy{ - configv1.TLSAdherencePolicyNoOpinion, - configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly, configv1.TLSAdherencePolicyStrictAllComponents, + configv1.TLSAdherencePolicyLegacyAdheringComponentsOnly, + } + + for _, value := range validValues { + current, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to get apiservers/cluster") + + desired := current.DeepCopy() + desired.Spec.TLSAdherence = value + + result, err := oc.AdminConfigClient().ConfigV1().APIServers().Update(ctx, desired, metav1.UpdateOptions{ + DryRun: []string{metav1.DryRunAll}, + }) + o.Expect(err).NotTo(o.HaveOccurred(), + "apiservers/cluster should accept spec.tlsAdherence=%s", value) + o.Expect(result.Spec.TLSAdherence).To( + o.Equal(value), + "apiservers/cluster should reflect spec.tlsAdherence=%s", value) } - o.Expect(apiServer.Spec.TLSAdherence).To( - o.BeElementOf(validValues), - "apiservers/cluster spec.tlsAdherence must be one of the defined TLSAdherencePolicy values") }) - // Test 5 – verify that no cluster operator is degraded when the TLSAdherence feature gate is active. + // Test 3 – verify that no cluster operator is degraded when the TLSAdherence feature gate is active. g.It("[FeatureGate:TLSAdherence] should not have any degraded cluster operators [apigroup:config.openshift.io]", func(ctx context.Context) { coList, err := oc.AdminConfigClient().ConfigV1().ClusterOperators().List(ctx, metav1.ListOptions{}) o.Expect(err).NotTo(o.HaveOccurred(), "failed to list clusteroperators")