Skip to content

CNTRLPLANE-2589: Migrate e2e-* tests to Ginkgo v2#859

Open
ropatil010 wants to merge 4 commits into
openshift:masterfrom
ropatil010:migrate-e2e-encryption-final
Open

CNTRLPLANE-2589: Migrate e2e-* tests to Ginkgo v2#859
ropatil010 wants to merge 4 commits into
openshift:masterfrom
ropatil010:migrate-e2e-encryption-final

Conversation

@ropatil010
Copy link
Copy Markdown
Contributor

@ropatil010 ropatil010 commented Mar 27, 2026

Hi Team,

This PR restores the Ginkgo v2 migration from PR #839 with a critical fix for the stdout corruption issue that caused it to be reverted in PR #857.

Changes from PR #839:

  • Migrate e2e-encryption, e2e-encryption-kms, e2e-encryption-perf, e2e-encryption-rotation, and e2e-oidc test suites to Ginkgo v2
  • Add testing.TB compatibility layer for library-go integration
  • Create new test implementation files with Ginkgo v2 specs
  • Configure appropriate test suite parallelism and qualifiers
  • Remove obsolete main_test.go files

Critical fix (new):

  • Redirect klog output to stderr to prevent warnings from corrupting JSON output during test listing. Previously, klog warnings were written to stdout, causing 'invalid character W' JSON parsing errors that blocked nightly CI jobs.

The fix adds klog.SetOutput(os.Stderr) in main() to ensure:

  • stdout contains only clean JSON (parseable by openshift-tests)
  • klog warnings still logged to stderr (visible for debugging)

Fixes the issue from PR #857.

Summary by CodeRabbit

  • Tests

    • Added comprehensive E2E suites for KMS, OIDC (Keycloak), encryption rotation, and encryption performance; many suites now run serially and include feature-gate checks.
    • Refactored tests to delegate to shared scenario wrappers and helpers, added migration-watching and DB-population helpers, improved test logging, and removed custom test-order randomization.
    • Added Keycloak cleanup helpers and OIDC validation/rollout checks.
  • Chores

    • Bumped klog dependency to v2.140.0.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Mar 27, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Mar 27, 2026

@ropatil010: This pull request references CNTRLPLANE-2589 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 epic to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Hi Team,

This PR restores the Ginkgo v2 migration from PR #839 with a critical fix for the stdout corruption issue that caused it to be reverted in PR #857.

Changes from PR #839:

  • Migrate e2e-encryption, e2e-encryption-kms, e2e-encryption-perf, e2e-encryption-rotation, and e2e-oidc test suites to Ginkgo v2
  • Add testing.TB compatibility layer for library-go integration
  • Create new test implementation files with Ginkgo v2 specs
  • Configure appropriate test suite parallelism and qualifiers
  • Remove obsolete main_test.go files

Critical fix (new):

  • Redirect klog output to stderr to prevent warnings from corrupting JSON output during test listing. Previously, klog warnings were written to stdout, causing 'invalid character W' JSON parsing errors that blocked nightly CI jobs.

The fix adds klog.SetOutput(os.Stderr) in main() to ensure:

  • stdout contains only clean JSON (parseable by openshift-tests)
  • klog warnings still logged to stderr (visible for debugging)

Fixes the issue from PR #857.

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.

@openshift-ci openshift-ci Bot requested review from ibihim and liouk March 27, 2026 18:13
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds new Ginkgo e2e suites and extracted reusable encryption/rotation/perf/KMS and OIDC test libraries; replaces many in-file tests with wrapper delegates; adds Keycloak admin helpers; introduces DB-population and migration-watcher helpers; lazy-inits KAS HTTPS port; removes custom TestMain randomization; bumps klog.

Changes

E2E Tests & Library

