From 165d8ce0e53ddfa55b8ab9dcdaebd71a8afc07ec Mon Sep 17 00:00:00 2001 From: Justin Kulikauskas Date: Mon, 24 Mar 2025 16:33:37 -0400 Subject: [PATCH] Add SVT test for standalone-hub-templating The test verifies the special message emitted when the addon is not enabled, as well as behavior around configuring "special" RBAC. Refs: - https://issues.redhat.com/browse/ACM-16137 - https://issues.redhat.com/browse/ACM-16094 Signed-off-by: Justin Kulikauskas --- .../standalone_hubtemplates_test.go | 151 ++++++++++++++++++ .../config-standalone-addon.yaml | 62 +++++++ .../config-standalone-rbac.yaml | 93 +++++++++++ .../standalone-hubtemplates-test-updated.yaml | 20 +++ .../standalone-hubtemplates-test.yaml | 19 +++ 5 files changed, 345 insertions(+) create mode 100644 test/integration/standalone_hubtemplates_test.go create mode 100644 test/resources/standalone_hubtemplates/config-standalone-addon.yaml create mode 100644 test/resources/standalone_hubtemplates/config-standalone-rbac.yaml create mode 100644 test/resources/standalone_hubtemplates/standalone-hubtemplates-test-updated.yaml create mode 100644 test/resources/standalone_hubtemplates/standalone-hubtemplates-test.yaml diff --git a/test/integration/standalone_hubtemplates_test.go b/test/integration/standalone_hubtemplates_test.go new file mode 100644 index 00000000..24f76d73 --- /dev/null +++ b/test/integration/standalone_hubtemplates_test.go @@ -0,0 +1,151 @@ +// Copyright Contributors to the Open Cluster Management project + +package integration + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "open-cluster-management.io/governance-policy-propagator/test/utils" + + "github.com/stolostron/governance-policy-framework/test/common" +) + +var _ = Describe("GRC: [P1][Sev1][policy-grc] Test standalone hub templating", Ordered, Serial, Label("SVT"), func() { + const ( + standaloneConfigPolYAML = "../resources/standalone_hubtemplates/standalone-hubtemplates-test.yaml" + standaloneConfigPolUpdated = "../resources/standalone_hubtemplates/standalone-hubtemplates-test-updated.yaml" + standaloneConfigPolName = "standalone-hubtemplates-test" + standaloneConfigPolNS = "open-cluster-management-policies" + + addonPolYAML = "../resources/standalone_hubtemplates/config-standalone-addon.yaml" + addonPolName = "config-standalone-addon" + + rbacPolYAML = "../resources/standalone_hubtemplates/config-standalone-rbac.yaml" + rbacPolName = "config-standalone-rbac" + + hubClusterNamespace = "local-cluster" + ) + + AfterAll(func(ctx SpecContext) { + By("Deleting policies") + + _, err := common.OcHub("delete", "-f", standaloneConfigPolYAML, "--ignore-not-found") + Expect(err).ToNot(HaveOccurred()) + utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + standaloneConfigPolName, standaloneConfigPolNS, false, defaultTimeoutSeconds) + + common.DoCleanupPolicy(addonPolYAML, common.GvrConfigurationPolicy) + common.DoCleanupPolicy(rbacPolYAML, common.GvrConfigurationPolicy) + }) + + It("Cannot resolve the policy when the addon is not enabled", func(ctx context.Context) { + _, err := common.OcHub("create", "-f", standaloneConfigPolYAML) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + standaloneConfigPolName, standaloneConfigPolNS, true, defaultTimeoutSeconds) + + compliance, _, _ := unstructured.NestedString(plc.Object, "status", "compliant") + + return compliance + }, defaultTimeoutSeconds, 2).Should(Equal("NonCompliant")) + + Consistently(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + standaloneConfigPolName, standaloneConfigPolNS, true, defaultTimeoutSeconds) + + details, _, _ := unstructured.NestedSlice(plc.Object, "status", "compliancyDetails") + Expect(details).To(HaveLen(1)) + + conds, _, _ := unstructured.NestedSlice(details[0].(map[string]interface{}), "conditions") + Expect(conds).To(HaveLen(1)) + + msg, _, _ := unstructured.NestedString(conds[0].(map[string]interface{}), "message") + + return msg + }, 10, 2).Should(ContainSubstring("governance-standalone-hub-templating addon must be enabled")) + }) + + It("Is able to successfully enforce the addon policy", func(ctx context.Context) { + _, err := common.OcHub("create", "-f", addonPolYAML) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + addonPolName, hubClusterNamespace, true, defaultTimeoutSeconds) + + compliance, _, _ := unstructured.NestedString(plc.Object, "status", "compliant") + + return compliance + }, defaultTimeoutSeconds, 2).Should(Equal("Compliant")) + }) + + It("Resolves the template after the addon is enabled", func(ctx context.Context) { + Eventually(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + standaloneConfigPolName, standaloneConfigPolNS, true, defaultTimeoutSeconds) + + compliance, _, _ := unstructured.NestedString(plc.Object, "status", "compliant") + + return compliance + }, defaultTimeoutSeconds, 2).Should(Equal("Compliant")) + }) + + It("Cannot resolve other resources without additional RBAC", func(ctx context.Context) { + _, err := common.OcHub("apply", "-f", standaloneConfigPolUpdated) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + standaloneConfigPolName, standaloneConfigPolNS, true, defaultTimeoutSeconds) + + compliance, _, _ := unstructured.NestedString(plc.Object, "status", "compliant") + + return compliance + }, defaultTimeoutSeconds, 2).Should(Equal("NonCompliant")) + + Consistently(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + standaloneConfigPolName, standaloneConfigPolNS, true, defaultTimeoutSeconds) + + details, _, _ := unstructured.NestedSlice(plc.Object, "status", "compliancyDetails") + Expect(details).To(HaveLen(1)) + + conds, _, _ := unstructured.NestedSlice(details[0].(map[string]interface{}), "conditions") + Expect(conds).To(HaveLen(1)) + + msg, _, _ := unstructured.NestedString(conds[0].(map[string]interface{}), "message") + + return msg + }, 10, 2).Should(ContainSubstring(`cannot list resource "configmaps"`)) + }) + + It("Is able to successfully configure additional RBAC permissions", func(ctx context.Context) { + _, err := common.OcHub("create", "-f", rbacPolYAML) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + rbacPolName, hubClusterNamespace, true, defaultTimeoutSeconds) + + compliance, _, _ := unstructured.NestedString(plc.Object, "status", "compliant") + + return compliance + }, defaultTimeoutSeconds, 2).Should(Equal("Compliant")) + }) + + It("Resolves the template after RBAC is configured", func(ctx context.Context) { + Eventually(func() string { + plc := utils.GetWithTimeout(clientHubDynamic, common.GvrConfigurationPolicy, + standaloneConfigPolName, standaloneConfigPolNS, true, defaultTimeoutSeconds) + + compliance, _, _ := unstructured.NestedString(plc.Object, "status", "compliant") + + return compliance + }, defaultTimeoutSeconds, 2).Should(Equal("Compliant")) + }) +}) diff --git a/test/resources/standalone_hubtemplates/config-standalone-addon.yaml b/test/resources/standalone_hubtemplates/config-standalone-addon.yaml new file mode 100644 index 00000000..d2e0b8f7 --- /dev/null +++ b/test/resources/standalone_hubtemplates/config-standalone-addon.yaml @@ -0,0 +1,62 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: config-standalone-addon + namespace: policy-test +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: config-standalone-addon + spec: + pruneObjectBehavior: DeleteAll + remediationAction: enforce + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: addon.open-cluster-management.io/v1alpha1 + kind: ManagedClusterAddOn + metadata: + name: governance-standalone-hub-templating + namespace: local-cluster + spec: + installNamespace: open-cluster-management-agent-addon +--- +apiVersion: cluster.open-cluster-management.io/v1beta1 +kind: Placement +metadata: + name: config-standalone-addon + namespace: policy-test +spec: + tolerations: + - key: cluster.open-cluster-management.io/unreachable + operator: Exists + - key: cluster.open-cluster-management.io/unavailable + operator: Exists + clusterSets: + - global + predicates: + - requiredClusterSelector: + labelSelector: + matchExpressions: + - key: name + operator: In + values: + - local-cluster +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: config-standalone-addon + namespace: policy-test +placementRef: + name: config-standalone-addon + apiGroup: cluster.open-cluster-management.io + kind: Placement +subjects: + - name: config-standalone-addon + apiGroup: policy.open-cluster-management.io + kind: Policy diff --git a/test/resources/standalone_hubtemplates/config-standalone-rbac.yaml b/test/resources/standalone_hubtemplates/config-standalone-rbac.yaml new file mode 100644 index 00000000..7db76b12 --- /dev/null +++ b/test/resources/standalone_hubtemplates/config-standalone-rbac.yaml @@ -0,0 +1,93 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: Policy +metadata: + name: config-standalone-rbac + namespace: policy-test +spec: + disabled: false + policy-templates: + - objectDefinition: + apiVersion: policy.open-cluster-management.io/v1 + kind: ConfigurationPolicy + metadata: + name: config-standalone-rbac + spec: + pruneObjectBehavior: DeleteAll + remediationAction: enforce + object-templates: + - complianceType: musthave + objectDefinition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: standalone-hubtemplates-test + namespace: local-cluster + data: + foo: bar + - complianceType: musthave + objectDefinition: + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: cm-reader + namespace: local-cluster + rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - complianceType: musthave + objectDefinition: + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: cm-reader-binding + namespace: local-cluster + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cm-reader + subjects: + - apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:open-cluster-management:cluster:local-cluster:addon:governance-standalone-hub-templating +--- +apiVersion: cluster.open-cluster-management.io/v1beta1 +kind: Placement +metadata: + name: config-standalone-rbac + namespace: policy-test +spec: + tolerations: + - key: cluster.open-cluster-management.io/unreachable + operator: Exists + - key: cluster.open-cluster-management.io/unavailable + operator: Exists + clusterSets: + - global + predicates: + - requiredClusterSelector: + labelSelector: + matchExpressions: + - key: name + operator: In + values: + - local-cluster +--- +apiVersion: policy.open-cluster-management.io/v1 +kind: PlacementBinding +metadata: + name: config-standalone-rbac + namespace: policy-test +placementRef: + name: config-standalone-rbac + apiGroup: cluster.open-cluster-management.io + kind: Placement +subjects: + - name: config-standalone-rbac + apiGroup: policy.open-cluster-management.io + kind: Policy diff --git a/test/resources/standalone_hubtemplates/standalone-hubtemplates-test-updated.yaml b/test/resources/standalone_hubtemplates/standalone-hubtemplates-test-updated.yaml new file mode 100644 index 00000000..11a8561c --- /dev/null +++ b/test/resources/standalone_hubtemplates/standalone-hubtemplates-test-updated.yaml @@ -0,0 +1,20 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: ConfigurationPolicy +metadata: + name: standalone-hubtemplates-test + namespace: open-cluster-management-policies +spec: + pruneObjectBehavior: DeleteAll + remediationAction: enforce + severity: low + object-templates: + - complianceType: musthave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: standalone-hubtemplates-test + namespace: default + data: + cloud: '{{hub .ManagedClusterLabels.cloud hub}}' + hubFoo: '{{hub fromConfigMap "local-cluster" "standalone-hubtemplates-test" "foo" hub}}' diff --git a/test/resources/standalone_hubtemplates/standalone-hubtemplates-test.yaml b/test/resources/standalone_hubtemplates/standalone-hubtemplates-test.yaml new file mode 100644 index 00000000..fc50c36f --- /dev/null +++ b/test/resources/standalone_hubtemplates/standalone-hubtemplates-test.yaml @@ -0,0 +1,19 @@ +apiVersion: policy.open-cluster-management.io/v1 +kind: ConfigurationPolicy +metadata: + name: standalone-hubtemplates-test + namespace: open-cluster-management-policies +spec: + pruneObjectBehavior: DeleteAll + remediationAction: enforce + severity: low + object-templates: + - complianceType: musthave + objectDefinition: + kind: ConfigMap + apiVersion: v1 + metadata: + name: standalone-hubtemplates-test + namespace: default + data: + cloud: '{{hub .ManagedClusterLabels.cloud hub}}'