Skip to content

ROX-33511: Fix cluster selection by name#19503

Open
rhybrillou wants to merge 5 commits intomaster-yann/ROX-33511/prefactor-move-pkg-accessscope-to-pkg-sacfrom
master-yann/ROX-33511/rework-scope-selection
Open

ROX-33511: Fix cluster selection by name#19503
rhybrillou wants to merge 5 commits intomaster-yann/ROX-33511/prefactor-move-pkg-accessscope-to-pkg-sacfrom
master-yann/ROX-33511/rework-scope-selection

Conversation

@rhybrillou
Copy link
Contributor

@rhybrillou rhybrillou commented Mar 19, 2026

Description

This PR is part of the split of #19351
The split results in the following stack of PRs:

The change at hand addresses the actual problem from the reported bug:
Cluster names that do not match the kubernetes label naming convention cannot be selected as part of the effective access scope.

Here, instead of converting the selection rules that rely on the cluster name to Kubernetes label selectors, explicit filters by name are being added to the cluster and namespace selection process.

User-facing documentation

Testing and quality

  • the change is production ready: the change is GA, or otherwise the functionality is gated by a feature flag
  • CI results are inspected

Automated testing

  • added unit tests

How I validated my change

Manual run of the added unit tests.

Manual testing

  • Create a cluster with a name not compliant with Kubernetes label syntax (my=cluster).
Screenshot 2026-03-12 at 10 00 19
  • Create a simple access scope that includes this cluster.
{
  "id": "d7062e4f-867b-46ad-9d58-c7599f085361",
  "name": "custom",
  "description": "",
  "rules": {
    "includedClusters": [
      "my=cluster"
    ],
    "includedNamespaces": [],
    "clusterLabelSelectors": [],
    "namespaceLabelSelectors": []
  },
  "traits": null
}
  • Create a role that references the created access scope.
{
  "name": "custom analyst",
  "description": "",
  "permissionSetId": "ffffffff-ffff-fff4-f5ff-fffffffffffe",
  "accessScopeId": "d7062e4f-867b-46ad-9d58-c7599f085361",
  "globalAccess": "NO_ACCESS",
  "resourceToAccess": {},
  "traits": null
}
  • Grant this role through AuthProvider rules.
Screenshot 2026-03-12 at 10 04 44
  • Log in with the configured AuthProvider in order to be granted the impacted role.

  • Open the ACS main dashboard.
    With the previous behaviour, the dashboard displays no data as the lookup queries return errors.

Screenshot 2026-03-12 at 10 06 24

With the fixed behaviour, the dashboard displays the expected data.
Screenshot 2026-03-12 at 10 11 56

@openshift-ci
Copy link

openshift-ci bot commented Mar 19, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • convertRulesToSelectors currently assumes scopeRules is non-nil; the new tests exercise nil rules, so you should guard for a nil scopeRules up front and return an empty selectors instance instead of dereferencing it.
  • emptySelector() initializes all maps and slices, but convertRulesToSelectors builds selectors with some fields left nil in the ‘no rules’ paths; either initialize these fields consistently (e.g., via emptySelector) or relax the tests to treat nil and empty maps/slices as equivalent.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- convertRulesToSelectors currently assumes scopeRules is non-nil; the new tests exercise nil rules, so you should guard for a nil scopeRules up front and return an empty selectors instance instead of dereferencing it.
- emptySelector() initializes all maps and slices, but convertRulesToSelectors builds selectors with some fields left nil in the ‘no rules’ paths; either initialize these fields consistently (e.g., via emptySelector) or relax the tests to treat nil and empty maps/slices as equivalent.

## Individual Comments

### Comment 1
<location path="pkg/sac/effectiveaccessscope/conversion_test.go" line_range="19-20" />
<code_context>
+	namespaceName2 = "namespace-B"
+)
+
+func TestConvertRulesToSelectors(t *testing.T) {
+	// Error cases
+
+	// Success cases
</code_context>
<issue_to_address>
**suggestion (testing):** Add explicit error-path tests for `convertRulesToSelectors`

The current test only covers success paths, even though the comment mentions error cases. Please add at least one case where an invalid `ClusterLabelSelectors` / `NamespaceLabelSelectors` entry causes `convertEachSetBasedLabelSelectorToK8sLabelSelector` to fail and `convertRulesToSelectors` to return an error, to verify error propagation and prevent regressions around accepting invalid selectors.

Suggested implementation:

```golang
func TestConvertRulesToSelectors(t *testing.T) {
	// Error cases
	for name, tc := range map[string]struct {
		rules *storage.SimpleAccessScope_Rules
	}{
		"invalid cluster label selector returns error": {
			// An intentionally malformed cluster label selector that should cause
			// convertEachSetBasedLabelSelectorToK8sLabelSelector to fail, which in
			// turn should cause convertRulesToSelectors to return an error.
			rules: &storage.SimpleAccessScope_Rules{
				ClusterLabelSelectors: []*storage.SetBasedLabelSelector{
					{
						// NOTE: This selector is expected to be invalid according to the
						// implementation of convertEachSetBasedLabelSelectorToK8sLabelSelector.
						// If the implementation changes, adjust this selector accordingly so
						// that it still exercises the error path.
						Requirements: []*storage.SetBasedLabelSelector_Requirement{
							{
								Key:      "",
								Operator: storage.SetBasedLabelSelector_IN,
								Values:   []string{"value"},
							},
						},
					},
				},
			},
		},
		"invalid namespace label selector returns error": {
			// Same as above but for namespace label selectors to ensure both
			// error paths are covered.
			rules: &storage.SimpleAccessScope_Rules{
				NamespaceLabelSelectors: []*storage.SetBasedLabelSelector{
					{
						Requirements: []*storage.SetBasedLabelSelector_Requirement{
							{
								Key:      "",
								Operator: storage.SetBasedLabelSelector_IN,
								Values:   []string{"value"},
							},
						},
					},
				},
			},
		},
	} {
		t.Run(name, func(t *testing.T) {
			_, err := convertRulesToSelectors(tc.rules)
			require.Error(t, err)
		})
	}

	// Success cases

```

The above edit assumes the following existing types and fields from the `storage` package:
- `storage.SimpleAccessScope_Rules` with fields:
  - `ClusterLabelSelectors []*storage.SetBasedLabelSelector`
  - `NamespaceLabelSelectors []*storage.SetBasedLabelSelector`
- `storage.SetBasedLabelSelector` with a field:
  - `Requirements []*storage.SetBasedLabelSelector_Requirement`
- `storage.SetBasedLabelSelector_Requirement` with fields:
  - `Key string`
  - `Operator storage.SetBasedLabelSelector_Operator`
  - `Values []string`
- An enum value `storage.SetBasedLabelSelector_IN`.

If the actual proto field or enum names differ (for example `Requirement` vs `Requirements`, or `IN` has a different identifier), adjust the field/enum names accordingly while keeping the overall structure:
- Construct at least one clearly invalid `ClusterLabelSelectors` entry and one invalid `NamespaceLabelSelectors` entry that cause `convertEachSetBasedLabelSelectorToK8sLabelSelector` to return an error.
- Ensure `require` (from `github.com/stretchr/testify/require`) is imported in this test file; if not, add the import.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@rhacs-bot
Copy link
Contributor

rhacs-bot commented Mar 19, 2026

Images are ready for the commit at d4ef26f.

To use with deploy scripts, first export MAIN_IMAGE_TAG=4.11.x-327-gd4ef26fb29.

@codecov
Copy link

codecov bot commented Mar 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 49.72%. Comparing base (924360c) to head (d4ef26f).

Additional details and impacted files
@@                                         Coverage Diff                                         @@
##           master-yann/ROX-33511/prefactor-move-pkg-accessscope-to-pkg-sac   #19503      +/-   ##
===================================================================================================
+ Coverage                                                            49.26%   49.72%   +0.45%     
===================================================================================================
  Files                                                                 2726     2701      -25     
  Lines                                                               205625   203475    -2150     
===================================================================================================
- Hits                                                                101308   101175     -133     
+ Misses                                                               96780    94777    -2003     
+ Partials                                                              7537     7523      -14     
Flag Coverage Δ
go-unit-tests 49.72% <100.00%> (+0.45%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@rhybrillou rhybrillou marked this pull request as ready for review March 19, 2026 17:54
@rhybrillou rhybrillou requested a review from a team as a code owner March 19, 2026 17:54
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • convertRulesToSelectors does not currently handle a nil scopeRules pointer but your tests expect it to (e.g., "nil rules result in an empty selector"), so you should add a nil check at the top of the function to return an empty selector without calling scopeRules getters.
  • In TestSelectorsMatchNamespace, the test case description "namespace NOT matched by label is included" contradicts the expected value (Excluded); please update the description to match the actual behavior to avoid confusion.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- convertRulesToSelectors does not currently handle a nil scopeRules pointer but your tests expect it to (e.g., "nil rules result in an empty selector"), so you should add a nil check at the top of the function to return an empty selector without calling scopeRules getters.
- In TestSelectorsMatchNamespace, the test case description "namespace NOT matched by label is included" contradicts the expected value (Excluded); please update the description to match the actual behavior to avoid confusion.

## Individual Comments

### Comment 1
<location path="pkg/sac/effectiveaccessscope/conversion.go" line_range="95-103" />
<code_context>
+//   - converts included_namespaces rules to a namespace matching map (parent cluster is identified by name),
 //   - converts all label selectors to standard ones with matching support.
-func convertRulesToLabelSelectors(scopeRules *storage.SimpleAccessScope_Rules) (clusterSelectors, namespaceSelectors []labels.Selector, err error) {
+func convertRulesToSelectors(scopeRules *storage.SimpleAccessScope_Rules) (*selectors, error) {
+	output := &selectors{}
+
 	// Convert each selector to labels.Selector.
</code_context>
<issue_to_address>
**suggestion:** Consider handling nil `scopeRules` explicitly to avoid potential panics on callers that pass nil

Now that this returns a structured `selectors` value, it’d be safer to explicitly handle `scopeRules == nil` (e.g., return an empty `selectors` with nil slices/sets). That makes the contract clear and prevents panics if any callers pass nil today or in the future.

```suggestion
	// convertRulesToSelectors:
	//   - converts included_clusters rules to a cluster name matching map,
	//   - converts included_namespaces rules to a namespace matching map (parent cluster is identified by name),
	//   - converts all label selectors to standard ones with matching support.
	func convertRulesToSelectors(scopeRules *storage.SimpleAccessScope_Rules) (*selectors, error) {
		// Explicitly handle nil rules: callers passing nil get an empty selectors value
		// instead of panicking on method calls on a nil pointer.
		if scopeRules == nil {
			return &selectors{}, nil
		}

		output := &selectors{}

		// Convert each selector to labels.Selector.
		clusterSelectors, clusterSelectorErr := convertEachSetBasedLabelSelectorToK8sLabelSelector(scopeRules.GetClusterLabelSelectors())
```
</issue_to_address>

### Comment 2
<location path="pkg/sac/effectiveaccessscope/conversion_test.go" line_range="22-25" />
<code_context>
+
+func TestConvertRulesToSelectors(t *testing.T) {
+	// Error cases
+	for name, tc := range map[string]struct {
+		rules *storage.SimpleAccessScope_Rules
+	}{
+		"bad label selection rules triggger an error": {
+			rules: &storage.SimpleAccessScope_Rules{
+				ClusterLabelSelectors: []*storage.SetBasedLabelSelector{
</code_context>
<issue_to_address>
**suggestion (testing):** Add an error-path test for invalid namespace label selectors, not only cluster label selectors

The error-path coverage here only exercises invalid `ClusterLabelSelectors`. Since `convertRulesToSelectors` can also fail on `NamespaceLabelSelectors`, please add a case with an invalid namespace label selector so that both error branches are tested.

Suggested implementation:

```golang
		"bad label selection rules triggger an error": {
			rules: &storage.SimpleAccessScope_Rules{
				ClusterLabelSelectors: []*storage.SetBasedLabelSelector{
					{
						Requirements: []*storage.SetBasedLabelSelector_Requirement{
							{
								Key: "some-label",
								Op:  storage.SetBasedLabelSelector_IN,
								// The clusterName2 value is not a valid label value as it contains the '=' character.
								Values: []string{clusterName2},
							},
						},
					},
				},
				NamespaceLabelSelectors: []*storage.SetBasedLabelSelector{
					{
						Requirements: []*storage.SetBasedLabelSelector_Requirement{
							{
								Key: "some-namespace-label",
								Op:  storage.SetBasedLabelSelector_IN,
								// The namespaceName2 value is not a valid label value as it contains the '=' character.
								Values: []string{namespaceName2},
							},
						},
					},

```

1. To fully exercise both error branches independently, consider adding a second error test case in the same table where:
   - `ClusterLabelSelectors` is either nil or contains only valid selectors.
   - `NamespaceLabelSelectors` contains an invalid selector (like the one added above).
2. That new case would mirror the structure of `"bad label selection rules triggger an error"` but populate only `NamespaceLabelSelectors` with the invalid value, ensuring `convertRulesToSelectors` hits the namespace error path even if it short-circuits on cluster selector errors.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +22 to +25
for name, tc := range map[string]struct {
rules *storage.SimpleAccessScope_Rules
}{
"bad label selection rules triggger an error": {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Add an error-path test for invalid namespace label selectors, not only cluster label selectors

The error-path coverage here only exercises invalid ClusterLabelSelectors. Since convertRulesToSelectors can also fail on NamespaceLabelSelectors, please add a case with an invalid namespace label selector so that both error branches are tested.

Suggested implementation:

		"bad label selection rules triggger an error": {
			rules: &storage.SimpleAccessScope_Rules{
				ClusterLabelSelectors: []*storage.SetBasedLabelSelector{
					{
						Requirements: []*storage.SetBasedLabelSelector_Requirement{
							{
								Key: "some-label",
								Op:  storage.SetBasedLabelSelector_IN,
								// The clusterName2 value is not a valid label value as it contains the '=' character.
								Values: []string{clusterName2},
							},
						},
					},
				},
				NamespaceLabelSelectors: []*storage.SetBasedLabelSelector{
					{
						Requirements: []*storage.SetBasedLabelSelector_Requirement{
							{
								Key: "some-namespace-label",
								Op:  storage.SetBasedLabelSelector_IN,
								// The namespaceName2 value is not a valid label value as it contains the '=' character.
								Values: []string{namespaceName2},
							},
						},
					},
  1. To fully exercise both error branches independently, consider adding a second error test case in the same table where:
    • ClusterLabelSelectors is either nil or contains only valid selectors.
    • NamespaceLabelSelectors contains an invalid selector (like the one added above).
  2. That new case would mirror the structure of "bad label selection rules triggger an error" but populate only NamespaceLabelSelectors with the invalid value, ensuring convertRulesToSelectors hits the namespace error path even if it short-circuits on cluster selector errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this comment addressed ?

@rhybrillou
Copy link
Contributor Author

/retest

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.

2 participants