Layer / File(s) Summary
Test registrations & blank imports
cmd/cluster-authentication-operator-tests-ext/main.go
Blank-imports new e2e packages and registers four serial encryption suites and OIDC with Parallelism: 1 and qualifier filters.
Ginkgo suite entrypoints
test/e2e-encryption/*.go, test/e2e-encryption-perf/*.go, test/e2e-encryption-rotation/*.go, test/e2e-encryption-kms/*.go, test/e2e-oidc/*.go
Adds/updates Ginkgo Describe/It blocks and top-level delegating test entrypoints for encryption (identity/unset/AESCBC/AESGCM/KMS), rotation, perf, KMS-specific, and External OIDC (Keycloak) scenarios.
Core scenario implementations
test/library/encryption/scenarios.go, test/e2e-encryption-rotation/encryption_rotation.go, test/e2e-encryption/*.go, test/e2e-encryption-kms/encryption_kms.go, test/e2e-encryption-perf/encryption_perf.go, test/e2e-oidc/external_oidc.go
Implements centralized encryption test logic (SetAndWaitForEncryptionType, turn-on/off, rotation, providers migration, perf flow, DB population, migration watcher) and the full External OIDC end-to-end flow including JWKS/JWT verification and operator interactions.
Library wrappers & API changes
test/library/encryption_wrappers.go, test/library/featuregates.go, test/library/waits.go
Adds exported wrapper functions delegating to local implementations, introduces CheckFeatureGatesOrSkip, and changes several wait helper signatures from *testing.T to testing.TB.
Test file delegations / cleanup
test/e2e-encryption/encryption_test.go, test/e2e-encryption-perf/encryption_perf_test.go, test/e2e-encryption-rotation/e2e-encryption-rotation_test.go, test/e2e-encryption-kms/encryption_kms_test.go, test/e2e-oidc/external_oidc_test.go
Replaces large inline test implementations with lightweight wrapper tests that call the extracted helper functions.
Helpers & Keycloak admin client
test/library/keycloakidp.go, test/library/client.go, test/library/encryption/helpers.go, test/library/encryption/perf_helpers.go
Adds Keycloak List/Delete helpers (paginated), switches client logging to t.Logf, and implements perf helpers for DB population, runner, and migration-condition watcher.
Removed test-order randomization
test/e2e-encryption/main_test.go, test/e2e-encryption-kms/main_test.go
Removes custom TestMain and unsafe/reflection-based test shuffling; tests use the default Go test harness.

Infrastructure & Tooling

Layer / File(s) Summary
KAS port initialization (lazy/memoized)
pkg/controllers/readiness/wellknown_ready_controller.go
Replaces eager package-init of KAS HTTPS port with getKASServicePort() using sync.Once; parses KUBERNETES_SERVICE_PORT_HTTPS, warns and defaults to 443 on parse failure; call sites updated to use accessor.
Dependency bump
go.mod
Bumps k8s.io/klog/v2 from v2.130.1 to v2.140.0.

Sequence Diagram(s)

sequenceDiagram
    participant Test as E2E Test
    participant Keycloak as Keycloak IdP
    participant CAO as Auth Operator
    participant KAS as Kube API Server
    participant K8s as Kubernetes API
    Test->>Keycloak: provision realm, user, claims
    Test->>CAO: apply AuthenticationSpec (OIDC config, CA, claim mappings)
    CAO->>K8s: create/update auth-config ConfigMaps and operator resources
    CAO->>KAS: trigger KAS rollout / ensure generated auth-config.json present
    KAS->>Keycloak: fetch JWKS (OIDC discovery) for token validation
    Test->>K8s: call SelfSubjectReview with ID token
    K8s-->>Test: return authentication result (Allowed / Unauthorized)
    Note over CAO,KAS: operator reconciles and overwrites manual auth-config changes when reconciling
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

🚥 Pre-merge checks | ✅ 8 | ❌ 4

❌ Failed checks (4 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning Two critical review issues remain unaddressed: errorStore ignored in encryption_perf.go, no retry.RetryOnConflict in encryption_rotation.go for concurrent updates. Assert errorStore empty in AssertDBPopulatedFunc. Wrap UnsupportedConfigFunc in retry.RetryOnConflict for concurrent write safety.
Microshift Test Compatibility ⚠️ Warning Tests use config.openshift.io and operator.openshift.io APIs unavailable on MicroShift. No [Skipped:MicroShift], [apigroup:...], or runtime protection checks present. Add [apigroup:config.openshift.io] or [apigroup:operator.openshift.io] tags to test names, or add [Skipped:MicroShift] labels. Alternatively use exutil.IsMicroShiftCluster() with g.Skip().
Ipv6 And Disconnected Network Test Compatibility ⚠️ Warning The test/e2e-oidc/external_oidc.go test requires external image pull from quay.io (keycloak:25.0) and lacks [Skipped:Disconnected] marking, making it incompatible with disconnected environments. Add [Skipped:Disconnected] to test name: g.It("[OIDC][Serial][Disruptive][Skipped:Disconnected] TestExternalOIDCWithKeycloak. Other encryption tests passed the check—no external pulls or IPv4 assumptions.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main change: migrating e2e tests to Ginkgo v2, with the Jira ticket reference providing project context.
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.
Stable And Deterministic Test Names ✅ Passed All Ginkgo test titles in the PR are stable and deterministic. No dynamic information found in any test name declarations.
Single Node Openshift (Sno) Test Compatibility ✅ Passed All new e2e tests are SNO-compatible. No multi-node topology, pod distribution, or HA assumptions found. Tests operate on cluster-wide APIs only.
Topology-Aware Scheduling Compatibility ✅ Passed PR adds test code and refactors port-loading logic in a controller. No deployment manifests or scheduling constraints are introduced. Check not applicable.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes detected. Main binary uses fmt.Errorf and klog.Fatal only. Test code uses fmt.Sprintf/Errorf. Ginkgo v2 properly isolates test output. No BeforeSuite logging violations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@ropatil010 ropatil010 force-pushed the migrate-e2e-encryption-final branch from debcb9a to 9541074 Compare March 30, 2026 02:49
@ropatil010
Copy link
Copy Markdown
Contributor Author

Before fix in CI logs we were hitting the same error which was mentioned in the Reverting PR: #857

https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-agnostic-ipv6/2037594585412145152

After fix the CI logs got pass

https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-agnostic-ipv6/2038524461480677376

/assign @liouk @stbenjam
Discussion: https://redhat-internal.slack.com/archives/C01CQA76KMX/p1774601343401799

@ropatil010 ropatil010 changed the title CNTRLPLANE-2589: [WIP] Migrate e2e-encryption tests to Ginkgo v2 with stdout fix CNTRLPLANE-2589: Migrate e2e-encryption tests to Ginkgo v2 with stdout fix Mar 30, 2026
Comment thread pkg/controllers/readiness/wellknown_ready_controller.go
Comment thread test/library/client.go Outdated
Comment thread test/library/encryption/helpers.go Outdated
Comment thread pkg/controllers/readiness/wellknown_ready_controller.go Outdated
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 2, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ropatil010
Once this PR has been reviewed and has the lgtm label, please ask for approval from liouk. 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

@liouk
Copy link
Copy Markdown
Member

liouk commented Apr 2, 2026

@ropatil010 please correct me if I'm wrong, but this issue seems that it's caused by OTE itself, is there a plan on fixing that on the OTE side?

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
test/e2e-oidc/external_oidc.go (1)

441-470: Consider extending algorithm support for future-proofing.

The extractRSAPubKeyFunc only handles RS256. While this matches current Keycloak defaults, if the IDP configuration changes to use RS384/RS512, tests would fail with an unhelpful error. This is acceptable for now but worth noting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-oidc/external_oidc.go` around lines 441 - 470, extractRSAPubKeyFunc
currently only accepts "RS256" and returns an error for other RSA algorithms;
update it to accept other RSA signing algorithms (e.g., "RS384", "RS512") or any
algorithm that starts with "RS" so the JWKS parsing is future-proof: modify the
switch on key.Alg in extractRSAPubKeyFunc (and the related issuerJWKS/Key usage)
to handle "RS384" and "RS512" (or use a strings.HasPrefix(key.Alg, "RS") check)
and keep constructing the rsa.PublicKey the same way, while keeping the
unexpected-algorithm error for non-RS algorithms. Ensure the error messages
still include key.KID and key.Alg for clarity.
test/e2e-encryption-perf/encryption_perf.go (1)

55-66: Simplify error handling with direct t.Fatal calls.

The pattern of creating an error and immediately passing it to require.NoError is confusing. Since the error is always non-nil when created, require.NoError will always fail, making this equivalent to t.Fatal but harder to read.

♻️ Proposed simplification
 		AssertDBPopulatedFunc: func(t testing.TB, errorStore map[string]int, statStore map[string]int) {
 			tokenCount, ok := statStore[tokenStatsKey]
 			if !ok {
-				err := errors.New("missing oauth access tokens count stats, can't continue the test")
-				require.NoError(t, err)
+				t.Fatal("missing oauth access tokens count stats, can't continue the test")
 			}
 			if tokenCount < 14000 {
-				err := fmt.Errorf("expected to create at least 14000 tokens but %d were created", tokenCount)
-				require.NoError(t, err)
+				t.Fatalf("expected to create at least 14000 tokens but %d were created", tokenCount)
 			}
 			t.Logf("Created %d access tokens", tokenCount)
 		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption-perf/encryption_perf.go` around lines 55 - 66, In
AssertDBPopulatedFunc simplify error handling by replacing the pattern that
constructs an error and calls require.NoError with direct test failures: when
statStore[tokenStatsKey] is missing call t.Fatalf (or require.FailNow) with a
clear message about the missing oauth access tokens count, and when tokenCount <
14000 call t.Fatalf (or require.FailNow) with a message showing the expected vs
actual tokenCount; update references around AssertDBPopulatedFunc and
tokenStatsKey accordingly.
test/e2e-encryption-rotation/encryption_rotation.go (1)

47-75: Consider adding retry logic for the operator update.

The UnsupportedConfigFunc performs a read-modify-write operation without handling potential conflict errors. If the operator object is modified between the Get (line 49) and Update (line 73), the update will fail with a conflict. For a 3-hour test, this could cause intermittent failures.

If conflicts are expected to be rare in this test context, the current implementation is acceptable, but retry-on-conflict would improve reliability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption-rotation/encryption_rotation.go` around lines 47 - 75,
Wrap the read-modify-write in UnsupportedConfigFunc with retry-on-conflict logic
(e.g., use k8s.io/client-go/util/retry.RetryOnConflict) so that if
cs.OperatorClient.Update returns a conflict you re-get the Operator
(cs.OperatorClient.Get), reapply the unsupportedConfig merge steps and retry the
Update; ensure the loop returns the final error if retries are exhausted and
keep references to UnsupportedConfigFunc, cs.OperatorClient.Get, and
cs.OperatorClient.Update to locate the change.
test/e2e-encryption/encryption.go (1)

54-74: Consider reusing the provided ClientSet parameter.

The CreateResourceFunc callback receives a library.ClientSet parameter but ignores it, creating a new client via operatorencryption.GetClients(t). If this is intentional (e.g., needing operator-specific client configuration), adding a brief comment would clarify the design choice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption/encryption.go` around lines 54 - 74, The
CreateResourceFunc inside testEncryptionTurnOnAndOff ignores the provided
library.ClientSet parameter and calls operatorencryption.GetClients(t); either
update CreateResourceFunc to use the passed-in client (the second parameter)
when calling operatorencryption.CreateAndStoreTokenOfLife (or adapt/convert the
library.ClientSet to the expected client type), or if using GetClients(t) is
intentional, add a brief comment above CreateResourceFunc explaining why
operatorencryption.GetClients(t) is required instead of the supplied client;
reference CreateResourceFunc, operatorencryption.CreateAndStoreTokenOfLife, and
operatorencryption.GetClients for locating the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@go.mod`:
- Around line 136-137: The go.mod replace pointing to the forked module
(github.com/ropatil010/openshift-tests-extension
v0.0.0-20260406095036-3a490698dab7) introduces supply-chain and reproducibility
risk; update the repository by adding a clear TODO comment in go.mod and create
a tracking issue linking upstream PR `#60` ("feat: configure klog to write to
stderr") so we revert this replace as soon as that PR is merged, then remove the
replace and restore github.com/openshift-eng/openshift-tests-extension; also add
a CI/release gate (or note in the release checklist) to block merging release
candidates until the follow-up removal is completed.

In `@test/e2e-encryption-rotation/encryption_rotation.go`:
- Around line 27-28: Fix the typo in the comment above testEncryptionRotation:
change "encyrption.Reason" to "encryption.Reason" in the comment that describes
forcing a key rotation so the term is spelled correctly and matches the
configuration field name.

In `@test/library/encryption/perf_helpers.go`:
- Around line 35-46: The predicate passed to wait.PollUntilContextTimeout
currently sends any EncryptionMigrationControllerProgressing=True timestamp even
if it predates the test and it never checks the cond.Reason; update the
predicate used by wait.PollUntilContextTimeout in perf_helpers.go (the anonymous
func that calls getOperatorConditionsFn and writes to migrationStartedCh) to
also require cond.Reason == "Migrating" and that cond.LastTransitionTime is
strictly after a test start time captured before the poll (e.g., record start :=
time.Now() or start := time.Now().UTC() before calling
wait.PollUntilContextTimeout, then only send cond.LastTransitionTime.Time if
cond.Type == "EncryptionMigrationControllerProgressing" && cond.Status ==
operatorv1.ConditionTrue && cond.Reason == "Migrating" &&
cond.LastTransitionTime.Time.After(start)). Ensure the log message remains
meaningful when the newer transition is observed.

In `@test/library/encryption/scenarios.go`:
- Around line 189-210: The test uses a non-blocking select to read
migrationStartedCh which can fall through before the watcher goroutine sends;
change this to wait for the signal with a bounded timeout instead of using the
default case: replace the select block reading migrationStartedCh with a
blocking receive combined with a timeout (e.g., select { case migrationStarted
:= <-migrationStartedCh: ... case <-time.After(timeout): tb.Error(...) }) or use
a context with deadline that you cancel when runTestEncryptionPerf returns;
ensure you reference the watcher by keeping migrationStartedCh passed to
watchForMigrationControllerProgressingConditionAsync and use that same channel
for the bounded wait so the watcher is not left running indefinitely.
- Around line 72-83: The switch in TestEncryptionType currently routes the
empty-string provider ("") to TestEncryptionTypeIdentity which causes
APIServer.Spec.Encryption.Type to be set to "identity"; change the dispatch so
that case configv1.EncryptionTypeIdentity handles the explicit identity value
and the empty-string case ("") dispatches to TestEncryptionTypeUnset instead.
Update the switch in the TestEncryptionType function (the cases for
configv1.EncryptionTypeIdentity and "") so that "" calls
TestEncryptionTypeUnset(tb, scenario) while leaving the explicit Identity case
calling TestEncryptionTypeIdentity(tb, scenario).
- Around line 340-349: The APIServer Get+Update can fail with resourceVersion
conflicts; wrap the read-modify-update of apiServer (performed via
libClientSet.ApiServerConfig.Get and Update) inside a retry.RetryOnConflict
loop: import "k8s.io/client-go/util/retry", use retry.RetryOnConflict to
repeatedly Get the APIServer, set apiServer.Spec.Encryption.Type =
encryptionType when changed, and call Update until it succeeds or the retry
gives up; ensure errors from Update are returned/checked with
require.NoError(tb, err) as before.

---

Nitpick comments:
In `@test/e2e-encryption-perf/encryption_perf.go`:
- Around line 55-66: In AssertDBPopulatedFunc simplify error handling by
replacing the pattern that constructs an error and calls require.NoError with
direct test failures: when statStore[tokenStatsKey] is missing call t.Fatalf (or
require.FailNow) with a clear message about the missing oauth access tokens
count, and when tokenCount < 14000 call t.Fatalf (or require.FailNow) with a
message showing the expected vs actual tokenCount; update references around
AssertDBPopulatedFunc and tokenStatsKey accordingly.

In `@test/e2e-encryption-rotation/encryption_rotation.go`:
- Around line 47-75: Wrap the read-modify-write in UnsupportedConfigFunc with
retry-on-conflict logic (e.g., use k8s.io/client-go/util/retry.RetryOnConflict)
so that if cs.OperatorClient.Update returns a conflict you re-get the Operator
(cs.OperatorClient.Get), reapply the unsupportedConfig merge steps and retry the
Update; ensure the loop returns the final error if retries are exhausted and
keep references to UnsupportedConfigFunc, cs.OperatorClient.Get, and
cs.OperatorClient.Update to locate the change.

In `@test/e2e-encryption/encryption.go`:
- Around line 54-74: The CreateResourceFunc inside testEncryptionTurnOnAndOff
ignores the provided library.ClientSet parameter and calls
operatorencryption.GetClients(t); either update CreateResourceFunc to use the
passed-in client (the second parameter) when calling
operatorencryption.CreateAndStoreTokenOfLife (or adapt/convert the
library.ClientSet to the expected client type), or if using GetClients(t) is
intentional, add a brief comment above CreateResourceFunc explaining why
operatorencryption.GetClients(t) is required instead of the supplied client;
reference CreateResourceFunc, operatorencryption.CreateAndStoreTokenOfLife, and
operatorencryption.GetClients for locating the change.

In `@test/e2e-oidc/external_oidc.go`:
- Around line 441-470: extractRSAPubKeyFunc currently only accepts "RS256" and
returns an error for other RSA algorithms; update it to accept other RSA signing
algorithms (e.g., "RS384", "RS512") or any algorithm that starts with "RS" so
the JWKS parsing is future-proof: modify the switch on key.Alg in
extractRSAPubKeyFunc (and the related issuerJWKS/Key usage) to handle "RS384"
and "RS512" (or use a strings.HasPrefix(key.Alg, "RS") check) and keep
constructing the rsa.PublicKey the same way, while keeping the
unexpected-algorithm error for non-RS algorithms. Ensure the error messages
still include key.KID and key.Alg for clarity.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0a512169-a204-4df2-92e6-760ec43345c5

📥 Commits

Reviewing files that changed from the base of the PR and between 9d60ca2 and 626f7d7.

⛔ Files ignored due to path filters (17)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift-eng/openshift-tests-extension/pkg/cmd/cmd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift-eng/openshift-tests-extension/pkg/cmd/cmdrun/runsuite.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift-eng/openshift-tests-extension/pkg/extension/extensiontests/result.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift-eng/openshift-tests-extension/pkg/extension/extensiontests/result_writer.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift-eng/openshift-tests-extension/pkg/extension/extensiontests/viewer.html is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo/logging.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/README.md is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_no_slog.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_slog.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/klog.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/klogr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/klogr_slog.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/textlogger/options.go is excluded by !vendor/**, !**/vendor/**
  • vendor/k8s.io/klog/v2/textlogger/textlogger.go is excluded by !vendor/**, !**/vendor/**
  • vendor/modules.txt is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (22)
  • cmd/cluster-authentication-operator-tests-ext/main.go
  • go.mod
  • pkg/controllers/readiness/wellknown_ready_controller.go
  • test/e2e-encryption-kms/encryption_kms.go
  • test/e2e-encryption-kms/encryption_kms_test.go
  • test/e2e-encryption-kms/main_test.go
  • test/e2e-encryption-perf/encryption_perf.go
  • test/e2e-encryption-perf/encryption_perf_test.go
  • test/e2e-encryption-rotation/e2e-encryption-rotation_test.go
  • test/e2e-encryption-rotation/encryption_rotation.go
  • test/e2e-encryption/encryption.go
  • test/e2e-encryption/encryption_test.go
  • test/e2e-encryption/main_test.go
  • test/e2e-oidc/external_oidc.go
  • test/e2e-oidc/external_oidc_test.go
  • test/library/client.go
  • test/library/encryption/helpers.go
  • test/library/encryption/perf_helpers.go
  • test/library/encryption/scenarios.go
  • test/library/encryption_wrappers.go
  • test/library/featuregates.go
  • test/library/waits.go
💤 Files with no reviewable changes (2)
  • test/e2e-encryption/main_test.go
  • test/e2e-encryption-kms/main_test.go

Comment thread go.mod Outdated
Comment thread test/e2e-encryption-rotation/encryption_rotation.go Outdated
Comment thread test/library/encryption/perf_helpers.go Outdated
Comment thread test/library/encryption/scenarios.go
Comment thread test/library/encryption/scenarios.go
Comment thread test/library/encryption/scenarios.go Outdated
@ropatil010 ropatil010 changed the title CNTRLPLANE-2589: Migrate e2e-encryption tests to Ginkgo v2 with stdout fix CNTRLPLANE-2589: [WIP] Migrate e2e-encryption tests to Ginkgo v2 with stdout fix Apr 6, 2026
@ropatil010 ropatil010 force-pushed the migrate-e2e-encryption-final branch from 4342519 to 8f115d7 Compare April 7, 2026 14:45
ropatil010 added a commit to ropatil010/cluster-authentication-operator that referenced this pull request Apr 7, 2026
This commit migrates five test suites (e2e-encryption, e2e-encryption-kms,
e2e-encryption-perf, e2e-encryption-rotation, e2e-oidc) from standalone
test binaries to the OpenShift Tests Extension (OTE) framework using Ginkgo v2.

Key changes:
- Migrate tests to Ginkgo v2 with OTE integration
- Extract test logic into dedicated helper files for better organization
- Remove obsolete main_test.go files in favor of Ginkgo suite setup
- Configure appropriate test suite parallelism and qualifiers
- Add klog stderr redirection to fix JSON output corruption

Critical fix for klog output corruption:
- Add klog.SetOutput(os.Stderr) in test binary's main() to prevent klog
  warnings from corrupting JSON output during 'openshift-tests list' commands
- This fixes "invalid character 'W'" parsing errors in CI that caused PR openshift#839
  to be reverted in PR openshift#857
- Ensures stdout contains only clean JSON for CI consumption while klog
  warnings go to stderr

Test organization:
- operator/parallel: Non-serial operator, templates, and tokens tests (parallelism: 4)
- operator/serial: Serial operator, OIDC, templates, and tokens tests
- operator/disruptive: Tests marked as [Disruptive]
- operator-encryption/serial: Basic encryption tests
- operator-encryption-rotation/serial: Encryption key rotation tests
- operator-encryption-perf/serial: Encryption performance tests
- operator-encryption-kms/serial: KMS encryption tests

Dependencies:
- Use standard OTE version v0.0.0-20251205182537-ff5553e56f33
- Updated klog dependency to v2.140.0
- No fork dependencies

See: openshift#857 (revert)
     openshift#859 (this PR)

Co-Authored-By: Rohit Patil <ropatil@redhat.com>
@ropatil010 ropatil010 force-pushed the migrate-e2e-encryption-final branch from 8f115d7 to 6c90e52 Compare April 7, 2026 15:19
ropatil010 added a commit to ropatil010/cluster-authentication-operator that referenced this pull request Apr 8, 2026
Restore the init package approach to fix 'invalid character W looking for
beginning of value' errors in CI when listing tests.

The previous fix using klog.SetOutput(os.Stderr) in main() was too late -
klog warnings were already generated during Go's init phase, corrupting the
JSON output before main() could run.

This commit implements a two-phase approach:

1. Init phase (pkg/test/init): Suppress all klog output using io.Discard
   - Runs during Go initialization, before any dependency can trigger warnings
   - Prevents warnings from appearing in stdout during 'openshift-tests list'

2. Main phase: Reconfigure klog to stderr for normal test execution
   - Enables proper logging after initialization completes
   - Keeps stdout clean for JSON output

This is the same approach that made commit 9541074 pass in CI, but was
inadvertently removed in commit 6c90e52, causing test failures.

Fixes the root cause of CI failures in PR openshift#859
See: openshift#857

Co-Authored-By: Rohit Patil <ropatil@redhat.com>
Comment thread cmd/cluster-authentication-operator-tests-ext/main.go Outdated
@ropatil010
Copy link
Copy Markdown
Contributor Author

Waiting for PR: openshift/origin#31009 to gets merged which fixes the issue "error: encountered errors while listing tests: invalid character 'W' looking for beginning of value".

The above mentioned issue has been fixed in this PR using init things but looks like it is not acceptable.

@ropatil010 ropatil010 force-pushed the migrate-e2e-encryption-final branch from 753ca4a to aa529ed Compare April 28, 2026 05:41
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Apr 28, 2026

@ropatil010: This pull request references CNTRLPLANE-2589 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 epic to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Hi Team,

This PR restores the Ginkgo v2 migration from PR #839 with a critical fix for the stdout corruption issue that caused it to be reverted in PR #857.

Changes from PR #839:

  • Migrate e2e-encryption, e2e-encryption-kms, e2e-encryption-perf, e2e-encryption-rotation, and e2e-oidc test suites to Ginkgo v2
  • Add testing.TB compatibility layer for library-go integration
  • Create new test implementation files with Ginkgo v2 specs
  • Configure appropriate test suite parallelism and qualifiers
  • Remove obsolete main_test.go files

Critical fix (new):

  • Redirect klog output to stderr to prevent warnings from corrupting JSON output during test listing. Previously, klog warnings were written to stdout, causing 'invalid character W' JSON parsing errors that blocked nightly CI jobs.

The fix adds klog.SetOutput(os.Stderr) in main() to ensure:

  • stdout contains only clean JSON (parseable by openshift-tests)
  • klog warnings still logged to stderr (visible for debugging)

Fixes the issue from PR #857.

Summary by CodeRabbit

  • Tests

  • Added comprehensive E2E test suites for KMS encryption scenarios, external OIDC (Keycloak) authentication, encryption rotation, and encryption performance testing.

  • Refactored encryption tests to use shared helper functions for improved maintainability.

  • Enhanced test infrastructure with feature gate validation and migration monitoring utilities.

  • Removed custom test execution order randomization.

  • Chores

  • Updated logging-related dependency k8s.io/klog/v2 to v2.140.0.

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (4)
test/library/encryption/scenarios.go (3)

340-349: ⚠️ Potential issue | 🟠 Major

Retry the APIServer update on conflict.

This is still a single read-modify-write against apiserver/cluster. If anything updates the object between Get and Update, the test fails on a transient resourceVersion conflict even though retrying would succeed. Wrap the mutation in retry.RetryOnConflict here.

Suggested fix
+	"k8s.io/client-go/util/retry"
-	apiServer, err := libClientSet.ApiServerConfig.Get(context.TODO(), "cluster", metav1.GetOptions{})
-	require.NoError(tb, err)
-
-	// Update encryption type if needed
-	needsUpdate := apiServer.Spec.Encryption.Type != encryptionType
-	if needsUpdate {
-		tb.Logf("Updating encryption type in the config file for APIServer to %q", encryptionType)
-		apiServer.Spec.Encryption.Type = encryptionType
-		_, err = libClientSet.ApiServerConfig.Update(context.TODO(), apiServer, metav1.UpdateOptions{})
-		require.NoError(tb, err)
+	apiServer, err := libClientSet.ApiServerConfig.Get(context.TODO(), "cluster", metav1.GetOptions{})
+	require.NoError(tb, err)
+
+	needsUpdate := apiServer.Spec.Encryption.Type != encryptionType
+	if needsUpdate {
+		tb.Logf("Updating encryption type in the config file for APIServer to %q", encryptionType)
+		err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
+			apiServer, err = libClientSet.ApiServerConfig.Get(context.TODO(), "cluster", metav1.GetOptions{})
+			if err != nil {
+				return err
+			}
+			apiServer.Spec.Encryption.Type = encryptionType
+			_, err = libClientSet.ApiServerConfig.Update(context.TODO(), apiServer, metav1.UpdateOptions{})
+			return err
+		})
+		require.NoError(tb, err)
 	} else {
 		tb.Logf("APIServer is already configured to use %q mode", encryptionType)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/library/encryption/scenarios.go` around lines 340 - 349, The update to
the APIServer object does a single read-modify-write and can fail on
resourceVersion conflicts; wrap the mutation+Update call in a
retry.RetryOnConflict loop so it re-reads and retries on conflict. Locate the
block that calls libClientSet.ApiServerConfig.Get and then sets
apiServer.Spec.Encryption.Type and calling libClientSet.ApiServerConfig.Update,
and replace that update path with a retry.RetryOnConflict that fetches the
latest ApiServer, applies the same encryptionType mutation to
apiServer.Spec.Encryption.Type, and retries the Update until it succeeds or a
non-conflict error occurs.

204-210: ⚠️ Potential issue | 🟠 Major

Don't use a non-blocking receive for migrationStartedCh.

If the watcher goroutine sends a moment later, this default path reports a false failure and never computes the migration duration. Wait on the same channel with a bounded timeout or cancelable context instead of falling through immediately.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/library/encryption/scenarios.go` around lines 204 - 210, The
non-blocking select on migrationStartedCh can cause false failures; replace the
select/default with a blocking receive that waits with a bounded timeout or a
cancelable context so the test actually observes the watcher send. Specifically,
wait for migrationStartedCh (instead of the default path) and compute
migrationTime = endTimeStamp.Sub(migrationStarted) before calling tb.Logf and
scenario.AssertMigrationTime; if the timeout/context expires, call tb.Error with
a clear timeout message. Use the existing symbols migrationStartedCh,
endTimeStamp, tb.Logf, and scenario.AssertMigrationTime to locate and update the
code.

73-81: ⚠️ Potential issue | 🟠 Major

Dispatch "" to TestEncryptionTypeUnset.

The empty-string provider still falls through to TestEncryptionTypeIdentity, which writes "identity" into APIServer.Spec.Encryption.Type instead of exercising the unset/defaulting path that this helper already models separately.

Suggested fix
 	switch provider {
 	case configv1.EncryptionTypeAESCBC:
 		TestEncryptionTypeAESCBC(tb, scenario)
 	case configv1.EncryptionTypeAESGCM:
 		TestEncryptionTypeAESGCM(tb, scenario)
 	case configv1.EncryptionTypeKMS:
 		TestEncryptionTypeKMS(tb, scenario)
-	case configv1.EncryptionTypeIdentity, "":
+	case configv1.EncryptionTypeIdentity:
 		TestEncryptionTypeIdentity(tb, scenario)
+	case "":
+		TestEncryptionTypeUnset(tb, scenario)
 	default:
 		tb.Fatalf("Unknown encryption type: %s", provider)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/library/encryption/scenarios.go` around lines 73 - 81, The switch in the
dispatcher incorrectly routes the empty-string provider to
TestEncryptionTypeIdentity; update the case handling so that
configv1.EncryptionTypeIdentity maps only to TestEncryptionTypeIdentity and the
empty string ("") maps to TestEncryptionTypeUnset. Locate the switch in
TestEncryption scenarios (the switch on provider in scenarios.go) and replace
the combined case `case configv1.EncryptionTypeIdentity, "":
TestEncryptionTypeIdentity(tb, scenario)` with two separate cases: one calling
TestEncryptionTypeIdentity(tb, scenario) for configv1.EncryptionTypeIdentity and
one calling TestEncryptionTypeUnset(tb, scenario) for the "" provider; leave the
other cases (TestEncryptionTypeAESCBC, TestEncryptionTypeAESGCM,
TestEncryptionTypeKMS) unchanged.
test/library/encryption/perf_helpers.go (1)

35-46: ⚠️ Potential issue | 🟠 Major

Only capture a fresh "Migrating" transition.

This still records any EncryptionMigrationControllerProgressing=True condition, even if it predates the current test or has a different reason. That can inflate the reported migration duration or use a stale start time. Capture a start := time.Now() before polling and only send LastTransitionTime when the condition is True, Reason == "Migrating", and the transition is newer than start.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/library/encryption/perf_helpers.go` around lines 35 - 46, The poll
currently sends any EncryptionMigrationControllerProgressing condition with
Status True, possibly using a stale LastTransitionTime; fix by recording a start
:= time.Now() immediately before calling wait.PollUntilContextTimeout and inside
the poll only send cond.LastTransitionTime to migrationStartedCh when cond.Type
== "EncryptionMigrationControllerProgressing", cond.Status ==
operatorv1.ConditionTrue, cond.Reason == "Migrating" and
cond.LastTransitionTime.Time.After(start); use getOperatorConditionsFn to fetch
conditions and ensure you return true,nil only when the transition is newer than
start.
🧹 Nitpick comments (3)
pkg/controllers/readiness/wellknown_ready_controller.go (1)

355-358: Optional: cache KAS service port once per function for readability.

Line 357 is correct, but pulling getKASServicePort() out of the loop makes intent clearer and avoids repeated calls in the condition.

♻️ Proposed refactor
 func getKASTargetPortFromService(service *corev1.Service) (int, bool) {
+	kasPort := getKASServicePort()
 	for _, port := range service.Spec.Ports {
-		if targetPort := port.TargetPort.IntValue(); targetPort != 0 && port.Protocol == corev1.ProtocolTCP && int(port.Port) == getKASServicePort() {
+		if targetPort := port.TargetPort.IntValue(); targetPort != 0 && port.Protocol == corev1.ProtocolTCP && int(port.Port) == kasPort {
 			return targetPort, true
 		}
 	}
 	return 0, false
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/controllers/readiness/wellknown_ready_controller.go` around lines 355 -
358, The loop in getKASTargetPortFromService repeatedly calls
getKASServicePort() inside the condition which obscures intent; cache the result
once before iterating by assigning kasPort := getKASServicePort(), then use
kasPort in the loop condition (referencing getKASTargetPortFromService and
getKASServicePort) so the code is clearer and avoids repeated calls.
test/e2e-encryption-perf/encryption_perf.go (2)

55-65: Consider using t.Fatalf directly instead of require.NoError with fabricated errors.

The current pattern creates an error just to pass it to require.NoError, which is indirect. Using t.Fatalf would be more idiomatic:

♻️ Suggested simplification
 AssertDBPopulatedFunc: func(t testing.TB, errorStore map[string]int, statStore map[string]int) {
 	tokenCount, ok := statStore[tokenStatsKey]
 	if !ok {
-		err := errors.New("missing oauth access tokens count stats, can't continue the test")
-		require.NoError(t, err)
+		t.Fatalf("missing oauth access tokens count stats, can't continue the test")
 	}
 	if tokenCount < 14000 {
-		err := fmt.Errorf("expected to create at least 14000 tokens but %d were created", tokenCount)
-		require.NoError(t, err)
+		t.Fatalf("expected to create at least 14000 tokens but %d were created", tokenCount)
 	}
 	t.Logf("Created %d access tokens", tokenCount)
 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption-perf/encryption_perf.go` around lines 55 - 65, The
AssertDBPopulatedFunc currently fabricates errors and calls require.NoError;
change those to direct test failures using t.Fatalf: when tokenStatsKey is
missing, call t.Fatalf("missing oauth access tokens count stats, can't continue
the test"); when tokenCount < 14000, call t.Fatalf("expected to create at least
14000 tokens but %d were created", tokenCount). Update the block in
AssertDBPopulatedFunc (which reads tokenCount, ok := statStore[tokenStatsKey])
to remove the temporary err variables and use t.Fatalf with the appropriate
messages.

81-97: Unused namespace parameter in the returned function.

The namespace parameter on line 82 is unused. If this is intentional (OAuth access tokens are cluster-scoped), consider using _ to make it explicit that it's intentionally ignored for clarity, consistent with the other unused parameters.

♻️ Suggested clarification
 func createAccessTokenWrapper(ctx context.Context, tokenClient oauthclient.OAuthAccessTokensGetter) library.DBLoaderFuncType {
-	return func(_ kubernetes.Interface, namespace string, errorCollector func(error), statsCollector func(string)) error {
+	return func(_ kubernetes.Interface, _ string, errorCollector func(error), statsCollector func(string)) error {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption-perf/encryption_perf.go` around lines 81 - 97, The
returned anonymous function in createAccessTokenWrapper currently declares a
parameter named namespace that is never used; update the signature of the
returned func (in createAccessTokenWrapper) to replace the unused namespace
parameter with _ (e.g., func(_ kubernetes.Interface, _ string, errorCollector
func(error), statsCollector func(string)) error) so it's explicit the namespace
is intentionally ignored while keeping the rest of the behavior the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/e2e-oidc/external_oidc.go`:
- Line 75: The suite is being gated incorrectly: change the
CheckFeatureGatesOrSkip call so it only requires FeatureGateExternalOIDC (i.e.,
call CheckFeatureGatesOrSkip(t, testCtx, testClient.configClient,
features.FeatureGateExternalOIDC) instead of passing both gates), and remove
FeatureGateExternalOIDCWithAdditionalClaimMappings from the top-level gate; for
tests that need the additional-claim behavior, add local calls to
CheckFeatureGatesOrSkip (or explicit checks) inside those specific subtests
before exercising code paths that depend on
FeatureGateExternalOIDCWithAdditionalClaimMappings; update references around
CheckFeatureGatesOrSkip and any subtest bodies that currently assume the extra
gate is globally enabled.
- Around line 111-118: The cleanup currently always calls
test.WaitForNewKASRollout after testClient.authResourceRollback even when
authResourceRollback was a no-op; change the cleanup closure (around
kasOriginalRevision, testClient.authResourceRollback, and
test.WaitForNewKASRollout) to detect whether the rollback actually persisted a
change and only call WaitForNewKASRollout when it did. Implement this by either:
(A) updating authResourceRollback to return an indicator (e.g., bool changed) in
addition to error and branch on that, or (B) after authResourceRollback, fetch
the current authentication spec (same shape as origAuthSpec) and compare it to
origAuthSpec and only invoke test.WaitForNewKASRollout if they differ; ensure
require.NoError checks still run for the rollback error but skip the rollout
wait when no spec change occurred.
- Around line 554-568: The informers are started with a non-cancelable context,
leaving goroutines running; change the Start/WaitForCacheSync usage to use a
cancelable context derived via context.WithCancel (derive cancelCtx, cancel :=
context.WithCancel(ctx) or similar) before calling
dynamicInformers.Start(cancelCtx.Done()) and
dynamicInformers.WaitForCacheSync(cancelCtx.Done()), and register cleanup to
stop them by either calling cancel() during test teardown or storing
dynamicInformers on the testClient and calling
dynamicInformers.Shutdown()/Shutdown in the teardown; update the code paths
around NewClusterScopedOperatorClient, dynamicInformers, Start,
WaitForCacheSync, and testClient to ensure the cancel function or Shutdown is
invoked in cleanup.

---

Duplicate comments:
In `@test/library/encryption/perf_helpers.go`:
- Around line 35-46: The poll currently sends any
EncryptionMigrationControllerProgressing condition with Status True, possibly
using a stale LastTransitionTime; fix by recording a start := time.Now()
immediately before calling wait.PollUntilContextTimeout and inside the poll only
send cond.LastTransitionTime to migrationStartedCh when cond.Type ==
"EncryptionMigrationControllerProgressing", cond.Status ==
operatorv1.ConditionTrue, cond.Reason == "Migrating" and
cond.LastTransitionTime.Time.After(start); use getOperatorConditionsFn to fetch
conditions and ensure you return true,nil only when the transition is newer than
start.

In `@test/library/encryption/scenarios.go`:
- Around line 340-349: The update to the APIServer object does a single
read-modify-write and can fail on resourceVersion conflicts; wrap the
mutation+Update call in a retry.RetryOnConflict loop so it re-reads and retries
on conflict. Locate the block that calls libClientSet.ApiServerConfig.Get and
then sets apiServer.Spec.Encryption.Type and calling
libClientSet.ApiServerConfig.Update, and replace that update path with a
retry.RetryOnConflict that fetches the latest ApiServer, applies the same
encryptionType mutation to apiServer.Spec.Encryption.Type, and retries the
Update until it succeeds or a non-conflict error occurs.
- Around line 204-210: The non-blocking select on migrationStartedCh can cause
false failures; replace the select/default with a blocking receive that waits
with a bounded timeout or a cancelable context so the test actually observes the
watcher send. Specifically, wait for migrationStartedCh (instead of the default
path) and compute migrationTime = endTimeStamp.Sub(migrationStarted) before
calling tb.Logf and scenario.AssertMigrationTime; if the timeout/context
expires, call tb.Error with a clear timeout message. Use the existing symbols
migrationStartedCh, endTimeStamp, tb.Logf, and scenario.AssertMigrationTime to
locate and update the code.
- Around line 73-81: The switch in the dispatcher incorrectly routes the
empty-string provider to TestEncryptionTypeIdentity; update the case handling so
that configv1.EncryptionTypeIdentity maps only to TestEncryptionTypeIdentity and
the empty string ("") maps to TestEncryptionTypeUnset. Locate the switch in
TestEncryption scenarios (the switch on provider in scenarios.go) and replace
the combined case `case configv1.EncryptionTypeIdentity, "":
TestEncryptionTypeIdentity(tb, scenario)` with two separate cases: one calling
TestEncryptionTypeIdentity(tb, scenario) for configv1.EncryptionTypeIdentity and
one calling TestEncryptionTypeUnset(tb, scenario) for the "" provider; leave the
other cases (TestEncryptionTypeAESCBC, TestEncryptionTypeAESGCM,
TestEncryptionTypeKMS) unchanged.

---

Nitpick comments:
In `@pkg/controllers/readiness/wellknown_ready_controller.go`:
- Around line 355-358: The loop in getKASTargetPortFromService repeatedly calls
getKASServicePort() inside the condition which obscures intent; cache the result
once before iterating by assigning kasPort := getKASServicePort(), then use
kasPort in the loop condition (referencing getKASTargetPortFromService and
getKASServicePort) so the code is clearer and avoids repeated calls.

In `@test/e2e-encryption-perf/encryption_perf.go`:
- Around line 55-65: The AssertDBPopulatedFunc currently fabricates errors and
calls require.NoError; change those to direct test failures using t.Fatalf: when
tokenStatsKey is missing, call t.Fatalf("missing oauth access tokens count
stats, can't continue the test"); when tokenCount < 14000, call
t.Fatalf("expected to create at least 14000 tokens but %d were created",
tokenCount). Update the block in AssertDBPopulatedFunc (which reads tokenCount,
ok := statStore[tokenStatsKey]) to remove the temporary err variables and use
t.Fatalf with the appropriate messages.
- Around line 81-97: The returned anonymous function in createAccessTokenWrapper
currently declares a parameter named namespace that is never used; update the
signature of the returned func (in createAccessTokenWrapper) to replace the
unused namespace parameter with _ (e.g., func(_ kubernetes.Interface, _ string,
errorCollector func(error), statsCollector func(string)) error) so it's explicit
the namespace is intentionally ignored while keeping the rest of the behavior
the same.
🪄 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: be01b227-071d-425e-b47e-7ae44ef825ce

📥 Commits

Reviewing files that changed from the base of the PR and between 626f7d7 and aa529ed.

⛔ Files ignored due to path filters (11)
  • go.sum is excluded by !**/*.sum
  • vendor/k8s.io/klog/v2/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_no_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klogr.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klogr_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/textlogger/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/textlogger/textlogger.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (22)
  • cmd/cluster-authentication-operator-tests-ext/main.go
  • go.mod
  • pkg/controllers/readiness/wellknown_ready_controller.go
  • test/e2e-encryption-kms/encryption_kms.go
  • test/e2e-encryption-kms/encryption_kms_test.go
  • test/e2e-encryption-kms/main_test.go
  • test/e2e-encryption-perf/encryption_perf.go
  • test/e2e-encryption-perf/encryption_perf_test.go
  • test/e2e-encryption-rotation/e2e-encryption-rotation_test.go
  • test/e2e-encryption-rotation/encryption_rotation.go
  • test/e2e-encryption/encryption.go
  • test/e2e-encryption/encryption_test.go
  • test/e2e-encryption/main_test.go
  • test/e2e-oidc/external_oidc.go
  • test/e2e-oidc/external_oidc_test.go
  • test/library/client.go
  • test/library/encryption/helpers.go
  • test/library/encryption/perf_helpers.go
  • test/library/encryption/scenarios.go
  • test/library/encryption_wrappers.go
  • test/library/featuregates.go
  • test/library/waits.go
💤 Files with no reviewable changes (2)
  • test/e2e-encryption-kms/main_test.go
  • test/e2e-encryption/main_test.go
✅ Files skipped from review due to trivial changes (1)
  • go.mod
🚧 Files skipped from review as they are similar to previous changes (6)
  • test/library/encryption_wrappers.go
  • test/library/featuregates.go
  • cmd/cluster-authentication-operator-tests-ext/main.go
  • test/e2e-encryption-kms/encryption_kms_test.go
  • test/e2e-encryption/encryption.go
  • test/library/waits.go

Comment thread test/e2e-oidc/external_oidc.go
Comment thread test/e2e-oidc/external_oidc.go
Comment thread test/e2e-oidc/external_oidc.go
…nsion framework

This commit migrates five test suites (e2e-encryption, e2e-encryption-kms,
e2e-encryption-perf, e2e-encryption-rotation, e2e-oidc) from standalone
test binaries to the OpenShift Tests Extension (OTE) framework using Ginkgo v2.

Migration Changes:
- Migrate tests to Ginkgo v2 with OTE integration
- Extract test logic into dedicated helper files for better organization
- Remove obsolete main_test.go files in favor of Ginkgo suite setup
- Configure appropriate test suite parallelism and qualifiers
- Add wrapper functions for Ginkgo v2 testing.TB compatibility

Test Organization:
- operator/parallel: Non-serial operator, templates, and tokens tests (parallelism: 4)
- operator/serial: Serial operator, OIDC, templates, and tokens tests
- operator/disruptive: Tests marked as [Disruptive]
- operator-encryption/serial: Basic encryption tests
- operator-encryption-rotation/serial: Encryption key rotation tests
- operator-encryption-perf/serial: Encryption performance tests
- operator-encryption-kms/serial: KMS encryption tests

Dependencies:
- Use standard OTE version v0.0.0-20251205182537-ff5553e56f33
- Updated klog dependency to v2.140.0
- Removed fork dependency (was blocking supply chain review)

Test Reliability Improvements (addresses coderabbitai feedback):
1. Migration timestamp validation:
   - Capture test start time before starting migration watcher
   - Validate cond.Reason == "Migrating"
   - Verify condition transition is fresh (after test start)
   - Prevents accepting stale conditions from previous tests

2. Empty string provider routing:
   - Separate empty string case from Identity case
   - Empty string now correctly calls TestEncryptionTypeUnset
   - Ensures proper encryption defaulting path is exercised

3. Non-blocking select timeout:
   - Replace default case with 30-second timeout
   - Prevents immediate test failure if watcher hasn't sent yet
   - Provides bounded wait instead of instant failure

4. APIServer Get+Update conflict handling:
   - Wrap Get+Update pattern in retry.RetryOnConflict
   - Handle ResourceVersion conflicts from concurrent writes
   - Prevents flaky test failures from transient conflicts

Fixes:
- Fixed KMS plugin deployment calls (added missing count parameter)
- Fixed typo in encryption rotation comment (encyrption -> encryption)

Testing:
- All unit tests pass
- Binary builds successfully (111 MB)
- make verify passes
- No compilation errors

Co-Authored-By: Rohit Patil <ropatil@redhat.com>
@ropatil010 ropatil010 force-pushed the migrate-e2e-encryption-final branch from aa529ed to 805bcb9 Compare April 28, 2026 05:57
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (7)
test/e2e-encryption-kms/encryption_kms.go (2)

48-53: Typo: "techincal" should be "technical".

Line 52 contains a spelling error in the comment.

📝 Fix typo
 	// TODO: Remove this skip once the authentication operator fully supports KMS encryption.
 	// Currently, while the API accepts encryption.type: "KMS" and the operator mounts the KMS
 	// plugin socket, it does not generate the EncryptionConfiguration with KMS provider stanza.
 	// This causes tests to timeout waiting for encryption keys to be created and migration to complete.
-	// See: https://redhat.atlassian.net/browse/OCPSTRAT-108 it is still under techincal preview
+	// See: https://redhat.atlassian.net/browse/OCPSTRAT-108 it is still under technical preview
 	t.Skip("Skipping KMS encryption test: operator implementation is incomplete")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption-kms/encryption_kms.go` around lines 48 - 53, Fix the
spelling mistake in the comment above the t.Skip call: change "techincal" to
"technical" in the comment that references the operator being under technical
preview (the comment block immediately preceding the t.Skip("Skipping KMS
encryption test: operator implementation is incomplete") line).

95-100: Same typo: "techincal" should be "technical".

📝 Fix typo
 	// TODO: Remove this skip once the authentication operator fully supports KMS encryption.
 	// Currently, while the API accepts encryption.type: "KMS" and the operator mounts the KMS
 	// plugin socket, it does not generate the EncryptionConfiguration with KMS provider stanza.
 	// This causes tests to timeout waiting for encryption keys to be created and migration to complete.
-	// See: https://redhat.atlassian.net/browse/OCPSTRAT-108 it is still under techincal preview
+	// See: https://redhat.atlassian.net/browse/OCPSTRAT-108 it is still under technical preview
 	t.Skip("Skipping KMS encryption test: operator implementation is incomplete")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption-kms/encryption_kms.go` around lines 95 - 100, Fix the
typo in the block comment above the t.Skip call: change "techincal" to
"technical" in the sentence referencing the technical preview and the Jira
ticket so the comment reads correctly; the change is in the comment surrounding
the t.Skip("Skipping KMS encryption test: operator implementation is
incomplete") statement in encryption_kms.go.
test/library/encryption/perf_helpers.go (1)

118-120: Misleading log message when workers encounter errors.

The log message "All workers completed successfully" is printed regardless of whether workers encountered errors. Since errors are collected in r.errorStore rather than causing the function to fail, this message can be misleading during debugging.

📝 Suggested improvement
 	r.wg.Wait()
-	t.Log("All workers completed successfully")
+	if len(r.errorStore) > 0 {
+		t.Logf("All workers completed with %d unique error types", len(r.errorStore))
+	} else {
+		t.Log("All workers completed successfully")
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/library/encryption/perf_helpers.go` around lines 118 - 120, The current
code always logs "All workers completed successfully" after r.wg.Wait() which is
misleading because worker errors are stored in r.errorStore; update the
post-wait logic to inspect r.errorStore (e.g., check its error count or
equivalent method on the runner) and only emit the success message when it is
empty, otherwise log or fail the test with the collected errors (use
t.Logf/t.Fatalf and include the contents of r.errorStore) so the message
accurately reflects worker outcomes.
test/e2e-encryption-rotation/encryption_rotation.go (1)

76-76: Use the predefined constant configv1.EncryptionTypeAESCBC instead of string cast.

Line 76 uses configv1.EncryptionType("aescbc"), which works but should use the constant configv1.EncryptionTypeAESCBC defined in the API types. This is consistent with how the constant is used throughout the encryption test library and aligns with the codebase pattern.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-encryption-rotation/encryption_rotation.go` at line 76, Replace the
string-cast usage configv1.EncryptionType("aescbc") with the predefined constant
configv1.EncryptionTypeAESCBC in the EncryptionProvider field; locate the
assignment in encryption_rotation.go (the EncryptionProvider assignment) and
swap the value to configv1.EncryptionTypeAESCBC so the test uses the API
constant consistently with other tests.
test/e2e-oidc/external_oidc.go (3)

950-969: Consider cleaning up test-created Keycloak resources.

The test creates a group and user in Keycloak but doesn't explicitly clean them up. If the Keycloak instance persists across test runs, these resources accumulate. If the IDP cleanup (test.AddKeycloakIDP cleanup handlers at line 127) removes the entire Keycloak deployment, this is acceptable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-oidc/external_oidc.go` around lines 950 - 969, The test creates
Keycloak resources (group and user via kcClient.CreateGroup and
kcClient.CreateUser assigned to variables group and user) but never explicitly
deletes them; add cleanup logic that calls the appropriate
kcClient.DeleteGroup(group) and kcClient.DeleteUser(user) (or equivalent
deletion methods) in a deferred or test cleanup handler after creation, or
ensure these deletions are registered with the existing test.AddKeycloakIDP
cleanup handlers so the group and user are removed when the Keycloak IDP is torn
down.

390-439: Use context-aware HTTP requests for cancellation support.

The client.Get() calls don't support context cancellation. Consider accepting a context parameter and using http.NewRequestWithContext with client.Do() instead. This allows the requests to be cancelled if the test context times out.

♻️ Proposed fix
-func fetchIssuerJWKS(issuerURL string) (*jwks, error) {
+func fetchIssuerJWKS(ctx context.Context, issuerURL string) (*jwks, error) {
 	client := &http.Client{
 		Timeout: 30 * time.Second,
 		Transport: &http.Transport{
 			TLSClientConfig: &tls.Config{
 				InsecureSkipVerify: true,
 				MinVersion:         tls.VersionTLS12,
 			},
 		},
 	}

 	// grab openid-configuration JSON which contains the URL of the provider's JWKS
-	resp, err := client.Get(issuerURL + "/.well-known/openid-configuration")
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, issuerURL+"/.well-known/openid-configuration", nil)
+	if err != nil {
+		return nil, fmt.Errorf("could not create request for well-known config: %v", err)
+	}
+	resp, err := client.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("could not get issuer OpenID well-known configuration: %v", err)
 	}
 	defer resp.Body.Close()
 	// ... similar change for the second request at line 422
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-oidc/external_oidc.go` around lines 390 - 439, fetchIssuerJWKS
currently uses client.Get which doesn't support cancellation; change its
signature to accept ctx context.Context (e.g., fetchIssuerJWKS(ctx
context.Context, issuerURL string) (*jwks, error)) and replace both client.Get
calls with context-aware requests by creating req :=
http.NewRequestWithContext(ctx, "GET",
issuerURL+"/.well-known/openid-configuration", nil) and req =
http.NewRequestWithContext(ctx, "GET", oidcConfig.JwksURL, nil) and use
client.Do(req) for each, preserving existing error handling and defer
resp.Body.Close().

690-716: String-based JSON comparison is fragile.

The exact string comparison of auth-config.json will break if field ordering changes in the operator's JSON marshaling (though Go's json.Marshal is currently deterministic by struct field order). Consider unmarshaling both and using semantic comparison via equality.Semantic.DeepEqual for more robust assertions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e-oidc/external_oidc.go` around lines 690 - 716, The test currently
compares auth-config.json via exact string equality (expectedAuthConfigJSON vs
actualCM.Data["auth-config.json"]) which is fragile; instead unmarshal both the
expectedAuthConfigJSON and actualCM.Data["auth-config.json"] into generic JSON
objects (e.g., map[string]interface{} or interface{}) and use
k8s.io/apimachinery/pkg/api/equality.Semantic.DeepEqual to assert semantic
equality; update the assertion after fetching actualCM (in the loop that calls
tc.kubeClient.CoreV1().ConfigMaps(...).Get) to unmarshal both JSON strings,
check errors with require.NoError, and require.Truef(t,
equality.Semantic.DeepEqual(expectedObj, actualObj), "unexpected
auth-config.json contents in %s/%s: diff=%v", actualCM.Namespace, actualCM.Name,
cmp.Diff(expectedObj, actualObj)) so field ordering changes won’t break the
test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/e2e-encryption-kms/encryption_kms.go`:
- Around line 48-53: Fix the spelling mistake in the comment above the t.Skip
call: change "techincal" to "technical" in the comment that references the
operator being under technical preview (the comment block immediately preceding
the t.Skip("Skipping KMS encryption test: operator implementation is
incomplete") line).
- Around line 95-100: Fix the typo in the block comment above the t.Skip call:
change "techincal" to "technical" in the sentence referencing the technical
preview and the Jira ticket so the comment reads correctly; the change is in the
comment surrounding the t.Skip("Skipping KMS encryption test: operator
implementation is incomplete") statement in encryption_kms.go.

In `@test/e2e-encryption-rotation/encryption_rotation.go`:
- Line 76: Replace the string-cast usage configv1.EncryptionType("aescbc") with
the predefined constant configv1.EncryptionTypeAESCBC in the EncryptionProvider
field; locate the assignment in encryption_rotation.go (the EncryptionProvider
assignment) and swap the value to configv1.EncryptionTypeAESCBC so the test uses
the API constant consistently with other tests.

In `@test/e2e-oidc/external_oidc.go`:
- Around line 950-969: The test creates Keycloak resources (group and user via
kcClient.CreateGroup and kcClient.CreateUser assigned to variables group and
user) but never explicitly deletes them; add cleanup logic that calls the
appropriate kcClient.DeleteGroup(group) and kcClient.DeleteUser(user) (or
equivalent deletion methods) in a deferred or test cleanup handler after
creation, or ensure these deletions are registered with the existing
test.AddKeycloakIDP cleanup handlers so the group and user are removed when the
Keycloak IDP is torn down.
- Around line 390-439: fetchIssuerJWKS currently uses client.Get which doesn't
support cancellation; change its signature to accept ctx context.Context (e.g.,
fetchIssuerJWKS(ctx context.Context, issuerURL string) (*jwks, error)) and
replace both client.Get calls with context-aware requests by creating req :=
http.NewRequestWithContext(ctx, "GET",
issuerURL+"/.well-known/openid-configuration", nil) and req =
http.NewRequestWithContext(ctx, "GET", oidcConfig.JwksURL, nil) and use
client.Do(req) for each, preserving existing error handling and defer
resp.Body.Close().
- Around line 690-716: The test currently compares auth-config.json via exact
string equality (expectedAuthConfigJSON vs actualCM.Data["auth-config.json"])
which is fragile; instead unmarshal both the expectedAuthConfigJSON and
actualCM.Data["auth-config.json"] into generic JSON objects (e.g.,
map[string]interface{} or interface{}) and use
k8s.io/apimachinery/pkg/api/equality.Semantic.DeepEqual to assert semantic
equality; update the assertion after fetching actualCM (in the loop that calls
tc.kubeClient.CoreV1().ConfigMaps(...).Get) to unmarshal both JSON strings,
check errors with require.NoError, and require.Truef(t,
equality.Semantic.DeepEqual(expectedObj, actualObj), "unexpected
auth-config.json contents in %s/%s: diff=%v", actualCM.Namespace, actualCM.Name,
cmp.Diff(expectedObj, actualObj)) so field ordering changes won’t break the
test.

In `@test/library/encryption/perf_helpers.go`:
- Around line 118-120: The current code always logs "All workers completed
successfully" after r.wg.Wait() which is misleading because worker errors are
stored in r.errorStore; update the post-wait logic to inspect r.errorStore
(e.g., check its error count or equivalent method on the runner) and only emit
the success message when it is empty, otherwise log or fail the test with the
collected errors (use t.Logf/t.Fatalf and include the contents of r.errorStore)
so the message accurately reflects worker outcomes.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: b29dbfbd-1513-45ba-a96f-a0e9944a0f1f

📥 Commits

Reviewing files that changed from the base of the PR and between aa529ed and 805bcb9.

⛔ Files ignored due to path filters (11)
  • go.sum is excluded by !**/*.sum
  • vendor/k8s.io/klog/v2/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_no_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klogr.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klogr_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/textlogger/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/textlogger/textlogger.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (22)
  • cmd/cluster-authentication-operator-tests-ext/main.go
  • go.mod
  • pkg/controllers/readiness/wellknown_ready_controller.go
  • test/e2e-encryption-kms/encryption_kms.go
  • test/e2e-encryption-kms/encryption_kms_test.go
  • test/e2e-encryption-kms/main_test.go
  • test/e2e-encryption-perf/encryption_perf.go
  • test/e2e-encryption-perf/encryption_perf_test.go
  • test/e2e-encryption-rotation/e2e-encryption-rotation_test.go
  • test/e2e-encryption-rotation/encryption_rotation.go
  • test/e2e-encryption/encryption.go
  • test/e2e-encryption/encryption_test.go
  • test/e2e-encryption/main_test.go
  • test/e2e-oidc/external_oidc.go
  • test/e2e-oidc/external_oidc_test.go
  • test/library/client.go
  • test/library/encryption/helpers.go
  • test/library/encryption/perf_helpers.go
  • test/library/encryption/scenarios.go
  • test/library/encryption_wrappers.go
  • test/library/featuregates.go
  • test/library/waits.go
💤 Files with no reviewable changes (2)
  • test/e2e-encryption/main_test.go
  • test/e2e-encryption-kms/main_test.go
✅ Files skipped from review due to trivial changes (2)
  • go.mod
  • test/library/encryption/helpers.go
🚧 Files skipped from review as they are similar to previous changes (9)
  • test/library/featuregates.go
  • test/library/client.go
  • test/e2e-encryption/encryption.go
  • pkg/controllers/readiness/wellknown_ready_controller.go
  • test/e2e-encryption/encryption_test.go
  • test/library/waits.go
  • test/e2e-encryption-perf/encryption_perf.go
  • test/library/encryption_wrappers.go
  • test/library/encryption/scenarios.go

@ropatil010
Copy link
Copy Markdown
Contributor Author

/test e2e-agnostic-ipv6

@ropatil010
Copy link
Copy Markdown
Contributor Author

@coderabbitai can you look at failing jobs and see if this PR is the cause of those errors?

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the current CI status for PR `#859`
gh pr view 859 --repo openshift/cluster-authentication-operator --json statusCheckRollup,checks 2>/dev/null || \
gh pr checks 859 --repo openshift/cluster-authentication-operator 2>/dev/null

Unrecoverable error: Failed to clone repository


🏁 Script executed:

#!/bin/bash
# Get the current CI status for PR `#859` - no repo clone needed
gh pr checks 859 --repo openshift/cluster-authentication-operator 2>&1 | head -80

Length of output: 10050


Let me fetch the logs from the failing jobs to understand the root cause.


🏁 Script executed:

#!/bin/bash
# Try to fetch finished.json and junit/build logs from GCS for failing jobs
BASE="https://storage.googleapis.com/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859"

JOBS=(
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-agnostic-upgrade/2049005550200426496"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-perf-serial-ote-1of2/2049005556902924288"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-serial-ote-2of2/2049005571230666752"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-parallel-ote/2049005573680140288"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-serial-ote/2049005575357861888"
)

for job in "${JOBS[@]}"; do
  echo "=============================="
  echo "JOB: $job"
  echo "=============================="
  url="$BASE/$job/finished.json"
  curl -sf "$url" 2>/dev/null || echo "Could not fetch finished.json"
  echo ""
done

Length of output: 3332


🏁 Script executed:

#!/bin/bash
BASE="https://storage.googleapis.com/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859"

JOBS=(
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-agnostic-upgrade/2049005550200426496"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-perf-serial-ote-1of2/2049005556902924288"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-serial-ote-2of2/2049005571230666752"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-parallel-ote/2049005573680140288"
  "pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-serial-ote/2049005575357861888"
)

for job in "${JOBS[@]}"; do
  echo "=============================="
  echo "JOB: $job"
  echo "=============================="
  # Try to get the last 100 lines of build-log.txt
  curl -sf "$BASE/$job/build-log.txt" 2>/dev/null | tail -100
  echo ""
done

Length of output: 50284


@ropatil010: I analyzed the logs for all 5 failing CI jobs. None of the failures appear to be caused by the code changes in this PR. Here's the breakdown:


1. e2e-agnostic-upgrade — ❌ MonitorTest failure

  • Failed with "failed due to a MonitorTest failure" (only 3 failures, threshold: 10).
  • This is a broad platform upgrade test unrelated to the encryption/auth changes in this PR.
  • The failure is at the infrastructure monitoring level, not test code.

2. e2e-aws-operator-encryption-perf-serial-ote-1of2 — ❌ Job timeout (not test failure)

  • The actual test step passed: "Step openshift-e2e-test succeeded after 28m40s"
  • The job failed because the gather-must-gather post-collection step hit the 2-hour overall job timeout: "Process did not finish before 2h0m0s timeout" → reason: executing_graph:interrupted.
  • This is a CI infrastructure timeout, completely unrelated to your PR changes. Note that the counterpart 2of2 job passed.

3. e2e-aws-operator-encryption-serial-ote-2of2 — ❌ MonitorTest failure

  • Failed with "failed due to a MonitorTest failure" (only 3 failures, threshold: 10).
  • Infrastructure-level monitoring failure (availability/invariant monitors), not test code.
  • Note that the counterpart 1of2 job passed.

4. e2e-aws-operator-parallel-ote — ❌ MonitorTest failure

  • Failed with "failed due to a MonitorTest failure" (only 2 failures, threshold: 10).
  • Same pattern — infrastructure monitors, not test code.

5. e2e-aws-operator-serial-ote — ❌ MonitorTest mass failure

  • Failed because 12 Monitor test failures exceeded the threshold of 10: "Mass test failures detected: 12 failures (threshold: 10)".
  • The failures are all infrastructure monitors (pod-lifecycle, image-registry-availability, legacy-storage-invariants, legacy-test-framework-invariants-pathological).
  • None of the 3 actual operator tests failed (3 pass, 0 flaky, 0 skip).

Summary

Job Root Cause Related to PR?
e2e-agnostic-upgrade MonitorTest failure (3/10) ❌ No
e2e-aws-operator-encryption-perf-serial-ote-1of2 Post-phase job timeout (test itself passed!) ❌ No
e2e-aws-operator-encryption-serial-ote-2of2 MonitorTest failure (3/10) ❌ No
e2e-aws-operator-parallel-ote MonitorTest failure (2/10) ❌ No
e2e-aws-operator-serial-ote Mass MonitorTest failure (12/10) ❌ No

All failures are infrastructure-level MonitorTest violations or a CI job timeout during artifact collection — not caused by the code changes in this PR. Notably, all GCP-based encryption jobs passed, the actual test steps in failing jobs either passed or weren't reached, and the original "invalid character 'W'" JSON parsing issue fixed by this PR is not present in any of the failures.

You can safely request a re-run of the failing jobs with /retest.

@ropatil010
Copy link
Copy Markdown
Contributor Author

Failure logs are not wrt the PR. Here the tc execution list

https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-serial-ote/2049005575357861888/artifacts/e2e-aws-operator-serial-ote/openshift-e2e-test/artifacts/e2e.log
         
https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-parallel-ote/2049005573680140288/artifacts/e2e-aws-operator-parallel-ote/openshift-e2e-test/artifacts/e2e.log
         
https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-serial-ote-2of2/2049005571230666752/artifacts/e2e-aws-operator-encryption-serial-ote/openshift-e2e-test/artifacts/e2e.log
         
https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-perf-serial-ote-1of2/2049005556902924288/artifacts/e2e-aws-operator-encryption-perf-serial-ote/openshift-e2e-test/artifacts/e2e.log

PASS logs for profile: e2e-agnostic-ipv6

https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-agnostic-ipv6/2049008063356080128

The dependent PR is merged: openshift/origin#31009

/verified by CI results
@liouk Can you PTAL on this PR which is waiting from long time. Rebased this PR more than 3 times.

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Apr 28, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@ropatil010: This PR has been marked as verified by CI results.

Details

In response to this:

Failure logs are not wrt the PR. Here the tc execution list

https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-serial-ote/2049005575357861888/artifacts/e2e-aws-operator-serial-ote/openshift-e2e-test/artifacts/e2e.log
        
https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-parallel-ote/2049005573680140288/artifacts/e2e-aws-operator-parallel-ote/openshift-e2e-test/artifacts/e2e.log
        
https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-serial-ote-2of2/2049005571230666752/artifacts/e2e-aws-operator-encryption-serial-ote/openshift-e2e-test/artifacts/e2e.log
        
https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-aws-operator-encryption-perf-serial-ote-1of2/2049005556902924288/artifacts/e2e-aws-operator-encryption-perf-serial-ote/openshift-e2e-test/artifacts/e2e.log

PASS logs for profile: e2e-agnostic-ipv6

https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_cluster-authentication-operator/859/pull-ci-openshift-cluster-authentication-operator-master-e2e-agnostic-ipv6/2049008063356080128

The dependent PR is merged: openshift/origin#31009

/verified by CI results
@liouk Can you PTAL on this PR which is waiting from long time. Rebased this PR more than 3 times.

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.

@ropatil010 ropatil010 changed the title CNTRLPLANE-2589: [WIP] Migrate e2e-encryption tests to Ginkgo v2 with stdout fix CNTRLPLANE-2589: [WIP] Migrate e2e-encryption tests to Ginkgo v2 Apr 28, 2026
@ropatil010 ropatil010 changed the title CNTRLPLANE-2589: [WIP] Migrate e2e-encryption tests to Ginkgo v2 CNTRLPLANE-2589: Migrate e2e-* tests to Ginkgo v2 Apr 28, 2026
Comment thread test/library/encryption/scenarios.go Outdated
Remove LocalClientSet type and toLibraryClientSet() converter function
that duplicated library.ClientSet from openshift/library-go. Update
SetAndWaitForEncryptionType to return library.ClientSet directly,
eliminating unnecessary wrapper conversions.

This addresses reviewer feedback on PR openshift#859 to simplify the code and
remove duplication.

Co-Authored-By: Rohit Patil <ropatil@redhat.com>
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Apr 30, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Apr 30, 2026

@ropatil010: This pull request references CNTRLPLANE-2589 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 epic to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Hi Team,

This PR restores the Ginkgo v2 migration from PR #839 with a critical fix for the stdout corruption issue that caused it to be reverted in PR #857.

Changes from PR #839:

  • Migrate e2e-encryption, e2e-encryption-kms, e2e-encryption-perf, e2e-encryption-rotation, and e2e-oidc test suites to Ginkgo v2
  • Add testing.TB compatibility layer for library-go integration
  • Create new test implementation files with Ginkgo v2 specs
  • Configure appropriate test suite parallelism and qualifiers
  • Remove obsolete main_test.go files

Critical fix (new):

  • Redirect klog output to stderr to prevent warnings from corrupting JSON output during test listing. Previously, klog warnings were written to stdout, causing 'invalid character W' JSON parsing errors that blocked nightly CI jobs.

The fix adds klog.SetOutput(os.Stderr) in main() to ensure:

  • stdout contains only clean JSON (parseable by openshift-tests)
  • klog warnings still logged to stderr (visible for debugging)

Fixes the issue from PR #857.

Summary by CodeRabbit

  • Tests

  • Added comprehensive E2E suites for KMS encryption, OIDC (Keycloak), encryption rotation, and encryption performance.

  • Refactored many tests to delegate to shared helpers and moved scenario implementations into reusable library wrappers; several suites constrained to run serially.

  • Added feature-gate checks, migration monitoring, DB population helpers, and removed custom test-order randomization.

  • Test logging now uses test-scoped logs instead of stdout.

  • Chores

  • Updated klog dependency to v2.140.0.

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.

@liouk
Copy link
Copy Markdown
Member

liouk commented Apr 30, 2026

@coderabbitai help

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@liouk
Copy link
Copy Markdown
Member

liouk commented Apr 30, 2026

@ropatil010 could you please also address the following comments from @coderabbitai:

  • test/library/encryption/perf_helpers.go:119 — "All workers completed successfully" logged even when errors occurred in r.errorStore
  • test/e2e-encryption-rotation/encryption_rotation.go:76 and test/e2e-encryption/encryption.go:72 — use configv1.EncryptionType("aescbc") instead of configv1.EncryptionTypeAESCBC
  • test/e2e-oidc/external_oidc.go:950-969 — Keycloak group+user created but never cleaned up
  • test/e2e-oidc/external_oidc.go:390-439fetchIssuerJWKS doesn't accept context for cancellation

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the relevant sections of all affected files

echo "=== test/library/encryption/perf_helpers.go (around line 119) ==="
fd -t f 'perf_helpers.go' --exec cat -n {} | sed -n '100,140p'

echo ""
echo "=== test/e2e-encryption-rotation/encryption_rotation.go (around line 76) ==="
fd -t f 'encryption_rotation.go' test/e2e-encryption-rotation --exec cat -n {} | sed -n '65,90p'

echo ""
echo "=== test/e2e-encryption/encryption.go (around line 72) ==="
fd -t f 'encryption.go' test/e2e-encryption --exec cat -n {} | sed -n '60,85p'

echo ""
echo "=== test/e2e-oidc/external_oidc.go (lines 940-980) ==="
fd -t f 'external_oidc.go' --exec cat -n {} | sed -n '940,985p'

echo ""
echo "=== test/e2e-oidc/external_oidc.go (lines 385-445) ==="
fd -t f 'external_oidc.go' --exec cat -n {} | sed -n '385,445p'

Length of output: 7642


@ropatil010, here are concrete suggestions for each of the four issues:


1. test/library/encryption/perf_helpers.go:119 — Misleading success log

The "All workers completed successfully" message is printed unconditionally, even when workers recorded errors into r.errorStore. Fix by checking the error store before choosing the log message:

	r.wg.Wait()
-	t.Log("All workers completed successfully")
+	if len(r.errorStore) > 0 {
+		t.Logf("Workers completed with %d distinct error type(s)", len(r.errorStore))
+	} else {
+		t.Log("All workers completed successfully")
+	}

2. test/e2e-encryption-rotation/encryption_rotation.go:76 and test/e2e-encryption/encryption.go:72 — Use the named constant

Both files use the raw string cast configv1.EncryptionType("aescbc"). The named constant configv1.EncryptionTypeAESCBC is more idiomatic and avoids a silent typo if the value ever changes:

// encryption_rotation.go:76  and  encryption.go:72
-	EncryptionProvider: configv1.EncryptionType("aescbc"),
+	EncryptionProvider: configv1.EncryptionTypeAESCBC,

3. test/e2e-oidc/external_oidc.go:950-969 — Keycloak group & user not cleaned up

The group and user are created but never deleted. Register cleanup with t.Cleanup immediately after each successful creation so they are removed even if a subsequent require assertion fails mid-test:

	group := names.SimpleNameGenerator.GenerateName("e2e-keycloak-group-")
	err = kcClient.CreateGroup(group)
	require.NoError(t, err)
+	t.Cleanup(func() {
+		if err := kcClient.DeleteGroup(group); err != nil {
+			t.Logf("WARNING: failed to delete Keycloak group %q: %v", group, err)
+		}
+	})

	user := names.SimpleNameGenerator.GenerateName("e2e-keycloak-user-")
	// ...
	err = kcClient.CreateUser(user, email, password, []string{group}, map[string]string{...})
	require.NoError(t, err)
+	t.Cleanup(func() {
+		if err := kcClient.DeleteUser(user); err != nil {
+			t.Logf("WARNING: failed to delete Keycloak user %q: %v", user, err)
+		}
+	})

Note: Adjust DeleteGroup/DeleteUser to match the actual method names on *test.KeycloakClient.


4. test/e2e-oidc/external_oidc.go:390-439fetchIssuerJWKS not context-aware

The function makes two blocking HTTP calls with no way to cancel them. Add a ctx context.Context parameter and use http.NewRequestWithContext for both requests:

-func fetchIssuerJWKS(issuerURL string) (*jwks, error) {
+func fetchIssuerJWKS(ctx context.Context, issuerURL string) (*jwks, error) {
 	client := &http.Client{
 		Timeout: 30 * time.Second,
 		Transport: &http.Transport{
 			TLSClientConfig: &tls.Config{
 				InsecureSkipVerify: true,
 				MinVersion:         tls.VersionTLS12,
 			},
 		},
 	}

-	resp, err := client.Get(issuerURL + "/.well-known/openid-configuration")
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, issuerURL+"/.well-known/openid-configuration", nil)
+	if err != nil {
+		return nil, fmt.Errorf("could not build well-known request: %v", err)
+	}
+	resp, err := client.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("could not get issuer OpenID well-known configuration: %v", err)
 	}
 	defer resp.Body.Close()
 	// ... unmarshal oidcConfig ...

-	resp, err = client.Get(oidcConfig.JwksURL)
+	req, err = http.NewRequestWithContext(ctx, http.MethodGet, oidcConfig.JwksURL, nil)
+	if err != nil {
+		return nil, fmt.Errorf("could not build JWKS request: %v", err)
+	}
+	resp, err = client.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("could not get issuer OpenID well-known JWKS configuration: %v", err)
 	}
 	// ...

Remember to update the call site at line 982 to pass the ctx that's already in scope:

-	issuerJWKS, err := fetchIssuerJWKS(kcClient.IssuerURL())
+	issuerJWKS, err := fetchIssuerJWKS(ctx, kcClient.IssuerURL())

This commit addresses all CodeRabbit AI review suggestions:
- Fix misleading success log in perf_helpers to check error store
- Use named constant EncryptionTypeAESCBC instead of string literal
- Add cleanup handlers for Keycloak groups and users in OIDC tests
- Make fetchIssuerJWKS context-aware with proper cancellation support
- Implement missing DeleteGroup and DeleteUser methods in KeycloakClient

Co-Authored-By: Rohit Patil <ropatil@redhat.com>
@ropatil010
Copy link
Copy Markdown
Contributor Author

/test e2e-agnostic-ipv6

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/e2e-oidc/external_oidc.go`:
- Around line 171-181: The polling callback masks real API errors by setting
cmErr and returning (false, nil); change the callback used in
wait.PollUntilContextTimeout so that when the GET returns a non-NotFound error
you return (false, err) immediately (use the result of
testClient.kubeClient.CoreV1().ConfigMaps(managedNS).Get(...) directly), and
remove the separate cmErr handling; also fix the final require.NoError assertion
to pass the actual error variable (waitErr) as the formatting argument rather
than the undefined err so failures surface immediately from
wait.PollUntilContextTimeout and the ConfigMap GET.

In `@test/library/encryption/perf_helpers.go`:
- Around line 55-58: The polling branch that handles an error from
wait.PollUntilContextTimeout currently logs and returns without notifying
migrationStartedCh, which leaves callers blocked; modify the error path in the
function containing the wait.PollUntilContextTimeout call so that before
returning it either closes migrationStartedCh or sends a zero time value on
migrationStartedCh to signal failure, and update callers to handle a closed
channel/zero time appropriately; reference the wait.PollUntilContextTimeout
invocation and the migrationStartedCh channel when making the change.

In `@test/library/keycloakidp.go`:
- Around line 393-457: DeleteGroup currently uses ListGroups which only fetches
the first page, so targets on later pages are missed and DeleteGroup returns nil
(silent failure); update the logic to either (A) make ListGroups support
pagination (accept first/max or iterate internally) and fetch all pages using
the Keycloak admin query params "first" and "max" until an empty page, or (B)
change DeleteGroup to page through results itself by calling the admin /groups
endpoint with increasing first offsets (e.g., first=0, first+=max) and scanning
each page for the matching name until found. After exhausting pages, return a
clear error (not nil) when the group isn't found. Apply the same pattern for
DeleteUser/ListUsers and use the functions ListGroups, DeleteGroup, ListUsers,
DeleteUser as entry points for the change.
🪄 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: 4568ba91-241f-4c97-b2a4-df197d85e4dd

📥 Commits

Reviewing files that changed from the base of the PR and between 384d967 and ff305c3.

📒 Files selected for processing (6)
  • test/e2e-encryption-perf/encryption_perf.go
  • test/e2e-encryption-rotation/encryption_rotation.go
  • test/e2e-encryption/encryption.go
  • test/e2e-oidc/external_oidc.go
  • test/library/encryption/perf_helpers.go
  • test/library/keycloakidp.go
✅ Files skipped from review due to trivial changes (1)
  • test/e2e-encryption/encryption.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e-encryption-perf/encryption_perf.go

Comment thread test/e2e-oidc/external_oidc.go Outdated
Comment thread test/library/encryption/perf_helpers.go
Comment thread test/library/keycloakidp.go
@ropatil010
Copy link
Copy Markdown
Contributor Author

/uncc @liouk @stbenjam @ibihim

@openshift-ci openshift-ci Bot removed the request for review from ibihim May 4, 2026 16:48
Fix polling error handling and resource pagination issues:
- Make ConfigMap polling fail fast on API errors instead of timing out
- Signal migration watcher failures via channel close to prevent indefinite hangs
- Add pagination support to Keycloak ListGroups/ListUsers to handle >100 entries
- Handle zero-time values from closed channels in migration time calculations

These changes ensure test failures surface immediately and cleanup operations
work correctly with large datasets.

Co-Authored-By: Rohit Patil <ropatil@redhat.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 5, 2026

@ropatil010: 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-aws-operator-serial-ote a96c6eb link false /test e2e-aws-operator-serial-ote
ci/prow/e2e-aws-operator-encryption-serial-ote-2of2 a96c6eb link false /test e2e-aws-operator-encryption-serial-ote-2of2
ci/prow/e2e-aws-operator-parallel-ote a96c6eb link false /test e2e-aws-operator-parallel-ote

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.

@ropatil010
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
test/library/encryption/perf_helpers.go (1)

25-38: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the migration watcher cancelable.

This helper hard-wires the poll loop to context.Background(). If the caller times out waiting on migrationStartedCh, the goroutine keeps polling for up to waitPollTimeout and can keep logging through t after the spec has already returned. Please take a caller-owned context.Context here and cancel it in TestPerfEncryption on both the success and timeout paths.

Suggested direction
-func watchForMigrationControllerProgressingConditionAsync(t testing.TB, getOperatorCondFn library.GetOperatorConditionsFuncType, migrationStartedCh chan time.Time, testStartTime time.Time) {
+func watchForMigrationControllerProgressingConditionAsync(ctx context.Context, t testing.TB, getOperatorCondFn library.GetOperatorConditionsFuncType, migrationStartedCh chan time.Time, testStartTime time.Time) {
 	t.Helper()
-	go watchForMigrationControllerProgressingCondition(t, getOperatorCondFn, migrationStartedCh, testStartTime)
+	go watchForMigrationControllerProgressingCondition(ctx, t, getOperatorCondFn, migrationStartedCh, testStartTime)
 }

-func watchForMigrationControllerProgressingCondition(t testing.TB, getOperatorConditionsFn library.GetOperatorConditionsFuncType, migrationStartedCh chan time.Time, testStartTime time.Time) {
+func watchForMigrationControllerProgressingCondition(ctx context.Context, t testing.TB, getOperatorConditionsFn library.GetOperatorConditionsFuncType, migrationStartedCh chan time.Time, testStartTime time.Time) {
 	t.Helper()

 	t.Logf("Waiting up to %s for the condition %q with the reason %q to be set to true (after %v)", waitPollTimeout.String(), "EncryptionMigrationControllerProgressing", "Migrating", testStartTime)
-	ctx := context.Background()
 	err := wait.PollUntilContextTimeout(ctx, waitPollInterval, waitPollTimeout, true, func(ctx context.Context) (bool, error) {
🤖 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/library/encryption/perf_helpers.go` around lines 25 - 38, The watcher
uses context.Background() so its poll can't be canceled by the caller; change
watchForMigrationControllerProgressingCondition to accept a caller-owned
context.Context parameter and use that context in wait.PollUntilContextTimeout
instead of context.Background(), update the helper wrapper
watchForMigrationControllerProgressingConditionAsync to take and forward the
same context, and in TestPerfEncryption create a cancellable context and cancel
it on both the success and timeout paths to ensure the goroutine stops and stops
logging to t.
🧹 Nitpick comments (1)
test/e2e-encryption/encryption.go (1)

30-39: ⚡ Quick win

Extract the shared oauth-apiserver BasicScenario defaults.

The same Namespace/LabelSelector/secret/operator tuple is repeated in all three helpers here, and the same literal shows up again in the KMS/perf suites. A tiny constructor keeps those suites from drifting on the next config rename.

♻️ Refactor sketch
+func oauthEncryptionBasicScenario() library.BasicScenario {
+	return library.BasicScenario{
+		Namespace:                       "openshift-config-managed",
+		LabelSelector:                   "encryption.apiserver.operator.openshift.io/component=openshift-oauth-apiserver",
+		EncryptionConfigSecretName:      "encryption-config-openshift-oauth-apiserver",
+		EncryptionConfigSecretNamespace: "openshift-config-managed",
+		OperatorNamespace:               "openshift-authentication-operator",
+		TargetGRs:                       operatorencryption.DefaultTargetGRs,
+		AssertFunc:                      operatorencryption.AssertTokens,
+	}
+}
+
 func testEncryptionTypeIdentity(t testing.TB) {
-	testlibrary.TestEncryptionTypeIdentity(t, library.BasicScenario{
-		Namespace:                       "openshift-config-managed",
-		LabelSelector:                   "encryption.apiserver.operator.openshift.io/component" + "=" + "openshift-oauth-apiserver",
-		EncryptionConfigSecretName:      "encryption-config-openshift-oauth-apiserver",
-		EncryptionConfigSecretNamespace: "openshift-config-managed",
-		OperatorNamespace:               "openshift-authentication-operator",
-		TargetGRs:                       operatorencryption.DefaultTargetGRs,
-		AssertFunc:                      operatorencryption.AssertTokens,
-	})
+	testlibrary.TestEncryptionTypeIdentity(t, oauthEncryptionBasicScenario())
 }

Also applies to: 42-51, 54-73

🤖 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-encryption/encryption.go` around lines 30 - 39, Extract the repeated
oauth-apiserver BasicScenario defaults into a small constructor function (e.g.,
newOAuthAPIServerScenario or oauthAPIServerDefaults) that returns
library.BasicScenario prefilled with Namespace="openshift-config-managed",
LabelSelector="encryption.apiserver.operator.openshift.io/component=openshift-oauth-apiserver",
EncryptionConfigSecretName="encryption-config-openshift-oauth-apiserver",
EncryptionConfigSecretNamespace="openshift-config-managed", and
OperatorNamespace="openshift-authentication-operator"; then update
testEncryptionTypeIdentity (and the other helpers that repeat the same literals)
to call that constructor and only set/override the remaining fields (TargetGRs,
AssertFunc, etc.) so all oauth-apiserver consumers (including KMS/perf suites)
share the single source of truth.
🤖 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/e2e-encryption-perf/encryption_perf.go`:
- Around line 55-66: The callback AssertDBPopulatedFunc must fail fast if any
worker errors occurred: inspect errorStore (the map[string]int passed in) before
trusting statStore and require it to be empty (or sum/count > 0 should cause a
test failure) and include details of the non-zero errors in the failure message;
after asserting errorStore is empty, proceed to read tokenStatsKey from
statStore (tokenCount) and assert tokenCount >= 14000 as before. Ensure you
reference AssertDBPopulatedFunc, errorStore, statStore, and tokenStatsKey when
adding the pre-check and error message.

In `@test/e2e-encryption-rotation/encryption_rotation.go`:
- Around line 47-74: The Get→mutate→Update block inside UnsupportedConfigFunc
should be wrapped in retry.RetryOnConflict: call retry.RetryOnConflict with a
closure that re-fetches the operator (cs.OperatorClient.Get(ctx, "cluster",
metav1.GetOptions{})), applies the same json.Unmarshal/SetNestedMap/Marshal
logic to set authOperator.Spec.UnsupportedConfigOverrides.Raw, and then calls
cs.OperatorClient.Update(ctx, authOperator, metav1.UpdateOptions{}), returning
the update error from the closure; propagate the final error returned by
RetryOnConflict. Keep use of ctx, operatorencryption.GetClients,
cs.OperatorClient.Get/Update, and
oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix as in the original
code.

---

Duplicate comments:
In `@test/library/encryption/perf_helpers.go`:
- Around line 25-38: The watcher uses context.Background() so its poll can't be
canceled by the caller; change watchForMigrationControllerProgressingCondition
to accept a caller-owned context.Context parameter and use that context in
wait.PollUntilContextTimeout instead of context.Background(), update the helper
wrapper watchForMigrationControllerProgressingConditionAsync to take and forward
the same context, and in TestPerfEncryption create a cancellable context and
cancel it on both the success and timeout paths to ensure the goroutine stops
and stops logging to t.

---

Nitpick comments:
In `@test/e2e-encryption/encryption.go`:
- Around line 30-39: Extract the repeated oauth-apiserver BasicScenario defaults
into a small constructor function (e.g., newOAuthAPIServerScenario or
oauthAPIServerDefaults) that returns library.BasicScenario prefilled with
Namespace="openshift-config-managed",
LabelSelector="encryption.apiserver.operator.openshift.io/component=openshift-oauth-apiserver",
EncryptionConfigSecretName="encryption-config-openshift-oauth-apiserver",
EncryptionConfigSecretNamespace="openshift-config-managed", and
OperatorNamespace="openshift-authentication-operator"; then update
testEncryptionTypeIdentity (and the other helpers that repeat the same literals)
to call that constructor and only set/override the remaining fields (TargetGRs,
AssertFunc, etc.) so all oauth-apiserver consumers (including KMS/perf suites)
share the single source of truth.
🪄 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: e8222167-d1ad-493c-aa5d-1881a44b8a74

📥 Commits

Reviewing files that changed from the base of the PR and between 24dab9f and a96c6eb.

⛔ Files ignored due to path filters (11)
  • go.sum is excluded by !**/*.sum
  • vendor/k8s.io/klog/v2/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_no_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/internal/serialize/keyvalues_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klogr.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/klogr_slog.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/textlogger/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/klog/v2/textlogger/textlogger.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (23)
  • cmd/cluster-authentication-operator-tests-ext/main.go
  • go.mod
  • pkg/controllers/readiness/wellknown_ready_controller.go
  • test/e2e-encryption-kms/encryption_kms.go
  • test/e2e-encryption-kms/encryption_kms_test.go
  • test/e2e-encryption-kms/main_test.go
  • test/e2e-encryption-perf/encryption_perf.go
  • test/e2e-encryption-perf/encryption_perf_test.go
  • test/e2e-encryption-rotation/e2e-encryption-rotation_test.go
  • test/e2e-encryption-rotation/encryption_rotation.go
  • test/e2e-encryption/encryption.go
  • test/e2e-encryption/encryption_test.go
  • test/e2e-encryption/main_test.go
  • test/e2e-oidc/external_oidc.go
  • test/e2e-oidc/external_oidc_test.go
  • test/library/client.go
  • test/library/encryption/helpers.go
  • test/library/encryption/perf_helpers.go
  • test/library/encryption/scenarios.go
  • test/library/encryption_wrappers.go
  • test/library/featuregates.go
  • test/library/keycloakidp.go
  • test/library/waits.go
💤 Files with no reviewable changes (2)
  • test/e2e-encryption/main_test.go
  • test/e2e-encryption-kms/main_test.go

Comment thread test/e2e-encryption-perf/encryption_perf.go
Comment on lines +47 to +74
UnsupportedConfigFunc: func(rawUnsupportedEncryptionCfg []byte) error {
cs := operatorencryption.GetClients(t)
authOperator, err := cs.OperatorClient.Get(ctx, "cluster", metav1.GetOptions{})
if err != nil {
return err
}

unsupportedConfigAsMap := map[string]interface{}{}
if len(authOperator.Spec.UnsupportedConfigOverrides.Raw) > 0 {
if err := json.Unmarshal(authOperator.Spec.UnsupportedConfigOverrides.Raw, &unsupportedConfigAsMap); err != nil {
return err
}
}
unsupportedEncryptionConfigAsMap := map[string]interface{}{}
if err := json.Unmarshal(rawUnsupportedEncryptionCfg, &unsupportedEncryptionConfigAsMap); err != nil {
return err
}
if err := unstructured.SetNestedMap(unsupportedConfigAsMap, unsupportedEncryptionConfigAsMap, oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix); err != nil {
return err
}
rawUnsupportedCfg, err := json.Marshal(unsupportedConfigAsMap)
if err != nil {
return err
}
authOperator.Spec.UnsupportedConfigOverrides.Raw = rawUnsupportedCfg

_, err = cs.OperatorClient.Update(ctx, authOperator, metav1.UpdateOptions{})
return err
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and read the relevant section
fd -t f "encryption_rotation.go" test/

Repository: openshift/cluster-authentication-operator

Length of output: 137


🏁 Script executed:

# Read the file to see the actual code
wc -l test/e2e-encryption-rotation/encryption_rotation.go

Repository: openshift/cluster-authentication-operator

Length of output: 140


🏁 Script executed:

# Read lines around 47-74 to verify the code
sed -n '40,80p' test/e2e-encryption-rotation/encryption_rotation.go

Repository: openshift/cluster-authentication-operator

Length of output: 1658


🏁 Script executed:

# Check for retry.RetryOnConflict usage in the codebase
rg "retry\.RetryOnConflict" --type go

Repository: openshift/cluster-authentication-operator

Length of output: 1541


🏁 Script executed:

# Check for similar Get-Update patterns
rg "OperatorClient\.Get\(" --type go -A 5 | head -100

Repository: openshift/cluster-authentication-operator

Length of output: 1036


🏁 Script executed:

# Check if retry package is imported anywhere in similar test files
rg '"k8s\.io/client-go/util/retry"' --type go

Repository: openshift/cluster-authentication-operator

Length of output: 874


Wrap the operator update in retry.RetryOnConflict to handle concurrent writes.

This Get → mutate → Update path runs against a live operator resource, so a concurrent write can invalidate the fetched resourceVersion and cause the test to fail spuriously. Please wrap the mutation in retry.RetryOnConflict and re-fetch inside the retry closure.

Suggested fix
+import "k8s.io/client-go/util/retry"
+
 		UnsupportedConfigFunc: func(rawUnsupportedEncryptionCfg []byte) error {
 			cs := operatorencryption.GetClients(t)
-			authOperator, err := cs.OperatorClient.Get(ctx, "cluster", metav1.GetOptions{})
-			if err != nil {
-				return err
-			}
-
-			unsupportedConfigAsMap := map[string]interface{}{}
-			if len(authOperator.Spec.UnsupportedConfigOverrides.Raw) > 0 {
-				if err := json.Unmarshal(authOperator.Spec.UnsupportedConfigOverrides.Raw, &unsupportedConfigAsMap); err != nil {
-					return err
-				}
-			}
-			unsupportedEncryptionConfigAsMap := map[string]interface{}{}
-			if err := json.Unmarshal(rawUnsupportedEncryptionCfg, &unsupportedEncryptionConfigAsMap); err != nil {
-				return err
-			}
-			if err := unstructured.SetNestedMap(unsupportedConfigAsMap, unsupportedEncryptionConfigAsMap, oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix); err != nil {
-				return err
-			}
-			rawUnsupportedCfg, err := json.Marshal(unsupportedConfigAsMap)
-			if err != nil {
-				return err
-			}
-			authOperator.Spec.UnsupportedConfigOverrides.Raw = rawUnsupportedCfg
-
-			_, err = cs.OperatorClient.Update(ctx, authOperator, metav1.UpdateOptions{})
-			return err
+			return retry.RetryOnConflict(retry.DefaultRetry, func() error {
+				authOperator, err := cs.OperatorClient.Get(ctx, "cluster", metav1.GetOptions{})
+				if err != nil {
+					return err
+				}
+
+				unsupportedConfigAsMap := map[string]interface{}{}
+				if len(authOperator.Spec.UnsupportedConfigOverrides.Raw) > 0 {
+					if err := json.Unmarshal(authOperator.Spec.UnsupportedConfigOverrides.Raw, &unsupportedConfigAsMap); err != nil {
+						return err
+					}
+				}
+				unsupportedEncryptionConfigAsMap := map[string]interface{}{}
+				if err := json.Unmarshal(rawUnsupportedEncryptionCfg, &unsupportedEncryptionConfigAsMap); err != nil {
+					return err
+				}
+				if err := unstructured.SetNestedMap(unsupportedConfigAsMap, unsupportedEncryptionConfigAsMap, oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix); err != nil {
+					return err
+				}
+				rawUnsupportedCfg, err := json.Marshal(unsupportedConfigAsMap)
+				if err != nil {
+					return err
+				}
+				authOperator.Spec.UnsupportedConfigOverrides.Raw = rawUnsupportedCfg
+
+				_, err = cs.OperatorClient.Update(ctx, authOperator, metav1.UpdateOptions{})
+				return err
+			})
 		},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
UnsupportedConfigFunc: func(rawUnsupportedEncryptionCfg []byte) error {
cs := operatorencryption.GetClients(t)
authOperator, err := cs.OperatorClient.Get(ctx, "cluster", metav1.GetOptions{})
if err != nil {
return err
}
unsupportedConfigAsMap := map[string]interface{}{}
if len(authOperator.Spec.UnsupportedConfigOverrides.Raw) > 0 {
if err := json.Unmarshal(authOperator.Spec.UnsupportedConfigOverrides.Raw, &unsupportedConfigAsMap); err != nil {
return err
}
}
unsupportedEncryptionConfigAsMap := map[string]interface{}{}
if err := json.Unmarshal(rawUnsupportedEncryptionCfg, &unsupportedEncryptionConfigAsMap); err != nil {
return err
}
if err := unstructured.SetNestedMap(unsupportedConfigAsMap, unsupportedEncryptionConfigAsMap, oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix); err != nil {
return err
}
rawUnsupportedCfg, err := json.Marshal(unsupportedConfigAsMap)
if err != nil {
return err
}
authOperator.Spec.UnsupportedConfigOverrides.Raw = rawUnsupportedCfg
_, err = cs.OperatorClient.Update(ctx, authOperator, metav1.UpdateOptions{})
return err
UnsupportedConfigFunc: func(rawUnsupportedEncryptionCfg []byte) error {
cs := operatorencryption.GetClients(t)
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
authOperator, err := cs.OperatorClient.Get(ctx, "cluster", metav1.GetOptions{})
if err != nil {
return err
}
unsupportedConfigAsMap := map[string]interface{}{}
if len(authOperator.Spec.UnsupportedConfigOverrides.Raw) > 0 {
if err := json.Unmarshal(authOperator.Spec.UnsupportedConfigOverrides.Raw, &unsupportedConfigAsMap); err != nil {
return err
}
}
unsupportedEncryptionConfigAsMap := map[string]interface{}{}
if err := json.Unmarshal(rawUnsupportedEncryptionCfg, &unsupportedEncryptionConfigAsMap); err != nil {
return err
}
if err := unstructured.SetNestedMap(unsupportedConfigAsMap, unsupportedEncryptionConfigAsMap, oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix); err != nil {
return err
}
rawUnsupportedCfg, err := json.Marshal(unsupportedConfigAsMap)
if err != nil {
return err
}
authOperator.Spec.UnsupportedConfigOverrides.Raw = rawUnsupportedCfg
_, err = cs.OperatorClient.Update(ctx, authOperator, metav1.UpdateOptions{})
return err
})
},
🤖 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-encryption-rotation/encryption_rotation.go` around lines 47 - 74,
The Get→mutate→Update block inside UnsupportedConfigFunc should be wrapped in
retry.RetryOnConflict: call retry.RetryOnConflict with a closure that re-fetches
the operator (cs.OperatorClient.Get(ctx, "cluster", metav1.GetOptions{})),
applies the same json.Unmarshal/SetNestedMap/Marshal logic to set
authOperator.Spec.UnsupportedConfigOverrides.Raw, and then calls
cs.OperatorClient.Update(ctx, authOperator, metav1.UpdateOptions{}), returning
the update error from the closure; propagate the final error returned by
RetryOnConflict. Keep use of ctx, operatorencryption.GetClients,
cs.OperatorClient.Get/Update, and
oauthapiconfigobservercontroller.OAuthAPIServerConfigPrefix as in the original
code.

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.

4 participants