Skip to content

CM-1040: Extract shared ApplyResource helper and migrate istiocsr to SSA#420

Open
sebrandon1 wants to merge 1 commit into
openshift:masterfrom
sebrandon1:extract-apply-resource
Open

CM-1040: Extract shared ApplyResource helper and migrate istiocsr to SSA#420
sebrandon1 wants to merge 1 commit into
openshift:masterfrom
sebrandon1:extract-apply-resource

Conversation

@sebrandon1

@sebrandon1 sebrandon1 commented May 6, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds a generic common.ApplyResource[T]() helper for SSA-based reconciliation with pluggable drift detection callbacks
  • Migrates trustmanager's 11 createOrApply methods to use the shared helper
  • Migrates istiocsr's 8 simple createOrApply methods from Create/UpdateWithRetry to SSA via the shared helper
  • Keeps istiocsr's complex ClusterRole/ClusterRoleBinding methods unchanged (they use GenerateName + List fallback + Delete for immutable RoleRef)
  • Drops istioCSRCreateRecon warning events from migrated methods (SSA is inherently idempotent)
  • Net -501 lines of duplicated boilerplate

Test plan

  • go test ./pkg/controller/common/... passes
  • go test ./pkg/controller/istiocsr/... passes
  • go test ./pkg/controller/trustmanager/... passes
  • go build ./... succeeds
  • make lint shows only pre-existing issues (9 total, none introduced)

Summary by CodeRabbit

  • Refactoring

    • Added a shared Server-Side Apply helper to standardize idempotent reconciliation and drift detection across controllers.
    • Migrated IstioCSR and TrustManager resources (Services, ServiceAccounts, Certificates, RBAC, Deployments, and webhook configurations) to the shared apply/patch workflow.
  • Bug Fixes

    • Improved RoleBinding reconciliation by handling immutable roleRef drift (replaces the existing binding when needed).
  • Tests

    • Updated/expanded unit tests and assertions to match apply-based behavior and standardized error wording.
    • Added coverage for the shared apply helper and IstioCSR network policy handling.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 6, 2026
@openshift-ci-robot

openshift-ci-robot commented May 6, 2026

Copy link
Copy Markdown

@sebrandon1: This pull request references CM-1040 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Adds a generic common.ApplyResource[T]() helper for SSA-based reconciliation with pluggable drift detection callbacks
  • Migrates trustmanager's 11 createOrApply methods to use the shared helper
  • Migrates istiocsr's 8 simple createOrApply methods from Create/UpdateWithRetry to SSA via the shared helper
  • Keeps istiocsr's complex ClusterRole/ClusterRoleBinding methods unchanged (they use GenerateName + List fallback + Delete for immutable RoleRef)
  • Drops istioCSRCreateRecon warning events from migrated methods (SSA is inherently idempotent)
  • Net -501 lines of duplicated boilerplate

Test plan

  • go test ./pkg/controller/common/... passes
  • go test ./pkg/controller/istiocsr/... passes
  • go test ./pkg/controller/trustmanager/... passes
  • go build ./... succeeds
  • make lint shows only pre-existing issues (9 total, none introduced)

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 openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown

Walkthrough

This PR adds a shared Server-Side Apply helper and routes IstioCSR and TrustManager reconciliation for multiple Kubernetes resources through it. Tests now validate patch-based behavior and standardized error messages.

Changes

Shared SSA reconciliation

Layer / File(s) Summary
Shared apply helper and ownership
pkg/controller/common/applier.go, pkg/controller/common/applier_test.go, pkg/controller/istiocsr/constants.go
Adds generic SSA reconciliation with field ownership, drift detection, error wrapping, reconciliation events, and error-classification tests.
IstioCSR resource migration
pkg/controller/istiocsr/*.go, pkg/controller/istiocsr/*_test.go
Migrates services, certificates, service accounts, network policies, Roles, and RoleBindings to the shared helper; immutable roleRef changes delete bindings before apply.
TrustManager resource migration
pkg/controller/trustmanager/*.go, pkg/controller/trustmanager/*_test.go
Migrates certificates, deployments, RBAC resources, services, service accounts, and webhook configurations to shared apply reconciliation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: swghosh, mytreya-rh


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Stable And Deterministic Test Names ❌ Error pkg/controller/istiocsr/networkpolicies_test.go uses t.Run(assetPath), so the subtest title is derived from filenames instead of a fixed descriptive string. Use static subtest names like the policy purpose; keep the asset path in assertions/body, not in the title.
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 (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the shared ApplyResource extraction and the SSA migration work, even though it understates the trustmanager scope.
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.
Test Structure And Quality ✅ Passed PASS: The changed tests are plain table-driven unit tests, not Ginkgo/e2e; no Eventually/BeforeEach/AfterEach or cluster resources appear, and they follow existing fake-client patterns.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the changed tests are standard unit tests and don’t trigger MicroShift API compatibility checks.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added; the changed files are plain unit tests and contain no SNO/multi-node assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed Modified files only refactor reconciliation to ApplyResource; no new node selectors, anti-affinity, spread constraints, or replica logic were added.
Ote Binary Stdout Contract ✅ Passed Changed files contain no main/init/TestMain/BeforeSuite hooks or stdout-printing calls; only controller logic and ordinary tests were modified.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the changed tests are plain testing.T unit tests with no IPv4 hardcoding or external network calls.
No-Weak-Crypto ✅ Passed Scanned changed Go files and found no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB use, custom crypto, or secret/token comparisons; only benign spec equality checks.
Container-Privileges ✅ Passed No changed manifest files or securityContext/privilege settings were introduced; the PR only refactors Go reconciliation code.
No-Sensitive-Data-In-Logs ✅ Passed New/changed logs only emit resource kind, namespace, and name; no passwords, tokens, PII, or customer data are logged.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci
openshift-ci Bot requested review from mytreya-rh and swghosh May 6, 2026 18:32
@openshift-ci

openshift-ci Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: sebrandon1
Once this PR has been reviewed and has the lgtm label, please assign mytreya-rh for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@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: 1

🧹 Nitpick comments (2)
pkg/controller/istiocsr/install_instiocsr_test.go (1)

68-84: ⚡ Quick win

Preserve generated-name simulation for ClusterRole in these fakes.

createOrApplyClusterRoles() still depends on Create mutating the object with a generated name before status is written and before the ClusterRoleBinding gets its RoleRef.Name. These stubs only backfill ClusterRoleBinding, so the test can still pass even if the role name is left empty. I'd add a *rbacv1.ClusterRole branch in each CreateCalls block as well.

Representative tweak
m.CreateCalls(func(ctx context.Context, obj client.Object, option ...client.CreateOption) error {
	switch o := obj.(type) {
+	case *rbacv1.ClusterRole:
+		role := testClusterRole()
+		role.DeepCopyInto(o)
 	case *appsv1.Deployment:
 		if !reflect.DeepEqual(o.GetLabels(), labels) {
 			return fmt.Errorf("labels mismatch in %v resource; got: %v, want: %v", o, o.GetLabels(), labels)
 		}

Also applies to: 110-117, 131-138

🤖 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 `@pkg/controller/istiocsr/install_instiocsr_test.go` around lines 68 - 84, The
CreateCalls test stubs need to simulate Create mutating a ClusterRole with a
generated name so createOrApplyClusterRoles() sees a non-empty Role.Name; update
the CreateCalls handlers (the ones that currently switch over *appsv1.Deployment
and *rbacv1.ClusterRoleBinding) to also include a case for *rbacv1.ClusterRole
that sets o.Name to a generated value (e.g., append "-generated" or a
deterministic string) and preserves labels so subsequent logic that reads the
ClusterRole's name (and the ClusterRoleBinding RoleRef.Name) behaves as in real
Create; apply this same addition to the other CreateCalls blocks mentioned.
pkg/controller/trustmanager/webhooks_test.go (1)

207-221: ⚡ Quick win

Keep the error assertion specific to the webhook config.

ApplyResource still includes the resource name in the returned error, so shortening these expectations to just failed to ... resource makes this table much less discriminating. A wrong object name or an extra apply call in this path would still satisfy the assertion. I'd keep the expected substring specific to trustManagerWebhookConfigName here, and mirror that in the other migrated reconciliation tests.

🤖 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 `@pkg/controller/trustmanager/webhooks_test.go` around lines 207 - 221, The
test's error expectation is too generic; update the table entries (the case with
name "patch error propagates" and similar migrated reconciliation tests) to
assert the error message includes the specific webhook resource name by matching
the substring that contains trustManagerWebhookConfigName (the Reconciler's
ApplyResource error includes the resource name), e.g. expect the returned error
to contain trustManagerWebhookConfigName along with "failed to apply resource",
and adjust other tests that assert "failed to check if resource" / "failed to
apply resource" to similarly include trustManagerWebhookConfigName so the
assertions target the specific webhook config rather than any resource.
🤖 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 `@pkg/controller/common/applier.go`:
- Around line 33-36: The resourceName construction in applier.go currently uses
fmt.Sprintf("%s/%s", desired.GetNamespace(), desired.GetName()) which yields
"/name" for cluster-scoped objects; change the logic to detect an empty
namespace (desired.GetNamespace() == "") and build resourceName as just
desired.GetName(), otherwise build it as namespace + "/" + name so
cluster-scoped resources do not get a leading slash; update any use of the
existing resourceName variable accordingly.

---

Nitpick comments:
In `@pkg/controller/istiocsr/install_instiocsr_test.go`:
- Around line 68-84: The CreateCalls test stubs need to simulate Create mutating
a ClusterRole with a generated name so createOrApplyClusterRoles() sees a
non-empty Role.Name; update the CreateCalls handlers (the ones that currently
switch over *appsv1.Deployment and *rbacv1.ClusterRoleBinding) to also include a
case for *rbacv1.ClusterRole that sets o.Name to a generated value (e.g., append
"-generated" or a deterministic string) and preserves labels so subsequent logic
that reads the ClusterRole's name (and the ClusterRoleBinding RoleRef.Name)
behaves as in real Create; apply this same addition to the other CreateCalls
blocks mentioned.

In `@pkg/controller/trustmanager/webhooks_test.go`:
- Around line 207-221: The test's error expectation is too generic; update the
table entries (the case with name "patch error propagates" and similar migrated
reconciliation tests) to assert the error message includes the specific webhook
resource name by matching the substring that contains
trustManagerWebhookConfigName (the Reconciler's ApplyResource error includes the
resource name), e.g. expect the returned error to contain
trustManagerWebhookConfigName along with "failed to apply resource", and adjust
other tests that assert "failed to check if resource" / "failed to apply
resource" to similarly include trustManagerWebhookConfigName so the assertions
target the specific webhook config rather than any resource.
🪄 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: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 683e1b36-07c6-463b-8cd3-d29a46add8d5

📥 Commits

Reviewing files that changed from the base of the PR and between a2e7514 and f8b7c81.

📒 Files selected for processing (26)
  • pkg/controller/common/applier.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/istiocsr/constants.go
  • pkg/controller/istiocsr/install_instiocsr_test.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/istiocsr/networkpolicies.go
  • pkg/controller/istiocsr/rbacs.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/istiocsr/serviceaccounts.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/controller_test.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/trustmanager/deployments_test.go
  • pkg/controller/trustmanager/rbacs.go
  • pkg/controller/trustmanager/rbacs_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/trustmanager/services.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/trustmanager/webhooks_test.go

Comment thread pkg/controller/common/applier.go Outdated
@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from ca8b171 to fdd735e Compare May 6, 2026 18:48

@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: 1

🧹 Nitpick comments (1)
pkg/controller/istiocsr/serviceaccounts_test.go (1)

22-25: ⚡ Quick win

Cover the no-op branch explicitly.

Now that this table has assertCalls, the "serviceaccount reconciliation successful" case should also assert PatchCallCount() == 0. Right now that case still passes if ApplyResource starts patching unchanged ServiceAccounts on every reconcile, which is one of the main regression risks in this SSA migration.

Suggested assertion
 		{
 			name: "serviceaccount reconciliation successful",
 			preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
 				m.ExistsCalls(func(ctx context.Context, ns types.NamespacedName, obj client.Object) (bool, error) {
 					switch o := obj.(type) {
 					case *corev1.ServiceAccount:
 						serviceaccount := testServiceAccount()
 						serviceaccount.DeepCopyInto(o)
 					}
 					return true, nil
 				})
 			},
+			assertCalls: func(t *testing.T, mock *fakes.FakeCtrlClient) {
+				if mock.PatchCallCount() != 0 {
+					t.Errorf("createOrApplyServiceAccounts() Patch call count: %d, want 0", mock.PatchCallCount())
+				}
+			},
 		},
🤖 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 `@pkg/controller/istiocsr/serviceaccounts_test.go` around lines 22 - 25, Update
the "serviceaccount reconciliation successful" testcase in the table-driven test
in serviceaccounts_test.go to explicitly assert that no patch operations
occurred: inside its assertCalls function, call mock.PatchCallCount() and
require it equals 0 (on the provided *fakes.FakeCtrlClient) to ensure
ApplyResource did not issue patches for unchanged ServiceAccounts; keep other
existing assertions and reference the Reconciler and ApplyResource behavior as
context.
🤖 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 `@pkg/controller/istiocsr/rbacs.go`:
- Around line 265-269: createOrApplyRoleBindings and
createOrApplyRoleBindingForLeases currently always call common.ApplyResource
(Server-Side Apply) but RoleBinding.roleRef is immutable—mirror the
ClusterRoleBinding handler's pattern: after calling common.ApplyResource (with
hasObjectChanged from getRoleBindingObject/hasObjectChanged), detect when the
failure or diff indicates only a roleRef drift (compare desired.RoleRef to the
live object.RoleRef), then delete the existing rbacv1.RoleBinding and recreate
the desired object (preserving owner refs/events/fieldOwner) as a fallback;
implement this delete-then-create flow in both createOrApplyRoleBindings and
createOrApplyRoleBindingForLeases using the same logic used in the
ClusterRoleBinding handler to avoid permanent SSA validation errors.

---

Nitpick comments:
In `@pkg/controller/istiocsr/serviceaccounts_test.go`:
- Around line 22-25: Update the "serviceaccount reconciliation successful"
testcase in the table-driven test in serviceaccounts_test.go to explicitly
assert that no patch operations occurred: inside its assertCalls function, call
mock.PatchCallCount() and require it equals 0 (on the provided
*fakes.FakeCtrlClient) to ensure ApplyResource did not issue patches for
unchanged ServiceAccounts; keep other existing assertions and reference the
Reconciler and ApplyResource behavior as context.
🪄 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: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3367fe15-60ea-4966-a17e-6222e23128a6

📥 Commits

Reviewing files that changed from the base of the PR and between f8b7c81 and fdd735e.

📒 Files selected for processing (26)
  • pkg/controller/common/applier.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/istiocsr/constants.go
  • pkg/controller/istiocsr/install_instiocsr_test.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/istiocsr/networkpolicies.go
  • pkg/controller/istiocsr/rbacs.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/istiocsr/serviceaccounts.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/controller_test.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/trustmanager/deployments_test.go
  • pkg/controller/trustmanager/rbacs.go
  • pkg/controller/trustmanager/rbacs_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/trustmanager/services.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/trustmanager/webhooks_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/certificates_test.go

Comment thread pkg/controller/istiocsr/rbacs.go
@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from fdd735e to 26c1bb6 Compare May 14, 2026 19:07
@sebrandon1

Copy link
Copy Markdown
Member Author

/retest

@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from 26c1bb6 to 8b48aaa Compare May 29, 2026 15:51
@sebrandon1

Copy link
Copy Markdown
Member Author

/retest

@sebrandon1

Copy link
Copy Markdown
Member Author

/retest-required

@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from 8b48aaa to 4442995 Compare June 15, 2026 16:25
@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from 4442995 to 786945d Compare June 24, 2026 19:51
@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from 786945d to 81c1b58 Compare July 6, 2026 16:17
@sebrandon1

Copy link
Copy Markdown
Member Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

@sebrandon1

Copy link
Copy Markdown
Member Author

Addressed CodeRabbit feedback on RoleBinding.roleRef immutability:

  • Added roleRef drift detection to createOrApplyRoleBindings and createOrApplyRoleBindingForLeases
  • If roleRef has changed, the existing binding is deleted before ApplyResource is called
  • This prevents SSA validation errors when roleRef changes (roleRef is immutable)
  • Mirrors the pattern already used in handleClusterRoleBindingModification

All tests pass with 85.2% coverage on istiocsr package.

@sebrandon1

Copy link
Copy Markdown
Member Author

/retest

@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from d4919c6 to edaac18 Compare July 13, 2026 17:58

@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 (1)
pkg/controller/istiocsr/rbacs.go (1)

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

Extract shared helper for RoleBinding roleRef drift/delete logic.

createOrApplyRoleBindings and createOrApplyRoleBindingForLeases duplicate ~18 nearly-identical lines (Exists check, rbacRoleBindingRefModified check, log, Delete with NotFound tolerance). Given this PR's stated goal of removing duplicated boilerplate, extract this into a shared helper, e.g. deleteRoleBindingIfRoleRefChanged(desired *rbacv1.RoleBinding) error.

♻️ Proposed refactor
+func (r *Reconciler) deleteRoleBindingIfRoleRefChanged(desired *rbacv1.RoleBinding) error {
+	key := client.ObjectKeyFromObject(desired)
+	existing := &rbacv1.RoleBinding{}
+	exists, err := r.Exists(r.ctx, key, existing)
+	if err != nil {
+		return common.FromClientError(err, "failed to check if RoleBinding %q exists", key)
+	}
+	if exists && rbacRoleBindingRefModified(desired, existing) {
+		r.log.V(1).Info("rolebinding roleRef changed, deleting for recreation (roleRef is immutable)", "name", key)
+		if err := r.Delete(r.ctx, existing); err != nil && !apierrors.IsNotFound(err) {
+			return common.FromClientError(err, "failed to delete RoleBinding %q to replace roleRef", key)
+		}
+	}
+	return nil
+}
+
 func (r *Reconciler) createOrApplyRoleBindings(istiocsr *v1alpha1.IstioCSR, serviceAccount string, resourceLabels map[string]string) error {
 	desired := r.getRoleBindingObject(serviceAccount, istiocsr.GetNamespace(), istiocsr.Spec.IstioCSRConfig.Istio.Namespace, resourceLabels)
-
-	// RoleBinding.roleRef is immutable; if it has changed, delete the existing binding first
-	key := client.ObjectKeyFromObject(desired)
-	existing := &rbacv1.RoleBinding{}
-	exists, err := r.Exists(r.ctx, key, existing)
-	if err != nil {
-		return common.FromClientError(err, "failed to check if RoleBinding %q exists", key)
-	}
-	if exists && rbacRoleBindingRefModified(desired, existing) {
-		r.log.V(1).Info("rolebinding roleRef changed, deleting for recreation (roleRef is immutable)", "name", key)
-		if err := r.Delete(r.ctx, existing); err != nil {
-			if !apierrors.IsNotFound(err) {
-				return common.FromClientError(err, "failed to delete RoleBinding %q to replace roleRef", key)
-			}
-		}
-	}
+	if err := r.deleteRoleBindingIfRoleRefChanged(desired); err != nil {
+		return err
+	}
 
 	return common.ApplyResource(r.ctx, r.CtrlClient, r.log, r.eventRecorder, istiocsr, desired, &rbacv1.RoleBinding{}, fieldOwner,
 		func(d, e *rbacv1.RoleBinding) bool { return hasObjectChanged(d, e) },
 	)
 }

Apply the analogous change to createOrApplyRoleBindingForLeases.

Also applies to: 331-352

🤖 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 `@pkg/controller/istiocsr/rbacs.go` around lines 285 - 306, Extract the
duplicated RoleBinding roleRef drift handling from createOrApplyRoleBindings and
createOrApplyRoleBindingForLeases into a shared helper such as
deleteRoleBindingIfRoleRefChanged, accepting the desired RoleBinding. Move the
Exists check, rbacRoleBindingRefModified comparison, diagnostic log, deletion,
and NotFound tolerance into that helper, then invoke it from both creation
methods before applying the resource.
🤖 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 `@pkg/controller/istiocsr/rbacs.go`:
- Around line 285-306: Extract the duplicated RoleBinding roleRef drift handling
from createOrApplyRoleBindings and createOrApplyRoleBindingForLeases into a
shared helper such as deleteRoleBindingIfRoleRefChanged, accepting the desired
RoleBinding. Move the Exists check, rbacRoleBindingRefModified comparison,
diagnostic log, deletion, and NotFound tolerance into that helper, then invoke
it from both creation methods before applying the resource.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a0bb173e-0351-4833-bd59-fa1f25c895cb

📥 Commits

Reviewing files that changed from the base of the PR and between 8b48aaa and edaac18.

📒 Files selected for processing (26)
  • pkg/controller/common/applier.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/istiocsr/constants.go
  • pkg/controller/istiocsr/install_instiocsr_test.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/istiocsr/networkpolicies.go
  • pkg/controller/istiocsr/rbacs.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/istiocsr/serviceaccounts.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/controller_test.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/trustmanager/deployments_test.go
  • pkg/controller/trustmanager/rbacs.go
  • pkg/controller/trustmanager/rbacs_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/trustmanager/services.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/trustmanager/webhooks_test.go
🚧 Files skipped from review as they are similar to previous changes (23)
  • pkg/controller/common/applier.go
  • pkg/controller/istiocsr/constants.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/trustmanager/deployments_test.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/istiocsr/serviceaccounts.go
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/trustmanager/webhooks_test.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/istiocsr/install_instiocsr_test.go
  • pkg/controller/trustmanager/rbacs_test.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/trustmanager/rbacs.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/istiocsr/networkpolicies.go

@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from edaac18 to b919b00 Compare July 17, 2026 18:55

@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 (1)
pkg/controller/istiocsr/install_instiocsr_test.go (1)

51-67: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the SSA patch contract, not only labels.

This stub accepts any patch type/options and does not assert the expected patched resource set. A regression to a non-SSA patch—or skipping a migrated resource—would still pass. Assert client.Apply, the field-owner/force options, and expected Patch calls via the fake’s recorded arguments.

🤖 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 `@pkg/controller/istiocsr/install_instiocsr_test.go` around lines 51 - 67,
Update the PatchCalls assertion around the SSA-migrated resources to validate
the full apply contract: require a client.Apply patch, the expected field-owner
and force options, and exactly the expected Service, ServiceAccount,
Certificate, Role, and RoleBinding patch calls using the fake’s recorded
arguments. Preserve the existing label assertions while rejecting skipped
resources or non-SSA patches.
🤖 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 `@pkg/controller/istiocsr/install_instiocsr_test.go`:
- Around line 51-67: Update the PatchCalls assertion around the SSA-migrated
resources to validate the full apply contract: require a client.Apply patch, the
expected field-owner and force options, and exactly the expected Service,
ServiceAccount, Certificate, Role, and RoleBinding patch calls using the fake’s
recorded arguments. Preserve the existing label assertions while rejecting
skipped resources or non-SSA patches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a104d795-c66e-4f2b-acf9-4a6a4f27e78f

📥 Commits

Reviewing files that changed from the base of the PR and between edaac18 and b919b00.

📒 Files selected for processing (26)
  • pkg/controller/common/applier.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/istiocsr/constants.go
  • pkg/controller/istiocsr/install_instiocsr_test.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/istiocsr/networkpolicies.go
  • pkg/controller/istiocsr/rbacs.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/istiocsr/serviceaccounts.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/controller_test.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/trustmanager/deployments_test.go
  • pkg/controller/trustmanager/rbacs.go
  • pkg/controller/trustmanager/rbacs_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/trustmanager/services.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/trustmanager/webhooks_test.go
🚧 Files skipped from review as they are similar to previous changes (22)
  • pkg/controller/trustmanager/controller_test.go
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/common/applier.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/deployments_test.go
  • pkg/controller/trustmanager/webhooks_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/services.go
  • pkg/controller/istiocsr/networkpolicies.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/serviceaccounts.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/trustmanager/rbacs.go

Extract a generic ApplyResource[T] function for Server-Side Apply
reconciliation and migrate istiocsr controllers to use it. Handle
RoleBinding.roleRef immutability by deleting and recreating when
the roleRef changes.

Add direct unit tests for ApplyResource covering create, no-op,
update, error handling, and error classification (irrecoverable vs
retryable). Add networkpolicies_test.go with tests for asset
decoding, namespace fallback, full apply, and error propagation.
@sebrandon1
sebrandon1 force-pushed the extract-apply-resource branch from b919b00 to 45acb13 Compare July 17, 2026 19:00

@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 (1)
pkg/controller/common/applier_test.go (1)

47-49: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the SSA patch contract, not just the call count.

This stub discards client.Apply, FieldOwner, and ForceOwnership. A regression to a non-SSA patch or missing ownership options would still pass every test here. Capture the patch/options and assert them in a successful apply case.

🤖 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 `@pkg/controller/common/applier_test.go` around lines 47 - 49, Update
stubCtrlClient.Patch to retain the received client.Patch and PatchOption values,
then extend the successful apply test assertions to verify client.Apply is used
with the expected FieldOwner and ForceOwnership options, in addition to checking
the patch count.
🤖 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 `@pkg/controller/common/applier_test.go`:
- Around line 47-49: Update stubCtrlClient.Patch to retain the received
client.Patch and PatchOption values, then extend the successful apply test
assertions to verify client.Apply is used with the expected FieldOwner and
ForceOwnership options, in addition to checking the patch count.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 37a2c255-13f8-4e8a-9a03-a2cad993605a

📥 Commits

Reviewing files that changed from the base of the PR and between b919b00 and 45acb13.

📒 Files selected for processing (28)
  • pkg/controller/common/applier.go
  • pkg/controller/common/applier_test.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/istiocsr/constants.go
  • pkg/controller/istiocsr/install_instiocsr_test.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/istiocsr/networkpolicies.go
  • pkg/controller/istiocsr/networkpolicies_test.go
  • pkg/controller/istiocsr/rbacs.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/istiocsr/serviceaccounts.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/controller_test.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/trustmanager/deployments_test.go
  • pkg/controller/trustmanager/rbacs.go
  • pkg/controller/trustmanager/rbacs_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/trustmanager/services.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/trustmanager/webhooks_test.go
🚧 Files skipped from review as they are similar to previous changes (23)
  • pkg/controller/trustmanager/serviceaccounts_test.go
  • pkg/controller/istiocsr/constants.go
  • pkg/controller/trustmanager/rbacs_test.go
  • pkg/controller/istiocsr/install_istiocsr.go
  • pkg/controller/common/applier.go
  • pkg/controller/istiocsr/certificates_test.go
  • pkg/controller/trustmanager/services.go
  • pkg/controller/trustmanager/certificates_test.go
  • pkg/controller/trustmanager/controller_test.go
  • pkg/controller/trustmanager/webhooks_test.go
  • pkg/controller/istiocsr/services_test.go
  • pkg/controller/trustmanager/services_test.go
  • pkg/controller/trustmanager/serviceaccounts.go
  • pkg/controller/istiocsr/networkpolicies.go
  • pkg/controller/istiocsr/install_instiocsr_test.go
  • pkg/controller/trustmanager/webhooks.go
  • pkg/controller/istiocsr/rbacs_test.go
  • pkg/controller/istiocsr/services.go
  • pkg/controller/istiocsr/certificates.go
  • pkg/controller/trustmanager/deployments.go
  • pkg/controller/istiocsr/serviceaccounts_test.go
  • pkg/controller/trustmanager/certificates.go
  • pkg/controller/trustmanager/rbacs.go

@openshift-ci

openshift-ci Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@sebrandon1: The following tests 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-operator 45acb13 link true /test e2e-operator
ci/prow/e2e-operator-tech-preview 45acb13 link false /test e2e-operator-tech-preview

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.

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

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants