Skip to content

Trim whitespace when splitting security-group annotations - #6535

Merged
KevinFCormier merged 2 commits into
stolostron:mainfrom
sungupta-llm:fix/governance-overview-standards-trim-whitespace
Jul 28, 2026
Merged

Trim whitespace when splitting security-group annotations#6535
KevinFCormier merged 2 commits into
stolostron:mainfrom
sungupta-llm:fix/governance-overview-standards-trim-whitespace

Conversation

@sungupta-llm

@sungupta-llm sungupta-llm commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

The Governance Overview Standards/Categories/Controls cards (and the policy
drill-down sidebar behind them) group policies by splitting the
policy.open-cluster-management.io/{standards,categories,controls}
annotation on ,:

const names = annotation.split(',')
for (const name of names) {
  let v = clusterViolations[name]   // raw, untrimmed string used as the aggregation key
  ...
}

String.split(',') leaves a leading space on every token after the first
(e.g. "A, B".split(',')["A", " B"]). If the same logical value (e.g.
"NIST SP 800-53") is the first item in one policy's annotation but a later
item in another policy's annotation, the two policies produce different map
keys ("NIST SP 800-53" vs " NIST SP 800-53") and render as two separate
rows on the card instead of aggregating into one.

The same unfixed split exists in the drill-down sidebar filter
(SecurityGroupPolicySummarySidebar.tsx), which does a strict equality
check (name === violation.name) against the untrimmed token, so the
sidebar's policy list can also fail to match policies whose annotation
formatting differs from the row that was clicked.

Fix

Trim each token after splitting, in both useSecurityGroupViolations
(Overview.tsx) and the matching filter in
SecurityGroupPolicySummarySidebar.tsx, so aggregation and drill-down
filtering key off the same normalized value regardless of comma-spacing.

Reproduction (single managed cluster is sufficient)

  1. Create Policy A with annotation:
    policy.open-cluster-management.io/standards: "NIST SP 800-53, PCI-DSS 4.0"
  2. Create Policy B with annotation:
    policy.open-cluster-management.io/standards: "CIS OpenShift Benchmark, PCI-DSS 4.0, NIST SP 800-53"
  3. Propagate both to any managed cluster, wait for Compliant status.
  4. Governance Overview → Standards card shows "NIST SP 800-53" as two
    separate rows instead of one aggregated row.

Test plan

  • Added a regression test to Overview.test.tsx that renders the Standards
    card with two policies carrying the same standard in different list
    positions, and asserts a single aggregated row.
  • Verified the new test fails without the fix (Expected: 1, Received: 2)
    and passes with it.
  • eslint --max-warnings=0 clean on all changed files.

Reported in Red Hat case 04500068.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Governance overview aggregation by trimming whitespace in comma-separated standards and security group names from annotations.
    • Fixed policy matching so clicked violation names correctly align with standards even when annotation tokens include extra spaces.
  • Tests
    • Added regression coverage to verify standards are deduplicated after trimming and that the sidebar includes the expected policy when names match non-first tokens.

@openshift-ci

openshift-ci Bot commented Jul 24, 2026

Copy link
Copy Markdown

Hi @sungupta-llm. Thanks for your PR.

I'm waiting for a stolostron member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Governance overview annotation parsing now trims whitespace around comma-separated security group and policy names. Regression tests verify standards deduplication and sidebar matching for trimmed annotation values.

Changes

Governance annotation parsing

Layer / File(s) Summary
Trim annotation values
frontend/src/routes/Governance/overview/Overview.tsx, frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx
Security group and policy names are trimmed after comma splitting before aggregation and matching.
Regression coverage
frontend/src/routes/Governance/overview/Overview.test.tsx
Adds typed policy fixtures and verifies standards with surrounding whitespace render once per unique standard, while sidebar matching recognizes a trimmed non-first token.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description has useful context, but it does not follow the repo template and is missing Ticket Link, Type of Change, and checklist sections. Rewrite the PR description using the required template, including Ticket Link, Type of Change, checklist items, and reviewer notes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main change: trimming whitespace while splitting security-group annotations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
frontend/src/routes/Governance/overview/Overview.test.tsx (3)

19-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a type-only import for Policy.

Policy is used only as a type in this test; split it into import type { Policy } to avoid a runtime import. As per coding guidelines, “Use import type for type-only imports to avoid generating runtime imports.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/routes/Governance/overview/Overview.test.tsx` at line 19, Update
the import of Policy in Overview.test.tsx to use a type-only import, while
keeping PolicyApiVersion and PolicyKind in the regular value import from
resources.

Source: Coding guidelines


197-210: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the required accessibility assertion.

Capture container from render and assert expect(await axe(container)).toHaveNoViolations() for this new component test. As per coding guidelines, “Every component test must include an accessibility assertion with jest-axe.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/routes/Governance/overview/Overview.test.tsx` around lines 197 -
210, Update the new GovernanceOverview test around the render call to capture
the returned container, then await axe(container) and assert it has no
accessibility violations. Preserve the existing providers, state initialization,
and component rendering while adding the required jest-axe assertion.

Source: Coding guidelines


200-203: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mock shared atoms through useSharedAtoms().

This new fixture initializes policiesState and managedClustersState through direct atom imports; mock the useSharedAtoms() contract instead. As per coding guidelines, “Mock Recoil atoms via useSharedAtoms() rather than direct atom imports.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/routes/Governance/overview/Overview.test.tsx` around lines 200 -
203, Update the test fixture’s initializeState setup around the policiesState
and managedClustersState references to mock the useSharedAtoms() contract
instead of importing or setting shared Recoil atoms directly. Ensure the test
receives the fixture values through the mocked hook while preserving the
existing policy and managed-cluster data.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@frontend/src/routes/Governance/overview/Overview.test.tsx`:
- Line 19: Update the import of Policy in Overview.test.tsx to use a type-only
import, while keeping PolicyApiVersion and PolicyKind in the regular value
import from resources.
- Around line 197-210: Update the new GovernanceOverview test around the render
call to capture the returned container, then await axe(container) and assert it
has no accessibility violations. Preserve the existing providers, state
initialization, and component rendering while adding the required jest-axe
assertion.
- Around line 200-203: Update the test fixture’s initializeState setup around
the policiesState and managedClustersState references to mock the
useSharedAtoms() contract instead of importing or setting shared Recoil atoms
directly. Ensure the test receives the fixture values through the mocked hook
while preserving the existing policy and managed-cluster data.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ea1a85b1-b21c-4ce0-b718-4c5c3a44b0e0

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa8714 and e1da5eb.

📒 Files selected for processing (3)
  • frontend/src/routes/Governance/overview/Overview.test.tsx
  • frontend/src/routes/Governance/overview/Overview.tsx
  • frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx

The Governance Overview Standards/Categories/Controls cards, and the
policy drill-down sidebar behind them, group policies by splitting
the policy.open-cluster-management.io/{standards,categories,controls}
annotation on ",". String.split(',') leaves a leading space on every
token after the first (e.g. "A, B".split(',') -> ["A", " B"]), so the
same logical value produces a second, distinct row whenever it isn't
first in a comma-separated list on some policies but is standalone or
first-in-list on others.

Trim each token after splitting in both useSecurityGroupViolations
(Overview.tsx) and the matching filter in
SecurityGroupPolicySummarySidebar.tsx so aggregation and drill-down
filtering key off the same normalized value regardless of annotation
formatting.

Reported in Red Hat case 04500068.

Signed-off-by: Sunny Gupta <sungupta@redhat.com>
@sungupta-llm
sungupta-llm force-pushed the fix/governance-overview-standards-trim-whitespace branch from e1da5eb to 2aa0aec Compare July 24, 2026 07:50
@KevinFCormier

Copy link
Copy Markdown
Contributor

/cc @Randy424

@openshift-ci
openshift-ci Bot requested a review from Randy424 July 24, 2026 14:14
Randy424
Randy424 previously approved these changes Jul 24, 2026

@Randy424 Randy424 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

The SecurityGroupPolicySummarySidebar drill-down applies the same
comma-split-without-trim fix as useSecurityGroupViolations, but the
existing regression test only exercised the Overview card path,
leaving the sidebar's fixed line uncovered on new code (SonarCloud
flagged 50% coverage on new code, below the 70% gate).

Add a test that renders SecurityGroupPolicySummarySidebar directly
with a policy whose matching standard is not first in its
comma-separated annotation, and asserts the policy appears in the
filtered list. Verified this test fails without the sidebar's
.trim() fix and passes with it.

Signed-off-by: Sunny Gupta <sungupta@redhat.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
frontend/src/routes/Governance/overview/Overview.test.tsx (1)

272-272: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Query the policy link by role.

The sidebar renders the policy name in a Link; assert it with findByRole('link', { name: 'policy-standards-last-sidebar' }) rather than text lookup.

As per coding guidelines, prefer role queries over text queries.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/routes/Governance/overview/Overview.test.tsx` at line 272,
Update the policy assertion in the Overview test to use screen.findByRole with
the link role and accessible name “policy-standards-last-sidebar” instead of
findByText, while preserving the existing async and visibility assertion.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/routes/Governance/overview/Overview.test.tsx`:
- Around line 16-20: Update the imports in the Overview test to use the ~/ alias
for newly added internal module imports, and split SecurityGroupViolations and
Policy into import type declarations because they are type-only symbols.
Preserve the existing value imports and runtime behavior.
- Around line 200-204: Replace direct atom initialization in both test fixtures
with shared atom access via useSharedAtoms(). In
frontend/src/routes/Governance/overview/Overview.test.tsx:200-204, initialize
both the policy and managed-cluster fixtures through useSharedAtoms(); at
257-260, initialize the policy fixture the same way, removing direct atom
imports or usage where applicable.

---

Nitpick comments:
In `@frontend/src/routes/Governance/overview/Overview.test.tsx`:
- Line 272: Update the policy assertion in the Overview test to use
screen.findByRole with the link role and accessible name
“policy-standards-last-sidebar” instead of findByText, while preserving the
existing async and visibility assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9cdadb73-9c64-4c27-b54f-aadf59a18148

📥 Commits

Reviewing files that changed from the base of the PR and between e1da5eb and 836f5ed.

📒 Files selected for processing (3)
  • frontend/src/routes/Governance/overview/Overview.test.tsx
  • frontend/src/routes/Governance/overview/Overview.tsx
  • frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/routes/Governance/overview/SecurityGroupPolicySummarySidebar.tsx
  • frontend/src/routes/Governance/overview/Overview.tsx

Comment on lines +16 to +20
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'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use aliases and type-only imports.

SecurityGroupViolations and Policy are type-only; the newly added internal imports are relative. Split type imports with import type and use ~/... aliases for the new internal imports.

As per coding guidelines, use ~/ shorthand and import type for type-only imports.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/routes/Governance/overview/Overview.test.tsx` around lines 16 -
20, Update the imports in the Overview test to use the ~/ alias for newly added
internal module imports, and split SecurityGroupViolations and Policy into
import type declarations because they are type-only symbols. Preserve the
existing value imports and runtime behavior.

Source: Coding guidelines

Comment on lines +200 to +204
<RecoilRoot
initializeState={(snapshot) => {
snapshot.set(policiesState, [policyWithStandardFirstInList, policyWithStandardLastInList])
snapshot.set(managedClustersState, mockManagedClusters)
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use shared atom access for the new fixtures.

Both tests set policiesState (and one sets managedClustersState) through direct atom imports.

  • frontend/src/routes/Governance/overview/Overview.test.tsx#L200-L204: initialize the policy and cluster fixtures through useSharedAtoms().
  • frontend/src/routes/Governance/overview/Overview.test.tsx#L257-L260: initialize the policy fixture through useSharedAtoms().

As per coding guidelines, mock Recoil atoms via useSharedAtoms() rather than direct atom imports.

📍 Affects 1 file
  • frontend/src/routes/Governance/overview/Overview.test.tsx#L200-L204 (this comment)
  • frontend/src/routes/Governance/overview/Overview.test.tsx#L257-L260
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/routes/Governance/overview/Overview.test.tsx` around lines 200 -
204, Replace direct atom initialization in both test fixtures with shared atom
access via useSharedAtoms(). In
frontend/src/routes/Governance/overview/Overview.test.tsx:200-204, initialize
both the policy and managed-cluster fixtures through useSharedAtoms(); at
257-260, initialize the policy fixture the same way, removing direct atom
imports or usage where applicable.

