Skip to content

CNTRLPLANE-3306: add ExternalOIDCWithUpstreamParity e2e tests - #8287

Merged
enxebre merged 14 commits into
openshift:mainfrom
ehearne-redhat:external-oidc-test-featuregate-externaloidcwithupstreamparity
Jul 3, 2026
Merged

CNTRLPLANE-3306: add ExternalOIDCWithUpstreamParity e2e tests#8287
enxebre merged 14 commits into
openshift:mainfrom
ehearne-redhat:external-oidc-test-featuregate-externaloidcwithupstreamparity

Conversation

@ehearne-redhat

@ehearne-redhat ehearne-redhat commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

This change:

  • Adds extensive testing for the ExternalOIDCWithUpstreamParity feature gate in control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go.

    • Includes testing the discoveryUrl, userValidationRules, claimValidationRules, and claimMappings.
  • Tests the feature gate in a HyperShift cluster in test/e2e/external_oidc_test.go.

  • Provides basic auth config testing of the feature gate in test/e2e/util/external_oidc.go .

  • Configures the control plane operator feature sets in hypershift-operator.

    • This change is required as hypershift-operator re-uses control-plane-operator
      auth config validation code, which checks specifically for control-plane-operator
      feature set enablement.

      Without this change, if we try to enable feature set such as TechPreviewNoUpgrade,
      validation will fail as hypershift-operator does not configure control-plane-operator
      feature sets.

  • Refactors existing tests to use a specified AuthConfig so that when the feature graduates it is easier to add the appropriate fields.

    • Tests can now interact with the keycloak instance via API so they can create
      new users/groups as needed for better testing coverage.

This change will allow us to test feature gates behind TechPreviewNoUpgrade and
others that are present in control-plane-operator, throughout HyperShift.

This should allow us to progress in promotion of the feature from TechPreview to GA.

Which issue(s) this PR fixes:

https://redhat.atlassian.net/browse/CNTRLPLANE-3306.

Allows us to progress in promotion of the ExternalOIDCWithUpstreamParity feature from TechPreview to GA.

Special notes for your reviewer:

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Summary by CodeRabbit

  • New Features

    • Added External OIDC with upstream parity (feature-gated): supports differing discovery URLs, CEL-based claim→username/groups mappings, multiple claim validation rules, and user validation rules (reject system: usernames).
  • Tests

    • Expanded unit and end-to-end tests covering discovery URL propagation, complex CEL claim mappings (nested/conditional/orValue/defaults/filter/map), claim and user validation behaviors, error case for empty CEL claim expression, and runtime username/groups resolution.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

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

openshift-ci-robot commented Apr 20, 2026

Copy link
Copy Markdown

@ehearne-redhat: This pull request references CNTRLPLANE-3306 which is a valid jira issue.

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

Details

In response to this:

What this PR does / why we need it:

This change:

  • Adds extensive testing for the ExternalOIDCWithUpstreamParity feature gate in control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go.

  • Includes testing the discoveryUrl, userValidationRules, claimValidationRules, and claimMappings.

  • Tests the feature gate in a HyperShift cluster in test/e2e/external_oidc_test.go.

  • Provides basic auth config testing of the feature gate in test/e2e/util/external_oidc.go .

This should allow us to progress in promotion of the feature from TechPreview to GA.

Which issue(s) this PR fixes:

https://redhat.atlassian.net/browse/CNTRLPLANE-3306.

Allows us to progress in promotion of the ExternalOIDCWithUpstreamParity feature from TechPreview to GA.

Special notes for your reviewer:

Currently a work in progress. Must check if tests pass at present, and will move PR into working state for review.

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

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

Walkthrough

Added unit and e2e tests and updated a test utility to exercise the ExternalOIDCWithUpstreamParity feature gate. Tests and the utility now emit and verify CEL-based claim mappings for username and groups, add CEL claim validation rules (email presence/non-empty and email_verified == true), and add a CEL user validation rule preventing usernames with the system: prefix. Tests also cover discovery URL handling when it differs from the issuer. All changes are limited to tests and the test helper that builds the AuthenticationConfiguration.

Sequence Diagram(s)

sequenceDiagram
  actor TestRunner
  participant HostedClusterSpec as "HostedCluster Spec"
  participant Controller as "Control Plane Operator"
  participant KAS as "Kube API Server (KAS)"
  participant SSR as "SelfSubjectReview"
  participant OIDC as "External OIDC Provider"

  TestRunner->>HostedClusterSpec: create spec with ExternalOIDCWithUpstreamParity enabled
  HostedClusterSpec->>Controller: reconcile spec
  Controller->>KAS: produce AuthenticationConfiguration (DiscoveryURL, CEL claim mappings, claim/user validation rules)
  KAS->>OIDC: use DiscoveryURL to fetch metadata / validate tokens
  OIDC-->>KAS: return token and user claims
  KAS->>SSR: evaluate ClaimMappings and UserValidationRules (CEL)
  SSR-->>TestRunner: return UserInfo (username, groups) and validation result
Loading
🚥 Pre-merge checks | ✅ 10 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 ❓ Inconclusive Test files referenced in PR summary are not present in repository, preventing verification of test structure quality against Ginkgo patterns. Verify test files are accessible and assess: single responsibility per It() block, proper cleanup in AfterEach(), timeouts on Eventually/Consistently, meaningful assertion messages, and consistency with repository patterns.
✅ Passed checks (10 passed)
Check name Status Explanation
Title check ✅ Passed The title 'CNTRLPLANE-3306: add ExternalOIDCWithUpstreamParity e2e tests' directly and clearly describes the main change: adding e2e tests for the ExternalOIDCWithUpstreamParity feature gate promotion.
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 test names in the PR use stable, deterministic patterns with static string literals and no dynamic values like timestamps, UUIDs, or random suffixes.
Microshift Test Compatibility ✅ Passed New e2e tests for HyperShift's external OIDC feature are guarded by ExternalOIDCWithUpstreamParity feature gate, which is HyperShift-specific and does not apply to MicroShift.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The new e2e test validates OIDC authentication configuration and claim mapping through control-plane APIs without requiring multi-node cluster topology.
Topology-Aware Scheduling Compatibility ✅ Passed PR contains exclusively test-file modifications with no deployment manifests, operator code, or scheduling constraint definitions.
Ote Binary Stdout Contract ✅ Passed The pull request adds only test code and test utility functions with no process-level code that could violate the OTE Binary Stdout Contract.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The new e2e tests do not contain IPv4 assumptions or external connectivity requirements. Tests validate internal Kubernetes OIDC configuration without external service calls.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci openshift-ci Bot added do-not-merge/needs-area do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Apr 20, 2026
@openshift-ci
openshift-ci Bot requested review from bryan-cox and csrwng April 20, 2026 13:10
@openshift-ci openshift-ci Bot added area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/testing Indicates the PR includes changes for e2e testing and removed do-not-merge/needs-area labels Apr 20, 2026
@ehearne-redhat
ehearne-redhat force-pushed the external-oidc-test-featuregate-externaloidcwithupstreamparity branch from 423d933 to 67f1e85 Compare April 20, 2026 13:15

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go (1)

1964-1996: Tighten this negative case by asserting error reason.

This case currently checks only that an error occurs. Please assert an expected error substring (e.g., empty CEL expression) so unrelated failures can’t satisfy the test.

🔧 Suggested pattern
 type testCase struct {
   name                                string
   client                              crclient.Reader
   expectedAuthenticationConfiguration *AuthenticationConfiguration
   hcpAuthenticationSpec               *configv1.AuthenticationSpec
   shouldError                         bool
+  expectedErrContains                 string
   featureGates                        []featuregate.Feature
 }

 // in negative test case:
 shouldError: true,
+expectedErrContains: "expression is not set",

 // in assertion block:
 if tc.shouldError {
   if err == nil {
     t.Fatal("expected an error to have occurred but got none")
   }
+  if tc.expectedErrContains != "" && !strings.Contains(err.Error(), tc.expectedErrContains) {
+    t.Fatalf("expected error containing %q, got: %v", tc.expectedErrContains, err)
+  }
   return
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go`
around lines 1964 - 1996, The test case "claimValidationRule with CEL - empty
expression, error" currently only sets shouldError = true; tighten it by adding
an expected error substring (e.g., expectedErrorSubstring: "empty" or "CEL
expression") and changing the test assertions in the test loop to assert the
returned error string contains that substring rather than merely checking
shouldError; update the test harness code that reads shouldError (the test loop
in auth_test.go) to look for expectedErrorSubstring when an error is returned
(and fail if no substring match) so unrelated failures cannot satisfy 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 `@control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go`:
- Around line 1964-1996: The test case "claimValidationRule with CEL - empty
expression, error" currently only sets shouldError = true; tighten it by adding
an expected error substring (e.g., expectedErrorSubstring: "empty" or "CEL
expression") and changing the test assertions in the test loop to assert the
returned error string contains that substring rather than merely checking
shouldError; update the test harness code that reads shouldError (the test loop
in auth_test.go) to look for expectedErrorSubstring when an error is returned
(and fail if no substring match) so unrelated failures cannot satisfy the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 829cd042-7de5-4a8b-9700-9504081ff9a9

📥 Commits

Reviewing files that changed from the base of the PR and between 5c06422 and 423d933.

📒 Files selected for processing (3)
  • control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go
  • test/e2e/external_oidc_test.go
  • test/e2e/util/external_oidc.go

@ehearne-redhat
ehearne-redhat force-pushed the external-oidc-test-featuregate-externaloidcwithupstreamparity branch from 67f1e85 to 92c4197 Compare April 20, 2026 13:17
@codecov

codecov Bot commented Apr 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 42.34%. Comparing base (712ba58) to head (64cb1b1).
⚠️ Report is 243 commits behind head on main.

Files with missing lines Patch % Lines
hypershift-operator/main.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8287      +/-   ##
==========================================
+ Coverage   41.66%   42.34%   +0.68%     
==========================================
  Files         758      774      +16     
  Lines       93929    97612    +3683     
==========================================
+ Hits        39135    41335    +2200     
- Misses      52046    53393    +1347     
- Partials     2748     2884     +136     
Files with missing lines Coverage Δ
hypershift-operator/main.go 0.00% <0.00%> (ø)

... and 87 files with indirect coverage changes

Flag Coverage Δ
cmd-support 35.88% <ø> (+0.92%) ⬆️
cpo-hostedcontrolplane 45.31% <ø> (+1.31%) ⬆️
cpo-other 45.10% <ø> (+1.64%) ⬆️
hypershift-operator 50.70% <0.00%> (-0.96%) ⬇️
other 31.69% <ø> (+0.13%) ⬆️

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

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

@ehearne-redhat ehearne-redhat changed the title [WIP] CNTRLPLANE-3306: add ExternalOIDCWithUpstreamParity e2e tests CNTRLPLANE-3306: add ExternalOIDCWithUpstreamParity e2e tests Apr 20, 2026
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 20, 2026
Comment thread control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go Outdated
Comment thread control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go Outdated
Comment thread test/e2e/util/external_oidc.go Outdated
Comment thread test/e2e/util/external_oidc.go Outdated
Comment thread test/e2e/external_oidc_test.go Outdated
Comment thread test/e2e/external_oidc_test.go Outdated
Comment thread test/e2e/external_oidc_test.go Outdated
@ehearne-redhat
ehearne-redhat force-pushed the external-oidc-test-featuregate-externaloidcwithupstreamparity branch from 92c4197 to cfa62cb Compare April 22, 2026 16:36
Comment thread test/e2e/external_oidc_test.go Outdated
g.Expect(selfSubjectReview.Status.UserInfo.Username).NotTo(ContainSubstring("@"))
// equals the actual email prefix
// e2eutil.ExternalOIDCExtraKeyFoo --> claims.email expression
emailValues := selfSubjectReview.Status.UserInfo.Extra[e2eutil.ExternalOIDCExtraKeyFoo]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@everettraven do we know if this field is feature gate dependent?

So if ExternalOIDCWithUIDAndExtraClaimMappings feature gate was disabled in the future what impact does it have on accessing this field for email verification?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since I have ensured the field can accessible on either feature gate enablement this shouldn't be an issue. :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That feature gate should already be enabled by default for a couple releases and therefore should never be disabled in the future. We actually need to remove it in the near future.

I don't think we need to check the UserInfo.Extra field as part of these tests though because that is functionality from an entirely different feature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah OK - thanks for clarifying! In that case we would need to use another mechanism as you rightfully pointed out in #8287 (comment) .

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go (1)

2220-2221: ⚠️ Potential issue | 🟠 Major

Use optional claim access before calling orValue here.

These two cases still use claims.groups.orValue([])..., but orValue([]) only works on an optional value. The earlier parity case already uses the correct form: claims.?groups.orValue([]). As written, these "shouldError: false" cases are asserting invalid CEL as a supported mapping.

Suggested fix
-								Expression: "claims.groups.orValue([]).filter(g, g.startsWith('ocp-'))",
+								Expression: "claims.?groups.orValue([]).filter(g, g.startsWith('ocp-'))",
-								Expression: "claims.groups.orValue([]).filter(g, g.startsWith('ocp-'))",
+								Expression: "claims.?groups.orValue([]).filter(g, g.startsWith('ocp-'))",

Also applies to: 2258-2260, 2311-2312, 2356-2358

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

In `@control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go`
around lines 2220 - 2221, The test cases are using non-optional access
`claims.groups.orValue([])...`, which is invalid because `orValue` requires an
optional; update each offending expression to use optional access
`claims.?groups.orValue([]).filter(g, g.startsWith('ocp-'))` (i.e., change
`claims.groups.orValue([])` to `claims.?groups.orValue([])` in the test
vectors). Locate and fix the same pattern occurrences referenced in the file
(the similar expressions around the other test cases that currently use
`claims.groups.orValue([])`).
🤖 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/external_oidc_test.go`:
- Around line 124-128: The username assertion currently reads the expected value
from the extra claim key e2eutil.ExternalOIDCExtraKeyFoo which only exists when
the ExternalOIDCWithUIDAndExtraClaimMappings feature is enabled; update the test
in external_oidc_test.go so it first checks whether
ExternalOIDCWithUIDAndExtraClaimMappings is enabled and only then asserts the
username from
selfSubjectReview.Status.UserInfo.Extra[e2eutil.ExternalOIDCExtraKeyFoo],
otherwise derive the expectedUserName from the test’s chosen upstream user (use
the variable that holds the selected test user/email used to create the upstream
identity) and assert that selfSubjectReview.Status.UserInfo.Username equals that
derived username.

---

Duplicate comments:
In `@control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go`:
- Around line 2220-2221: The test cases are using non-optional access
`claims.groups.orValue([])...`, which is invalid because `orValue` requires an
optional; update each offending expression to use optional access
`claims.?groups.orValue([]).filter(g, g.startsWith('ocp-'))` (i.e., change
`claims.groups.orValue([])` to `claims.?groups.orValue([])` in the test
vectors). Locate and fix the same pattern occurrences referenced in the file
(the similar expressions around the other test cases that currently use
`claims.groups.orValue([])`).
🪄 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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 0971fdb6-6682-4fe9-b2fd-40b3d5169afd

📥 Commits

Reviewing files that changed from the base of the PR and between 92c4197 and cfa62cb.

📒 Files selected for processing (3)
  • control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go
  • test/e2e/external_oidc_test.go
  • test/e2e/util/external_oidc.go

Comment thread test/e2e/external_oidc_test.go Outdated
@ehearne-redhat
ehearne-redhat force-pushed the external-oidc-test-featuregate-externaloidcwithupstreamparity branch from cfa62cb to ac11bf0 Compare April 23, 2026 12:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/e2e/external_oidc_test.go (1)

132-139: Consider verifying actual groups mapping, not just configuration.

This subtest only validates that the groups expression is configured but doesn't verify the actual selfSubjectReview.Status.UserInfo.Groups contains expected values. If the Keycloak test users have groups configured, asserting their presence would strengthen this test.

💡 Suggested enhancement
 t.Run("[OCPFeatureGate:ExternalOIDCWithUpstreamParity] Test CEL groups expression mapping", func(t *testing.T) {
     g := NewWithT(t)
     t.Logf("begin to test CEL groups expression mapping")
     // Groups expression uses: has(claims.groups) && type(claims.groups) == list ? claims.groups : []
     // If the token has groups, they should be present without prefix (no prefix in CEL expression)
     g.Expect(hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimMappings.Groups.Expression).NotTo(BeEmpty())
+    // Verify groups are actually present in the response if user has groups configured
+    g.Expect(selfSubjectReview.Status.UserInfo.Groups).NotTo(BeEmpty())
     t.Logf("CEL groups expression configured: %s", hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimMappings.Groups.Expression)
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/external_oidc_test.go` around lines 132 - 139, The test currently
only asserts the CEL groups expression is configured; instead, after confirming
hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimMappings.Groups.Expression
is not empty, call the same code path that performs a self-subject review
(inspect the SelfSubjectReview object used in this test) and assert that
selfSubjectReview.Status.UserInfo.Groups contains the expected group names for
the Keycloak test user(s). Locate the subtest block (the t.Run with label "Test
CEL groups expression mapping") and add an assertion using the existing test
helper that retrieves the SelfSubjectReview (or create one via the API client
used elsewhere in the test suite) to verify the groups slice is non-empty and
includes the known group(s) for the test account.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go`:
- Around line 2219-2221: The CEL expressions in test fixtures using
PrefixedClaimOrExpression.Expression wrongly call orValue() on possibly-missing
fields (e.g. "claims.groups.orValue([])") which requires optional access; update
each Expression string to use the optional operator before the field (e.g.
"claims.?groups.orValue([])") and do the same for roles (use
"claims.?roles.orValue([])"); apply this change to all occurrences of
PrefixedClaimOrExpression where Expression references claims.groups or
claims.roles (the instances noted around the test cases at the four groups lines
and the two roles lines).

---

Nitpick comments:
In `@test/e2e/external_oidc_test.go`:
- Around line 132-139: The test currently only asserts the CEL groups expression
is configured; instead, after confirming
hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimMappings.Groups.Expression
is not empty, call the same code path that performs a self-subject review
(inspect the SelfSubjectReview object used in this test) and assert that
selfSubjectReview.Status.UserInfo.Groups contains the expected group names for
the Keycloak test user(s). Locate the subtest block (the t.Run with label "Test
CEL groups expression mapping") and add an assertion using the existing test
helper that retrieves the SelfSubjectReview (or create one via the API client
used elsewhere in the test suite) to verify the groups slice is non-empty and
includes the known group(s) for the test account.
🪄 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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 66e94f4c-86ef-48ad-9645-5acece62f594

📥 Commits

Reviewing files that changed from the base of the PR and between cfa62cb and ac11bf0.

📒 Files selected for processing (3)
  • control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go
  • test/e2e/external_oidc_test.go
  • test/e2e/util/external_oidc.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e/util/external_oidc.go

@ehearne-redhat
ehearne-redhat force-pushed the external-oidc-test-featuregate-externaloidcwithupstreamparity branch from ac11bf0 to 842e4e3 Compare April 23, 2026 15:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
test/e2e/external_oidc_test.go (2)

132-139: Outdated comment contradicts actual implementation.

The comment on line 135 states:

// Groups expression uses: has(claims.groups) && type(claims.groups) == list ? claims.groups : []

However, the actual expression set in test/e2e/util/external_oidc.go line 172 is claims.?groups.orValue([]). Please update the comment to reflect the correct expression.

Additionally, this test only verifies configuration was applied (checking Expression is non-empty), not actual behavior. Consider strengthening the test by verifying selfSubjectReview.Status.UserInfo.Groups matches expected values, similar to how username is verified.

📝 Proposed fix for the comment
-			// Groups expression uses: has(claims.groups) && type(claims.groups) == list ? claims.groups : []
-			// If the token has groups, they should be present without prefix (no prefix in CEL expression)
+			// Groups expression uses: claims.?groups.orValue([])
+			// Groups are returned as-is when present, or empty list when absent
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/external_oidc_test.go` around lines 132 - 139, The comment inside
the Test CEL groups expression mapping test is stale and should be updated to
match the actual CEL expression used (claims.?groups.orValue([])) — locate the
test (t.Run "[OCPFeatureGate:ExternalOIDCWithUpstreamParity] Test CEL groups
expression mapping") and replace the old comment with the correct expression
string referencing
hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimMappings.Groups.Expression;
additionally, strengthen the test by fetching the SelfSubjectReview and
asserting selfSubjectReview.Status.UserInfo.Groups contains the expected group
values (similar to the existing username assertion) to verify behavior, not just
configuration presence.

141-156: Test assertions are tightly coupled to implementation details.

The tests hard-code the exact CEL expressions being verified. If the implementation changes these expressions, the tests will fail even if the new expressions are functionally equivalent.

Consider extracting these to constants shared between external_oidc.go and this test file, or using more behavioral assertions where possible.

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

In `@test/e2e/external_oidc_test.go` around lines 141 - 156, The test hard-codes
exact CEL strings from ClaimValidationRules
(hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimValidationRules)
which couples the test to implementation; extract the two CEL expressions into
exported constants (e.g., ClaimExprEmailExists and ClaimExprEmailVerified) in
the package that defines external_oidc.go and reference those constants in this
test, or replace the exact-string assertions with behavioral checks (e.g.,
assert the rule Type is TokenValidationRuleTypeCEL and the CEL expression
contains/semantically matches the expected predicate) so the test verifies
intent not exact syntax.
🤖 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/external_oidc_test.go`:
- Around line 132-139: The comment inside the Test CEL groups expression mapping
test is stale and should be updated to match the actual CEL expression used
(claims.?groups.orValue([])) — locate the test (t.Run
"[OCPFeatureGate:ExternalOIDCWithUpstreamParity] Test CEL groups expression
mapping") and replace the old comment with the correct expression string
referencing
hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimMappings.Groups.Expression;
additionally, strengthen the test by fetching the SelfSubjectReview and
asserting selfSubjectReview.Status.UserInfo.Groups contains the expected group
values (similar to the existing username assertion) to verify behavior, not just
configuration presence.
- Around line 141-156: The test hard-codes exact CEL strings from
ClaimValidationRules
(hostedCluster.Spec.Configuration.Authentication.OIDCProviders[0].ClaimValidationRules)
which couples the test to implementation; extract the two CEL expressions into
exported constants (e.g., ClaimExprEmailExists and ClaimExprEmailVerified) in
the package that defines external_oidc.go and reference those constants in this
test, or replace the exact-string assertions with behavioral checks (e.g.,
assert the rule Type is TokenValidationRuleTypeCEL and the CEL expression
contains/semantically matches the expected predicate) so the test verifies
intent not exact syntax.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 98f452a1-8817-4b7c-898f-55d646f9551c

📥 Commits

Reviewing files that changed from the base of the PR and between ac11bf0 and 842e4e3.

📒 Files selected for processing (3)
  • control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go
  • test/e2e/external_oidc_test.go
  • test/e2e/util/external_oidc.go

@ehearne-redhat
ehearne-redhat force-pushed the external-oidc-test-featuregate-externaloidcwithupstreamparity branch from 842e4e3 to 7870823 Compare April 23, 2026 16:16
Comment thread test/e2e/util/external_oidc.go Outdated
Comment thread test/e2e/util/external_oidc.go Outdated
Comment thread test/e2e/external_oidc_test.go Outdated
g.Expect(selfSubjectReview.Status.UserInfo.Username).NotTo(ContainSubstring("@"))
// equals the actual email prefix
// e2eutil.ExternalOIDCExtraKeyFoo --> claims.email expression
emailValues := selfSubjectReview.Status.UserInfo.Extra[e2eutil.ExternalOIDCExtraKeyFoo]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That feature gate should already be enabled by default for a couple releases and therefore should never be disabled in the future. We actually need to remove it in the near future.

I don't think we need to check the UserInfo.Extra field as part of these tests though because that is functionality from an entirely different feature.

Comment thread test/e2e/external_oidc_test.go Outdated
Comment thread test/e2e/external_oidc_test.go Outdated
Comment thread test/e2e/external_oidc_test.go Outdated
@bryan-cox

Copy link
Copy Markdown
Member

/uncc

@openshift-ci
openshift-ci Bot removed the request for review from bryan-cox April 29, 2026 14:16
@ehearne-redhat

Copy link
Copy Markdown
Contributor Author

/retest

@everettraven

Copy link
Copy Markdown
Contributor

@ehearne-redhat This looks like it is ready for review from a hypershift approver to try and grab the approved label

Comment thread control-plane-operator/controllers/hostedcontrolplane/v2/kas/auth_test.go Outdated
Comment thread hypershift-operator/main.go
Comment thread test/e2e/external_oidc_test.go Outdated
@enxebre enxebre added the tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. label Jul 1, 2026
…eded

This change patches auth config on the fly so we can improve costs
and run time by using one cluster. It follows conventions from
`test/e2e/v2/lifecycle/azure.gotest/e2e/v2/lifecycle/azure.go`
from `postCreateExternalOIDC()` .
This change corrects the test names of introducted tests in
`control-plane-operator/controllers/hostedcontrolplane/v2/
kas/auth_test.go` by renaming the tests following the
`When... it should... ` convention.

Example:

When CEL expression for username and groups with filtering omits
prefix and prefixPolicy, it should generate valid authentication
configuration.
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jul 1, 2026
@ehearne-redhat

Copy link
Copy Markdown
Contributor Author

/test e2e-azure-aks-external-oidc-techpreview
/test e2e-aws-external-oidc-techpreview

This change fixes Eventually() panic error, by
adding gomega to it --> g.Eventually() .
@ehearne-redhat

Copy link
Copy Markdown
Contributor Author

/test e2e-azure-aks-external-oidc-techpreview
/test e2e-aws-external-oidc-techpreview

@ehearne-redhat

Copy link
Copy Markdown
Contributor Author

/test e2e-azure-aks-external-oidc-techpreview

@enxebre

enxebre commented Jul 2, 2026

Copy link
Copy Markdown
Member

/approve

@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ehearne-redhat, enxebre, everettraven

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 2, 2026
@ehearne-redhat

Copy link
Copy Markdown
Contributor Author

/verified by e2e-aws-external-oidc-techpreview, e2e-azure-aks-external-oidc-techpreview

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jul 2, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@ehearne-redhat: This PR has been marked as verified by e2e-aws-external-oidc-techpreview,e2e-azure-aks-external-oidc-techpreview.

Details

In response to this:

/verified by e2e-aws-external-oidc-techpreview, e2e-azure-aks-external-oidc-techpreview

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

liouk commented Jul 2, 2026

Copy link
Copy Markdown
Member

/lgtm

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

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aks-4-22
/test e2e-aws-4-22
/test e2e-aks
/test e2e-aws
/test e2e-aws-upgrade-hypershift-operator
/test e2e-azure-v2-self-managed
/test e2e-kubevirt-aws-ovn-reduced
/test e2e-v2-aws
/test e2e-v2-gke

@ehearne-redhat

Copy link
Copy Markdown
Contributor Author

/test e2e-aks-4-22

@ehearne-redhat

Copy link
Copy Markdown
Contributor Author

/test e2e-aws-4-22

@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@ehearne-redhat: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@hypershift-jira-solve-ci

hypershift-jira-solve-ci Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Now I have the complete picture. Here is the final report:

Test Failure Analysis Complete

Job Information

  • Prow Job: codecov/patch (GitHub check run)
  • Build ID: 84973311266 (GitHub check run ID)
  • PR: #8287CNTRLPLANE-3306: add ExternalOIDCWithUpstreamParity e2e tests
  • Target: Code coverage patch validation
  • Result: 0.00% of diff hit (target 41.66%)

Test Failure Analysis

Error

codecov/patch — 0.00% of diff hit (target 41.66%)
3 lines in hypershift-operator/main.go have 0% patch coverage.

Summary

The codecov/patch check fails because the only non-test, non-ignored file modified in this PR — hypershift-operator/main.go — adds 3 executable lines (an import of cpofeaturegate and a call to cpofeaturegate.ConfigureFeatureSet(featureSet)) that are not exercised by any unit test, yielding 0% patch coverage against a 41.66% target. The other 4 changed files (all test code under test/ or *_test.go) are excluded from Codecov tracking by the repository's .codecov.yml ignore rules. The codecov/project check passes — overall coverage actually increased to 42.34% (+0.68%). All 20+ Prow CI jobs pass successfully.

Root Cause

The PR adds 5 files but 4 are excluded from Codecov instrumentation:

File Reason Excluded
control-plane-operator/.../auth_test.go *_test.go files are never instrumented
test/e2e/external_oidc_test.go Matches test/** ignore rule
test/e2e/util/external_oidc.go Matches test/** ignore rule
test/e2e/util/keycloak.go Matches test/** ignore rule

The only tracked file is hypershift-operator/main.go, where the diff adds:

import (
    cpofeaturegate "github.com/openshift/hypershift/control-plane-operator/featuregates"
)

// In NewStartCommand():
// Configure feature set from CPO (needed to propagate feature gates like TechPreviewNoUpgrade)
cpofeaturegate.ConfigureFeatureSet(featureSet)

These 3 lines live inside NewStartCommand(), which constructs the root Cobra command for the hypershift-operator binary. This is startup initialization code that is inherently tested via integration/e2e rather than unit tests. The file hypershift-operator/main.go has 0% overall coverage on both base and head — this is not a regression; the new lines follow the same untested pattern as the rest of the file.

Since these 3 lines are the only tracked lines in the entire diff, the patch coverage computes to 0.00%, failing the default Codecov patch threshold of 41.66%.

Recommendations
  1. This failure is safe to override/ignore. The codecov/patch check is not a required merge gate — it's an informational GitHub status check. All actual Prow CI jobs pass. The codecov/project check also passes (coverage went up +0.68%).

  2. If the team wants to satisfy the check, two options:

    • Add a unit test for NewStartCommand() in hypershift-operator/main_test.go that calls the function and verifies the returned *cobra.Command is properly configured — this would cover the 3 lines.
    • Add hypershift-operator/main.go to the ignore list in .codecov.yml, since it's a CLI entrypoint inherently tested via integration/e2e. Many projects exclude main.go for this reason.
  3. No functional code changes needed — the PR's code is correct and all e2e tests pass, including the new ExternalOIDCWithUpstreamParity tests.

Evidence
Evidence Detail
Codecov report 0.00% of diff hit (target 41.66%)view on Codecov
Missing lines 3 lines in hypershift-operator/main.go: 1 import (cpofeaturegate) + 1 comment + 1 function call (cpofeaturegate.ConfigureFeatureSet(featureSet))
File baseline coverage hypershift-operator/main.go has 0.00% coverage on both base and head — not a regression
Project coverage Increased from 41.66% → 42.34% (+0.68%) — codecov/project check passes
Ignore rules .codecov.yml ignores test/**, hack/**, *_test.go — excludes 4 of 5 changed files
CI status All 20+ Prow jobs pass (e2e-aws, e2e-aks, e2e-azure, e2e-kubevirt, images, security, verify-deps)
Diff in main.go +4 lines total: 1 import, 1 blank line, 1 comment, 1 ConfigureFeatureSet call (3 executable)

@enxebre
enxebre merged commit 488ef0e into openshift:main Jul 3, 2026
43 of 45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/testing Indicates the PR includes changes for e2e testing jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants