Skip to content

ESO-396: Mount user configured trustedCABundle on external-secrets core controller#149

Open
bharath-b-rh wants to merge 2 commits into
openshift:mainfrom
bharath-b-rh:eso-396
Open

ESO-396: Mount user configured trustedCABundle on external-secrets core controller#149
bharath-b-rh wants to merge 2 commits into
openshift:mainfrom
bharath-b-rh:eso-396

Conversation

@bharath-b-rh

@bharath-b-rh bharath-b-rh commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implement trustedCABundle reconciliation: validate PEM CA certs, mount user-ca-bundle volume and SSL_CERT_DIR on the core controller only
  • Add ConfigMap watch (namespace-scoped cache + watching label) for self-healing when bundle data is fixed
  • Introduce UserTrustedCABundleError with Degraded status; NotFound requeues, invalid PEM recovers via watch
  • Skip redundant user mount when CNO inject label + proxy are both active (proxy bundle already mounted)
  • Export operand/trusted-CA constants from external_secrets package; fix certificate issuer-not-found error handling
  • Add unit and e2e coverage for happy path, Degraded cases, and recovery scenarios

Test plan

  • unit tests - make test-unit
  • api integration tests - make test-apis
  • e2e: -ginkgo.focus-file=trusted_ca_bundle_test.go
  • Manual:
  • Set trustedCABundle with valid PEM ConfigMap → Ready=True, user-ca-bundle volume + SSL_CERT_DIR on core controller only
  • Clear trustedCABundle from spec → volume and SSL_CERT_DIR removed, operator stays Ready
  • Reference missing ConfigMap → Degraded=True, NotFound message
  • ConfigMap missing expected key → Degraded=True
  • ConfigMap with invalid PEM → Degraded=True, InvalidTrustedCABundle event
  • ConfigMap with leaf (non-CA) cert → Degraded=True, TrustedCABundleNotCACertificate event
  • ConfigMap with private key PEM → Degraded=True, TrustedCABundlePrivateKeyRejected event
  • Fix invalid PEM in ConfigMap only (no spec change) → recovers to Ready=True
  • Create missing ConfigMap after initial Degraded → recovers to Ready=True (~30s)
  • Delete referenced ConfigMap after success → Degraded=True, stale volume/SSL_CERT_DIR removed from deployment
  • ConfigMap gets externalsecretsconfig.operator.openshift.io/watching=true label after reconcile
  • CNO inject label, no proxy → user CA bundle still mounted
  • CNO inject label + proxy enabled → user mount skipped, TrustedCABundleSkippedCNOProxy event, operator Ready
  • Webhook and cert-controller deployments never get user-ca-bundle or SSL_CERT_DIR
  • HTTPS backend signed by user CA works (no x509: unknown authority in core controller logs)
  • Cert-manager with missing issuer → clear error message (not )

Summary by CodeRabbit

  • New Features

    • Improved trusted CA bundle handling: validation, mount/ENV behavior, degraded-state reporting, and clearer proxy-aware behavior.
  • Bug Fixes

    • Prevent unintended user-CA injection when proxy injection is enabled; clarify proxy TLS certificate fallback and reconcile behavior for missing/invalid bundles.
  • Documentation

    • API docs and CRD descriptions updated to clarify trustedCABundle constraints and TLS fallback semantics.
  • Tests

    • Expanded unit and e2e coverage for CA bundle, proxy, deployment, and reconciliation scenarios.

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

openshift-ci-robot commented Jun 5, 2026

Copy link
Copy Markdown

@bharath-b-rh: This pull request references ESO-396 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 story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Implement trustedCABundle reconciliation: validate PEM CA certs, mount user-ca-bundle volume and SSL_CERT_DIR on the core controller only
  • Add ConfigMap watch (namespace-scoped cache + watching label) for self-healing when bundle data is fixed
  • Introduce UserTrustedCABundleError with Degraded status; NotFound requeues, invalid PEM recovers via watch
  • Skip redundant user mount when CNO inject label + proxy are both active (proxy bundle already mounted)
  • Export operand/trusted-CA constants from external_secrets package; fix certificate issuer-not-found error handling
  • Add unit and e2e coverage for happy path, Degraded cases, and recovery scenarios

Test plan

  • unit tests - make test-unit
  • api integration tests - make test-apis
  • e2e: -ginkgo.focus-file=trusted_ca_bundle_test.go
  • Manual:
  • Set trustedCABundle with valid PEM ConfigMap → Ready=True, user-ca-bundle volume + SSL_CERT_DIR on core controller only
  • Clear trustedCABundle from spec → volume and SSL_CERT_DIR removed, operator stays Ready
  • Reference missing ConfigMap → Degraded=True, NotFound message
  • ConfigMap missing expected key → Degraded=True
  • ConfigMap with invalid PEM → Degraded=True, InvalidTrustedCABundle event
  • ConfigMap with leaf (non-CA) cert → Degraded=True, TrustedCABundleNotCACertificate event
  • ConfigMap with private key PEM → Degraded=True, TrustedCABundlePrivateKeyRejected event
  • Fix invalid PEM in ConfigMap only (no spec change) → recovers to Ready=True
  • Create missing ConfigMap after initial Degraded → recovers to Ready=True (~30s)
  • Delete referenced ConfigMap after success → Degraded=True, stale volume/SSL_CERT_DIR removed from deployment
  • ConfigMap gets externalsecretsconfig.operator.openshift.io/watching=true label after reconcile
  • CNO inject label, no proxy → user CA bundle still mounted
  • CNO inject label + proxy enabled → user mount skipped, TrustedCABundleSkippedCNOProxy event, operator Ready
  • Webhook and cert-controller deployments never get user-ca-bundle or SSL_CERT_DIR
  • HTTPS backend signed by user CA works (no x509: unknown authority in core controller logs)
  • Cert-manager with missing issuer → clear error message (not )

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 Jun 5, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: f0e968d7-7ab1-4f65-b6ef-5c7ca98ef874

📥 Commits

Reviewing files that changed from the base of the PR and between fa603bf and 3ca3da6.

⛔ Files ignored due to path filters (60)
  • cmd/external-secrets-operator/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • test/go.sum is excluded by !**/*.sum
  • tools/go.sum is excluded by !**/*.sum
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/id.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/number.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/status.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/traces.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/internal/telemetry/value.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/auto/sdk/tracer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/.codespellignore is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/.lycheeignore is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/RELEASING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/VERSIONING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/encoder.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/internal/attribute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/internal/xxhash/xxhash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/set.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/type_string.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/attribute/value.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/baggage/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/dependencies.Dockerfile is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/errorhandler/errorhandler.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/handler.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/instruments.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/meter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/internal/global/state.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/asyncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/meter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/noop/noop.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncfloat64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/metric/syncint64.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/baggage.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/propagation/trace_context.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.37.0/error_type.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/MIGRATION.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/attribute_group.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/error_type.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/exception.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/semconv/v1.39.0/schema.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/auto.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/config.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/span.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/trace/tracestate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.opentelemetry.io/otel/versions.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (11)
  • cmd/external-secrets-operator/go.mod
  • go.mod
  • pkg/controller/external_secrets/certificate.go
  • pkg/controller/external_secrets/deployments.go
  • pkg/controller/external_secrets/deployments_test.go
  • pkg/controller/external_secrets/trusted_ca_bundle.go
  • pkg/controller/external_secrets/trusted_ca_bundle_test.go
  • test/e2e/e2e_test.go
  • test/go.mod
  • test/utils/cleanup.go
  • tools/go.mod
🚧 Files skipped from review as they are similar to previous changes (11)
  • tools/go.mod
  • go.mod
  • test/go.mod
  • pkg/controller/external_secrets/certificate.go
  • cmd/external-secrets-operator/go.mod
  • test/utils/cleanup.go
  • pkg/controller/external_secrets/trusted_ca_bundle_test.go
  • pkg/controller/external_secrets/trusted_ca_bundle.go
  • test/e2e/e2e_test.go
  • pkg/controller/external_secrets/deployments_test.go
  • pkg/controller/external_secrets/deployments.go

Walkthrough

Adds validated trusted CA bundle support, refactors controller cache/watch and reconcile flow, introduces a user-trusted-CA error kind, rewires deployment proxy and CA wiring, fixes certificate issuer lookup, and expands unit and e2e tests, docs, and constants.

Changes

Trusted CA Bundle Feature Implementation

Layer / File(s) Summary
API, CRD and docs
api/v1alpha1/*, config/crd/bases/*, bundle/manifests/*, docs/api_reference.md
Adds ExternalSecretsConfig GVR and refines trustedCABundle and proxy.networkPolicyProvisioning descriptions; updates CSV timestamp.
Constants and shared names
pkg/controller/external_secrets/constants.go, pkg/controller/commontest/utils.go, test/utils/*
Exports operand/deployment/container/pod-prefix constants, managed/watched label keys, trusted CA config/volume/mount names, and switches tests to shared constants.
Error kinds and predicates
pkg/controller/common/errors.go, pkg/controller/common/errors_test.go
Adds UserTrustedCABundleError, constructor and predicates, and unit tests for predicates and FromClientError behavior.
Trusted CA PEM validation
pkg/controller/external_secrets/trusted_ca_bundle.go, *_test.go
Parses and validates PEM CA bundles, rejects private keys/non-CA certs, returns typed validation errors, emits throttled Warning events, with comprehensive unit tests.
Controller cache/watch & reconciler refactor
pkg/controller/external_secrets/controller.go, utils.go, controller_test.go, utils_test.go
Implements label-driven managed/watch mapping, namespace-scoped ConfigMap cache for trusted CABundle, getWithCacheFallback, updateWatchLabel, proxy status tracking, now clock, structured reconcile result handling, and updated SetupWithManager; includes tests.
Deployment proxy and user CA wiring
pkg/controller/external_secrets/deployments.go, deployments_test.go
Propagates trusted-CA errors from deployment assembly, adds apply/remove user CA config, replaces proxy/env/volume logic with deterministic merge/prune helpers, adds mergeUserEnvVars and extensive tests including TestApplyUserCABundleConfig.
Trusted CA ConfigMap reconciliation
pkg/controller/external_secrets/configmap.go
Gates operator-managed proxy trusted CA ConfigMap creation on proxy enabled, uses ProxyTrustedCABundleConfigMapName, reorders create/update paths, and uses injection label constant.
Certificate issuer lookup fixes
pkg/controller/external_secrets/certificate.go, certificate_test.go
Returns ReconcileError directly when appropriate, separates fetch vs not-found handling, tightens issuer key construction, and adds a missing-issuer test case.
Failure classification & status helpers
pkg/controller/external_secrets/controller.go, controller_failure_test.go
Adds helpers to translate deployment failures into Ready/Degraded conditions and requeue semantics; unit tests added.
Test utilities and e2e suites
test/*, test/utils/*, test/e2e/*
Adds Trusted CA e2e suite, harmonizes tests to shared constants, adds helpers (IsCertManagerConfigEnabled, VerifyOperandPodsReady), updates cleanup/conditions to use ExternalSecretsConfigGVR, and updates test dependencies in go.mod.
Misc docs/comments & go.mod
pkg/version/version.go, test/go.mod, cmd/*, tools/*
Minor comment edits and OpenTelemetry/test indirect dependency version updates.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

docs-approved, lgtm

Suggested reviewers

  • mytreya-rh
  • TrilokGeer
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@openshift-ci openshift-ci Bot requested review from TrilokGeer and mytreya-rh June 5, 2026 07:34
@openshift-ci

openshift-ci Bot commented Jun 5, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: bharath-b-rh

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 Jun 5, 2026
…re controller

Signed-off-by: Bharath B <bhb@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: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/controller/external_secrets/controller.go (1)

314-322: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix watch registration: pointer-literal switch cases never match
In pkg/controller/external_secrets/controller.go, controllerManagedResources is a []client.Object holding pointer instances (e.g., &appsv1.Deployment{}, &corev1.Secret{}). The switch res { case &appsv1.Deployment{}: ... } compares pointer identities, so those case literals never match the slice elements and the default branch always runs.

Suggested fix
 	for _, res := range controllerManagedResources {
-		switch res {
-		case &appsv1.Deployment{}:
+		switch res.(type) {
+		case *appsv1.Deployment:
 			mgrBuilder.Watches(res, handler.EnqueueRequestsFromMapFunc(mapFunc), withIgnoreStatusUpdatePredicates)
-		case &corev1.Secret{}:
+		case *corev1.Secret:
 			mgrBuilder.WatchesMetadata(res, handler.EnqueueRequestsFromMapFunc(mapFunc), builder.WithPredicates(predicate.LabelChangedPredicate{}))
 		default:
 			mgrBuilder.Watches(res, handler.EnqueueRequestsFromMapFunc(mapFunc), managedResourcePredicate)
 		}
 	}
🤖 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/external_secrets/controller.go` around lines 314 - 322, The
switch in controller.go is comparing pointer literal identities so cases like
"&appsv1.Deployment{}" never match elements from controllerManagedResources;
change the logic to type-switch or compare concrete types instead: iterate
controllerManagedResources and use a type switch on the element (or
reflect.TypeOf(res)) to detect *appsv1.Deployment and *corev1.Secret and then
call mgrBuilder.Watches/mgrBuilder.WatchesMetadata with the appropriate
predicates (preserving handler.EnqueueRequestsFromMapFunc(mapFunc),
withIgnoreStatusUpdatePredicates,
builder.WithPredicates(predicate.LabelChangedPredicate{}), and
managedResourcePredicate).
🧹 Nitpick comments (2)
test/e2e/e2e_test.go (1)

401-403: ⚡ Quick win

Avoid replacing the entire ControllerConfig when toggling env overrides.

These assignments wipe unrelated ControllerConfig fields and can create cross-test drift. Update only ComponentConfigs on the copied CR.

♻️ Proposed fix
-				updatedCR.Spec.ControllerConfig = operatorv1alpha1.ControllerConfig{
-					ComponentConfigs: applicableEnvConfigs,
-				}
+				updatedCR.Spec.ControllerConfig.ComponentConfigs = applicableEnvConfigs
-				updatedCR.Spec.ControllerConfig = operatorv1alpha1.ControllerConfig{
-					ComponentConfigs: nil,
-				}
+				updatedCR.Spec.ControllerConfig.ComponentConfigs = nil

Also applies to: 451-454

🤖 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 `@test/e2e/e2e_test.go` around lines 401 - 403, The test currently replaces the
whole updatedCR.Spec.ControllerConfig with a new ControllerConfig which wipes
other fields; instead assign only ComponentConfigs to preserve unrelated fields:
ensure updatedCR.Spec.ControllerConfig is non-nil (create a zero value if
needed) and set updatedCR.Spec.ControllerConfig.ComponentConfigs =
applicableEnvConfigs; apply the same change to the other similar assignment
later in the file where ControllerConfig is being replaced.
pkg/controller/external_secrets/deployments_test.go (1)

2027-2033: ⚡ Quick win

Avoid branching test setup by test-name string.

Line 2031 uses a literal test title to select behavior. This is brittle and can silently break setup on rename; use an explicit per-case flag instead.

Refactor to explicit case metadata
@@
 	tests := []struct {
 		name         string
 		esc          *v1alpha1.ExternalSecretsConfig
 		cm           *corev1.ConfigMap
+		cmNotFound   bool
 		deployment   *appsv1.Deployment
@@
 		{
 			name: "removes user CA config when ConfigMap is missing",
 			esc:  baseESC,
+			cmNotFound: true,
@@
-			case tt.name == "removes user CA config when ConfigMap is missing":
+			case tt.cmNotFound:
 				cached = &fakes.FakeCtrlClient{}
 				uncached = &fakes.FakeCtrlClient{}
🤖 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/external_secrets/deployments_test.go` around lines 2027 -
2033, The test currently branches setup on the literal test title (tt.name ==
"removes user CA config when ConfigMap is missing"); add an explicit per-case
flag to the test case struct (e.g., a bool like noConfigMapClients or
needsEmptyClients), update the affected test cases to set that flag, and replace
the name-based branch with a check of that flag in the switch that assigns
cached and uncached; keep the existing behavior by instantiating
&fakes.FakeCtrlClient{} for cached and uncached when the flag is set, otherwise
call setupConfigMapClients(t, tt.cm) when tt.cm != nil.
🤖 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/external_secrets/certificate.go`:
- Line 196: The error formatting uses types.NamespacedName variable key directly
with %q which yields noisy diagnostics; update the fmt.Errorf call to format the
key as a string (e.g., use key.String()) and pass that string to the formatter
(for example use "%s" with key.String() or "%q" with key.String()) in the return
statement that currently reads fmt.Errorf("failed to fetch %q issuer: %w", key,
err), referencing the key variable (types.NamespacedName) in the certificate
fetch logic.

In `@pkg/controller/external_secrets/controller.go`:
- Around line 205-206: The code ignores the error returned by
labels.NewRequirement when building managedResourceLabelReqSelector and uses a
value switch that compares pointer identity for elements from
controllerManagedResources, causing watches for Deployments/Secrets not to
register; fix by checking and returning/logging the error from
labels.NewRequirement when creating managedResourceLabelReq (used to build
managedResourceLabelReqSelector) instead of discarding it, and change the switch
over res in the controllerManagedResources loop to a type switch (e.g., switch
res.(type) { case *appsv1.Deployment: ... case *corev1.Secret: ... }) so the
cases match the actual pointer types and the special watches for
appsv1.Deployment and corev1.Secret are correctly registered.

In `@pkg/controller/external_secrets/deployments_test.go`:
- Around line 1874-1899: Enhance the tests to assert the SSL_CERT_DIR env var is
present only on the core controller container and absent elsewhere: in the
assertDeploy closure, after locating controller via findContainer(deployment,
OperandCoreControllerContainer) assert controller.Env contains a variable named
"SSL_CERT_DIR" (and optionally its expected value), then after locating the
sidecar via findContainer(deployment, "sidecar") assert sidecar.Env does NOT
contain "SSL_CERT_DIR"; apply the same absence assertion to the nil-config
cleanup test block (the other test around lines 1934-1950) so both the
controller-only and cleanup paths explicitly check SSL_CERT_DIR
presence/absence.

In `@pkg/controller/external_secrets/deployments.go`:
- Around line 128-136: The code returns early when applyUserCABundleConfig
returns a NotFound error, which prevents subsequent deployment assembly steps
(e.g., updateResourceRequirement, affinity/tolerations/nodeSelector, user
overrides, proxy wiring) from running; change the error handling in the block
that calls applyUserCABundleConfig so that if
common.IsUserTrustedCABundleNotFound(err) you do NOT return but instead record
or wrap the error and continue assembling the Deployment (i.e., proceed to call
updateResourceRequirement and the remaining wiring functions), while preserving
the existing behavior of returning nil, wrapped for all other errors from
applyUserCABundleConfig.
- Around line 520-543: mergeContainerEnvVars currently iterates the envVars map
in unpredictable order which can reorder container.Env and cause spurious diffs;
modify mergeContainerEnvVars to collect and sort the keys of envVars (e.g., into
a []string, sort.Strings(keys)), then iterate the sorted keys to append managed
env vars, and finally append existing container.Env entries that are not present
in envVars so the resulting container.Env order is deterministic.

In `@pkg/controller/external_secrets/trusted_ca_bundle.go`:
- Around line 97-139: parsePEMCABundle currently ignores any non-PEM trailing
bytes left in the rest buffer after the pem.Decode loop; after the loop (before
the caCount==0 check) validate that rest is empty or only contains
whitespace/newlines and if not return a trustedCABundleValidationError (use
eventReason trustedCABundleEventInvalidPEM) with a message indicating malformed
trailing data in the trusted CA bundle; reference the rest variable, the
pem.Decode loop, parsePEMCABundle function and trustedCABundleValidationError to
locate where to add this post-loop validation.

In `@test/e2e/trusted_ca_bundle_test.go`:
- Around line 118-125: The cleanup call that currently discards the result of
retry.RetryOnConflict must check and assert the error instead of ignoring it:
capture the returned error from the retry.RetryOnConflict call that modifies
ExternalSecretsConfig (the anonymous func that gets esc and sets
esc.Spec.ControllerConfig.TrustedCABundle = nil and calls
suiteRuntimeClient.Update), then assert the result is nil or allowable (e.g.
treat apierrors.IsNotFound(err) as success) so teardown failures aren’t
swallowed; update the AfterEach to assign the retry result to a variable and
perform the appropriate assertion/conditional handling around that variable.

---

Outside diff comments:
In `@pkg/controller/external_secrets/controller.go`:
- Around line 314-322: The switch in controller.go is comparing pointer literal
identities so cases like "&appsv1.Deployment{}" never match elements from
controllerManagedResources; change the logic to type-switch or compare concrete
types instead: iterate controllerManagedResources and use a type switch on the
element (or reflect.TypeOf(res)) to detect *appsv1.Deployment and *corev1.Secret
and then call mgrBuilder.Watches/mgrBuilder.WatchesMetadata with the appropriate
predicates (preserving handler.EnqueueRequestsFromMapFunc(mapFunc),
withIgnoreStatusUpdatePredicates,
builder.WithPredicates(predicate.LabelChangedPredicate{}), and
managedResourcePredicate).

---

Nitpick comments:
In `@pkg/controller/external_secrets/deployments_test.go`:
- Around line 2027-2033: The test currently branches setup on the literal test
title (tt.name == "removes user CA config when ConfigMap is missing"); add an
explicit per-case flag to the test case struct (e.g., a bool like
noConfigMapClients or needsEmptyClients), update the affected test cases to set
that flag, and replace the name-based branch with a check of that flag in the
switch that assigns cached and uncached; keep the existing behavior by
instantiating &fakes.FakeCtrlClient{} for cached and uncached when the flag is
set, otherwise call setupConfigMapClients(t, tt.cm) when tt.cm != nil.

In `@test/e2e/e2e_test.go`:
- Around line 401-403: The test currently replaces the whole
updatedCR.Spec.ControllerConfig with a new ControllerConfig which wipes other
fields; instead assign only ComponentConfigs to preserve unrelated fields:
ensure updatedCR.Spec.ControllerConfig is non-nil (create a zero value if
needed) and set updatedCR.Spec.ControllerConfig.ComponentConfigs =
applicableEnvConfigs; apply the same change to the other similar assignment
later in the file where ControllerConfig is being replaced.
🪄 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: 5749c0c6-c704-4267-92d5-fa8b2db8d24b

📥 Commits

Reviewing files that changed from the base of the PR and between 96b0684 and 6ad967a.

📒 Files selected for processing (36)
  • api/v1alpha1/external_secrets_config_types.go
  • api/v1alpha1/groupversion_info.go
  • api/v1alpha1/meta.go
  • bundle/manifests/openshift-external-secrets-operator.clusterserviceversion.yaml
  • bundle/manifests/operator.openshift.io_externalsecretsconfigs.yaml
  • bundle/manifests/operator.openshift.io_externalsecretsmanagers.yaml
  • config/crd/bases/operator.openshift.io_externalsecretsconfigs.yaml
  • config/crd/bases/operator.openshift.io_externalsecretsmanagers.yaml
  • docs/api_reference.md
  • pkg/controller/common/errors.go
  • pkg/controller/common/errors_test.go
  • pkg/controller/commontest/utils.go
  • pkg/controller/external_secrets/certificate.go
  • pkg/controller/external_secrets/certificate_test.go
  • pkg/controller/external_secrets/configmap.go
  • pkg/controller/external_secrets/constants.go
  • pkg/controller/external_secrets/controller.go
  • pkg/controller/external_secrets/controller_failure_test.go
  • pkg/controller/external_secrets/controller_test.go
  • pkg/controller/external_secrets/deployments.go
  • pkg/controller/external_secrets/deployments_test.go
  • pkg/controller/external_secrets/networkpolicy_test.go
  • pkg/controller/external_secrets/test_utils.go
  • pkg/controller/external_secrets/trusted_ca_bundle.go
  • pkg/controller/external_secrets/trusted_ca_bundle_test.go
  • pkg/controller/external_secrets/utils.go
  • pkg/controller/external_secrets/utils_test.go
  • pkg/version/version.go
  • test/e2e/bitwarden_es_test.go
  • test/e2e/e2e_test.go
  • test/e2e/helpers_test.go
  • test/e2e/trusted_ca_bundle_test.go
  • test/utils/bitwarden.go
  • test/utils/cleanup.go
  • test/utils/conditions.go
  • test/utils/external_secrets_config.go

Comment thread pkg/controller/external_secrets/certificate.go Outdated
Comment thread pkg/controller/external_secrets/controller.go
Comment thread pkg/controller/external_secrets/deployments_test.go
Comment thread pkg/controller/external_secrets/deployments.go
Comment thread pkg/controller/external_secrets/deployments.go
Comment thread pkg/controller/external_secrets/trusted_ca_bundle.go
Comment thread test/e2e/trusted_ca_bundle_test.go

@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

🤖 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 `@test/go.mod`:
- Around line 73-74: The go.mod pins "go.opentelemetry.io/otel v1.38.0" and
"go.opentelemetry.io/otel/trace v1.38.0", which are within the vulnerable range
for GHSA-mh2q-q3fh-2475; update both module versions to at least v1.41.0 (e.g.,
replace those entries with v1.41.0 or run go get
go.opentelemetry.io/otel@v1.41.0 and go get
go.opentelemetry.io/otel/trace@v1.41.0), then run go mod tidy to lock the
updates and verify builds/tests pass.
🪄 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: 21dd620e-35ed-4eba-924d-05d44774bc9a

📥 Commits

Reviewing files that changed from the base of the PR and between 6ad967a and 252cf3b.

⛔ Files ignored due to path filters (1)
  • test/go.sum is excluded by !**/*.sum
📒 Files selected for processing (37)
  • api/v1alpha1/external_secrets_config_types.go
  • api/v1alpha1/groupversion_info.go
  • api/v1alpha1/meta.go
  • bundle/manifests/openshift-external-secrets-operator.clusterserviceversion.yaml
  • bundle/manifests/operator.openshift.io_externalsecretsconfigs.yaml
  • bundle/manifests/operator.openshift.io_externalsecretsmanagers.yaml
  • config/crd/bases/operator.openshift.io_externalsecretsconfigs.yaml
  • config/crd/bases/operator.openshift.io_externalsecretsmanagers.yaml
  • docs/api_reference.md
  • pkg/controller/common/errors.go
  • pkg/controller/common/errors_test.go
  • pkg/controller/commontest/utils.go
  • pkg/controller/external_secrets/certificate.go
  • pkg/controller/external_secrets/certificate_test.go
  • pkg/controller/external_secrets/configmap.go
  • pkg/controller/external_secrets/constants.go
  • pkg/controller/external_secrets/controller.go
  • pkg/controller/external_secrets/controller_failure_test.go
  • pkg/controller/external_secrets/controller_test.go
  • pkg/controller/external_secrets/deployments.go
  • pkg/controller/external_secrets/deployments_test.go
  • pkg/controller/external_secrets/networkpolicy_test.go
  • pkg/controller/external_secrets/test_utils.go
  • pkg/controller/external_secrets/trusted_ca_bundle.go
  • pkg/controller/external_secrets/trusted_ca_bundle_test.go
  • pkg/controller/external_secrets/utils.go
  • pkg/controller/external_secrets/utils_test.go
  • pkg/version/version.go
  • test/e2e/bitwarden_es_test.go
  • test/e2e/e2e_test.go
  • test/e2e/helpers_test.go
  • test/e2e/trusted_ca_bundle_test.go
  • test/go.mod
  • test/utils/bitwarden.go
  • test/utils/cleanup.go
  • test/utils/conditions.go
  • test/utils/external_secrets_config.go
✅ Files skipped from review due to trivial changes (11)
  • bundle/manifests/operator.openshift.io_externalsecretsmanagers.yaml
  • docs/api_reference.md
  • pkg/version/version.go
  • api/v1alpha1/meta.go
  • api/v1alpha1/groupversion_info.go
  • config/crd/bases/operator.openshift.io_externalsecretsconfigs.yaml
  • test/utils/bitwarden.go
  • config/crd/bases/operator.openshift.io_externalsecretsmanagers.yaml
  • bundle/manifests/operator.openshift.io_externalsecretsconfigs.yaml
  • bundle/manifests/openshift-external-secrets-operator.clusterserviceversion.yaml
  • api/v1alpha1/external_secrets_config_types.go
🚧 Files skipped from review as they are similar to previous changes (25)
  • pkg/controller/external_secrets/networkpolicy_test.go
  • pkg/controller/external_secrets/controller_test.go
  • pkg/controller/commontest/utils.go
  • pkg/controller/common/errors.go
  • pkg/controller/external_secrets/certificate_test.go
  • pkg/controller/external_secrets/utils_test.go
  • test/e2e/helpers_test.go
  • test/utils/cleanup.go
  • pkg/controller/external_secrets/trusted_ca_bundle_test.go
  • pkg/controller/external_secrets/certificate.go
  • test/utils/conditions.go
  • pkg/controller/common/errors_test.go
  • pkg/controller/external_secrets/trusted_ca_bundle.go
  • pkg/controller/external_secrets/configmap.go
  • pkg/controller/external_secrets/test_utils.go
  • pkg/controller/external_secrets/utils.go
  • test/utils/external_secrets_config.go
  • test/e2e/trusted_ca_bundle_test.go
  • pkg/controller/external_secrets/controller_failure_test.go
  • test/e2e/bitwarden_es_test.go
  • pkg/controller/external_secrets/controller.go
  • pkg/controller/external_secrets/deployments_test.go
  • test/e2e/e2e_test.go
  • pkg/controller/external_secrets/deployments.go
  • pkg/controller/external_secrets/constants.go

Comment thread test/go.mod Outdated
Signed-off-by: Bharath B <bhb@redhat.com>
@bharath-b-rh

Copy link
Copy Markdown
Contributor Author

/test e2e-operator

@openshift-ci

openshift-ci Bot commented Jun 5, 2026

Copy link
Copy Markdown

@bharath-b-rh: all tests passed!

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.

@codecov-commenter

codecov-commenter commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 62.57426% with 189 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.27%. Comparing base (96b0684) to head (3ca3da6).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
pkg/controller/external_secrets/deployments.go 64.89% 57 Missing and 9 partials ⚠️
...g/controller/external_secrets/trusted_ca_bundle.go 63.04% 29 Missing and 5 partials ⚠️
pkg/controller/external_secrets/test_utils.go 0.00% 28 Missing ⚠️
pkg/controller/external_secrets/certificate.go 0.00% 18 Missing ⚠️
pkg/controller/external_secrets/controller.go 83.48% 16 Missing and 2 partials ⚠️
pkg/controller/external_secrets/configmap.go 10.00% 9 Missing ⚠️
pkg/controller/external_secrets/utils.go 76.92% 6 Missing and 3 partials ⚠️
pkg/controller/common/errors.go 66.66% 5 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #149      +/-   ##
==========================================
- Coverage   47.94%   46.27%   -1.68%     
==========================================
  Files          29       31       +2     
  Lines        4207     5005     +798     
==========================================
+ Hits         2017     2316     +299     
- Misses       1902     2391     +489     
- Partials      288      298      +10     
Flag Coverage Δ
e2e 46.27% <62.57%> (-1.68%) ⬇️

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

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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. 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.

3 participants