Skip to content

fix(rbac): handle immutable roleRef in RoleBinding reconciliation#3321

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
vparfonov:log9542
Jul 2, 2026
Merged

fix(rbac): handle immutable roleRef in RoleBinding reconciliation#3321
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
vparfonov:log9542

Conversation

@vparfonov

@vparfonov vparfonov commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description

RoleBinding.roleRef is immutable in Kubernetes. When the referenced Role name changes (e.g. during upgrade from v6.5 to v6.6), delete and recreate the RoleBinding instead of attempting to update.

/cc
/assign

Links

Summary by CodeRabbit

  • Bug Fixes
    • Improved RoleBinding reconciliation to handle permission changes more reliably.
    • Existing bindings are now updated when only subjects or ownership change, while bindings with changed role references are recreated to ensure the correct access is applied.
  • Tests
    • Added coverage for creating, updating, and recreating RoleBindings during reconciliation.

RoleBinding.roleRef is immutable in Kubernetes. When the referenced Role
name changes (e.g. during upgrade from v6.5 to v6.6), delete and recreate
the RoleBinding instead of attempting to update.

Signed-off-by: Vitalii Parfonov <vparfono@redhat.com>
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

RoleBinding reconciliation in internal/reconcile/rbac.go was rewritten from a controllerutil.CreateOrUpdate-based approach to an explicit Get-then-manage flow: create if missing, delete/recreate if RoleRef changed, or update Subjects/OwnerReferences otherwise. A new test suite validates these three scenarios.

Changes

RoleBinding Reconciliation

Layer / File(s) Summary
Explicit Get/Create/Delete/Update logic
internal/reconcile/rbac.go
Replaces CreateOrUpdate with explicit Get, create-if-missing, delete/recreate on RoleRef change, and update-in-place for Subjects/OwnerReferences otherwise.
Test coverage for reconciliation scenarios
internal/reconcile/rbac_test.go
Adds Ginkgo/Gomega tests with a fake client covering creation, unchanged-RoleRef updates, and RoleRef-change delete/recreate flows.

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

Related PRs: None identified.

Suggested labels: None

Suggested reviewers: None

🐰 A binding once bound, now torn and remade,
When roles shift like shadows, the old one must fade.
Get, check, and decide—create, swap, or stay,
Subjects and owners in tidy array.
Tests hop through each path, delighted, precise! 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the issue and links a JIRA ticket, but it leaves the mandatory /cc and /assign fields unfilled. Add the required /cc and /assign commands with real OWNERS entries, and keep the existing context plus link details.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: handling immutable roleRef during RoleBinding reconciliation.
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

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

@vparfonov

Copy link
Copy Markdown
Contributor Author

/assign @xperimental
/cc @Clee2691

@openshift-ci openshift-ci Bot requested review from alanconway and jcantrill July 1, 2026 15:43
@openshift-ci openshift-ci Bot requested a review from Clee2691 July 1, 2026 15:44

@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 (2)
internal/reconcile/rbac.go (2)

30-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Duplicate logic with ClusterRoleBinding.

This Get/Create/Delete-recreate/Update flow (lines 30-54) mirrors ClusterRoleBinding (lines 56-80) almost line-for-line, differing only in namespaced vs. cluster scope and OwnerReferences handling. Worth extracting a shared helper (e.g. keyed on a RoleRef-getter interface) to avoid the two implementations drifting apart over time.

🤖 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 `@internal/reconcile/rbac.go` around lines 30 - 54, The RoleBinding
reconciliation flow duplicates the ClusterRoleBinding logic almost exactly, so
factor the shared Get/Create/Delete-recreate/Update sequence into a common
helper to keep both paths aligned. Keep the scope-specific differences in
separate wrappers such as RoleBinding and ClusterRoleBinding, and pass in the
object-specific details like namespace handling and OwnerReferences updates via
a small interface or callback. Use the existing RoleBinding and
ClusterRoleBinding functions as the call sites for the shared helper so future
changes only need to be made in one place.

50-53: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Update is called unconditionally even when nothing changed.

Unlike the previous controllerutil.CreateOrUpdate (which only writes when the mutate callback actually changes the object), this path always calls Update even if Subjects/OwnerReferences already match desired. That's an unnecessary API write (and resourceVersion bump) on every reconcile.

♻️ Proposed fix to skip no-op updates
+	if reflect.DeepEqual(existing.Subjects, desired.Subjects) && reflect.DeepEqual(existing.OwnerReferences, desired.OwnerReferences) {
+		return nil
+	}
 	existing.Subjects = desired.Subjects
 	existing.OwnerReferences = desired.OwnerReferences
 	log.V(3).Info("Updating roleBinding", "name", desired.Name, "namespace", desired.Namespace)
 	return k8Client.Update(context.TODO(), existing)

Requires adding "reflect" to the 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 `@internal/reconcile/rbac.go` around lines 50 - 53, The role binding reconcile
path always performs an Update even when the object is already in the desired
state, causing unnecessary API writes and resourceVersion bumps. In
internal/reconcile/rbac.go, update the logic around the existing.Subjects and
existing.OwnerReferences assignment in the roleBinding handling so it first
compares them to desired using reflect.DeepEqual and skips k8Client.Update when
nothing changed. Keep the existing log.V(3).Info and Update call only for real
mutations, and add reflect to the imports.
🤖 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 `@internal/reconcile/rbac.go`:
- Around line 30-54: The RoleBinding reconciliation flow duplicates the
ClusterRoleBinding logic almost exactly, so factor the shared
Get/Create/Delete-recreate/Update sequence into a common helper to keep both
paths aligned. Keep the scope-specific differences in separate wrappers such as
RoleBinding and ClusterRoleBinding, and pass in the object-specific details like
namespace handling and OwnerReferences updates via a small interface or
callback. Use the existing RoleBinding and ClusterRoleBinding functions as the
call sites for the shared helper so future changes only need to be made in one
place.
- Around line 50-53: The role binding reconcile path always performs an Update
even when the object is already in the desired state, causing unnecessary API
writes and resourceVersion bumps. In internal/reconcile/rbac.go, update the
logic around the existing.Subjects and existing.OwnerReferences assignment in
the roleBinding handling so it first compares them to desired using
reflect.DeepEqual and skips k8Client.Update when nothing changed. Keep the
existing log.V(3).Info and Update call only for real mutations, and add reflect
to the imports.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d29ba02e-90e4-4d18-b962-d5cb8e291cb0

📥 Commits

Reviewing files that changed from the base of the PR and between f32eb77 and 7d5c373.

📒 Files selected for processing (2)
  • internal/reconcile/rbac.go
  • internal/reconcile/rbac_test.go

@vparfonov

Copy link
Copy Markdown
Contributor Author

/assign @jcantrill

@openshift-ci

openshift-ci Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@vparfonov: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-using-bundle 7d5c373 link false /test e2e-using-bundle

Full PR test history. Your PR dashboard.

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. I understand the commands that are listed here.

@jcantrill

Copy link
Copy Markdown
Contributor

/approve
/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 2, 2026
@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jcantrill, vparfonov

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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 2, 2026
@openshift-merge-bot openshift-merge-bot Bot merged commit c02ef14 into openshift:master Jul 2, 2026
9 of 10 checks passed
@vparfonov vparfonov deleted the log9542 branch July 2, 2026 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. release/6.6

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants