diff --git a/frontend/src/routes/Governance/overview/Overview.test.tsx b/frontend/src/routes/Governance/overview/Overview.test.tsx
index d7640d66a3d..8c26944fcfc 100644
--- a/frontend/src/routes/Governance/overview/Overview.test.tsx
+++ b/frontend/src/routes/Governance/overview/Overview.test.tsx
@@ -13,9 +13,11 @@ import {
mockPolicy,
mockPolicyNoStatus,
} from '../governance.sharedMocks'
-import GovernanceOverview from './Overview'
+import GovernanceOverview, { SecurityGroupViolations } from './Overview'
+import { SecurityGroupPolicySummarySidebar } from './SecurityGroupPolicySummarySidebar'
import userEvent from '@testing-library/user-event'
import { defaultContext, PluginDataContext } from '../../../lib/PluginDataContext'
+import { Policy, PolicyApiVersion, PolicyKind } from '../../../resources'
describe('Overview Page', () => {
beforeEach(async () => nockIgnoreApiPaths())
@@ -141,4 +143,132 @@ describe('Overview Page', () => {
userEvent.click(screen.getByText(/show 85 more/i))
expect(queryByText(/show 85 more/i)).not.toBeInTheDocument()
})
+
+ test('Should aggregate Standards card by trimmed annotation value, not raw comma-split token', async () => {
+ // Regression test: a standard listed anywhere but first in a comma-separated
+ // policy.open-cluster-management.io/standards annotation must not produce a
+ // separate row on the Standards card just because of the leading space left
+ // behind by String.split(',').
+ const policyWithStandardFirstInList: Policy = {
+ apiVersion: PolicyApiVersion,
+ kind: PolicyKind,
+ metadata: {
+ name: 'policy-standards-first',
+ namespace: 'test',
+ uid: 'standards-test-uid-1',
+ annotations: {
+ 'policy.open-cluster-management.io/standards': 'NIST SP 800-53, PCI-DSS 4.0',
+ },
+ },
+ spec: {
+ disabled: false,
+ 'policy-templates': [],
+ remediationAction: 'inform',
+ },
+ status: {
+ compliant: 'Compliant',
+ },
+ }
+ const policyWithStandardLastInList: Policy = {
+ apiVersion: PolicyApiVersion,
+ kind: PolicyKind,
+ metadata: {
+ name: 'policy-standards-last',
+ namespace: 'test',
+ uid: 'standards-test-uid-2',
+ annotations: {
+ 'policy.open-cluster-management.io/standards': 'CIS OpenShift Benchmark, PCI-DSS 4.0, NIST SP 800-53',
+ },
+ },
+ spec: {
+ disabled: false,
+ 'policy-templates': [],
+ remediationAction: 'inform',
+ },
+ status: {
+ compliant: 'Compliant',
+ },
+ }
+
+ const pluginData = {
+ ...defaultContext,
+ loadStarted: true,
+ loadCompleted: true,
+ }
+ render(
+
+ {
+ snapshot.set(policiesState, [policyWithStandardFirstInList, policyWithStandardLastInList])
+ snapshot.set(managedClustersState, mockManagedClusters)
+ }}
+ >
+
+
+
+
+
+ )
+
+ // Before the fix this rendered two separate rows/spans for the same logical
+ // standard (one from the untrimmed " NIST SP 800-53" split token).
+ expect(screen.getAllByText('NIST SP 800-53').length).toBe(1)
+ expect(screen.getAllByText('PCI-DSS 4.0').length).toBe(1)
+ })
+
+ test('SecurityGroupPolicySummarySidebar should match policies by trimmed annotation value', async () => {
+ // Regression test for the sidebar drill-down: a policy whose standard is not
+ // the first item in its comma-separated annotation must still match the
+ // clicked-on violation, which is keyed by the trimmed value.
+ const policyWithStandardLastInList: Policy = {
+ apiVersion: PolicyApiVersion,
+ kind: PolicyKind,
+ metadata: {
+ name: 'policy-standards-last-sidebar',
+ namespace: 'test',
+ uid: 'standards-test-uid-3',
+ annotations: {
+ 'policy.open-cluster-management.io/standards': 'CIS OpenShift Benchmark, PCI-DSS 4.0, NIST SP 800-53',
+ },
+ },
+ spec: {
+ disabled: false,
+ 'policy-templates': [],
+ remediationAction: 'inform',
+ },
+ status: {
+ compliant: 'Compliant',
+ },
+ }
+ const violation: SecurityGroupViolations = {
+ name: 'NIST SP 800-53',
+ compliant: 1,
+ noncompliant: 0,
+ pending: 0,
+ }
+
+ const pluginData = {
+ ...defaultContext,
+ loadStarted: true,
+ loadCompleted: true,
+ }
+ render(
+
+ {
+ snapshot.set(policiesState, [policyWithStandardLastInList])
+ }}
+ >
+
+
+
+
+
+ )
+
+ // Before the fix, the sidebar's filter compared the untrimmed " NIST SP 800-53"
+ // split token against violation.name ("NIST SP 800-53") and never matched,
+ // so the policy would not appear in this list.
+ expect(await screen.findByText('policy-standards-last-sidebar')).toBeInTheDocument()
+ })
})
diff --git a/frontend/src/routes/Governance/overview/Overview.tsx b/frontend/src/routes/Governance/overview/Overview.tsx
index 473b2bd78f3..84be3de2b68 100644
--- a/frontend/src/routes/Governance/overview/Overview.tsx
+++ b/frontend/src/routes/Governance/overview/Overview.tsx
@@ -100,7 +100,7 @@ function useSecurityGroupViolations(group: string, policies: Policy[]) {
if (policy.spec.disabled) continue
const annotation = policy.metadata.annotations?.[`policy.open-cluster-management.io/${group}`]
if (!annotation) continue
- const names = annotation.split(',')
+ const names = annotation.split(',').map((name) => name.trim())
for (const name of names) {
let v = clusterViolations[name]
if (!v) {
diff --git a/frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx b/frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx
index 525d83b966c..64a1411a057 100644
--- a/frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx
+++ b/frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx
@@ -36,7 +36,7 @@ export function SecurityGroupPolicySummarySidebar(props: {
if (!annotation) {
return false
}
- const names = annotation.split(',')
+ const names = annotation.split(',').map((name) => name.trim())
for (const name of names) {
if (name === violation.name && policy.status?.compliant) {
return true