Source: Coding guidelines

@sungupta-llm

Copy link
Copy Markdown
Contributor Author

/retest

@openshift-ci

openshift-ci Bot commented Jul 25, 2026

Copy link
Copy Markdown

@sungupta-llm: Cannot trigger testing until a trusted user reviews the PR and leaves an /ok-to-test message.

Details

In response to this:

/retest

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@Randy424

Copy link
Copy Markdown
Contributor

/ok-to-test

@sungupta-llm

Copy link
Copy Markdown
Contributor Author

/ok-to-test

@Randy424

Copy link
Copy Markdown
Contributor

/retest-required

@Randy424 Randy424 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm label Jul 26, 2026
@openshift-ci

openshift-ci Bot commented Jul 26, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Randy424, sungupta-llm

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sungupta-llm

Copy link
Copy Markdown
Contributor Author

@Randy424 It seems its pending on 1 more test which require your approval.

@Randy424

Copy link
Copy Markdown
Contributor

/ok-to-test

@Randy424

Copy link
Copy Markdown
Contributor

/test unit-tests-sonarcloud

@Randy424

Copy link
Copy Markdown
Contributor

@sungupta-llm it looks like we are still running into some test failures ([frontend] FAIL src/wizards/Governance/Policy/policyWizard.test.tsx (51.115 s)) ...Could you review this unit test and confirm whether this failure is related to your changes?

@sungupta-llm

sungupta-llm commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@Randy424 No code overlap: PolicyWizard.tsx/policyWizard.test.tsx have zero references to Overview.tsx or SecurityGroupPolicySummarySidebar.tsx (the only files this PR touches besides the test).
I saw PR #6443 (merged 2026-07-09) fixed the identical MISSING NOCK(S) failure for a different test in this same file (default tolerations persist after switching to existing and back to new placement) — same error signature, same setupAfterEach stack trace at src/setupTests.ts:231. That fix added one missing mock line for that specific test.

cc @KevinFCormier

@sungupta-llm

Copy link
Copy Markdown
Contributor Author

/ok-to-test

@sungupta-llm

Copy link
Copy Markdown
Contributor Author

/test unit-tests-sonarcloud

@sonarqubecloud

Copy link
Copy Markdown

@Randy424

Copy link
Copy Markdown
Contributor

/ok-to-test

@KevinFCormier

Copy link
Copy Markdown
Contributor

/retest

@KevinFCormier
KevinFCormier merged commit f011467 into stolostron:main Jul 28, 2026
15 of 17 checks passed
@Randy424

Randy424 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

/cherry-pick release-2.17

@openshift-cherrypick-robot

Copy link
Copy Markdown
Contributor

@Randy424: new pull request created: #6641

Details

In response to this:

/cherry-pick release-2.17

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@Randy424

Randy424 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

/cherry-pick release-2.16

@openshift-cherrypick-robot

Copy link
Copy Markdown
Contributor

@Randy424: new pull request created: #6642

Details

In response to this:

/cherry-pick release-2.16

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@Randy424

Randy424 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

/cherry-pick release-2.15

@openshift-cherrypick-robot

Copy link
Copy Markdown
Contributor

@Randy424: new pull request created: #6643

Details

In response to this:

/cherry-pick release-2.15

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants