Skip to content

WIP: CNTRLPLANE-3210: Update external OIDC config generation to support external claims sourcing#880

Draft
everettraven wants to merge 6 commits into
openshift:masterfrom
everettraven:feature/ext-claims-impl
Draft

WIP: CNTRLPLANE-3210: Update external OIDC config generation to support external claims sourcing#880
everettraven wants to merge 6 commits into
openshift:masterfrom
everettraven:feature/ext-claims-impl

Conversation

@everettraven
Copy link
Copy Markdown
Contributor

@everettraven everettraven commented May 1, 2026

Summary by CodeRabbit

  • Chores

    • Updated Go module dependencies and added local replace directives for development
  • Refactor

    • External OIDC auth config generation split into pluggable kube-apiserver and oauth-apiserver generators
    • Controller now delegates generation and streamlines sync (removed in-controller validation)
  • New Features

    • Added runtime validators to verify issuer CA/discovery accessibility and CEL expression compilation
  • Tests

    • Simplified controller tests; added extensive unit/validation suites covering generation, CEL checks, external-claims sourcing, and TLS/CA handling
  • Documentation

    • Added package-level docs for the new generator package

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 1, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 1, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 1, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented May 1, 2026

@everettraven: This pull request references CNTRLPLANE-3210 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:

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
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 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

Controller generation/validation of External OIDC AuthenticationConfiguration is delegated to pluggable generators (kubeapiserver or oauthapiserver). OIDC discovery/CA checks, CEL compilation/validation, and email_verified rules moved into generation packages with validators and tests. go.mod adds oauth-apiserver and local replace directives.

Changes

External OIDC refactor + generators

Layer / File(s) Summary
Dependency changes
go.mod
Adds github.com/openshift/oauth-apiserver requirement and replace directives mapping github.com/openshift/api -> ../api/ and github.com/openshift/oauth-apiserver -> ../oauth-apiserver/; bumps some OpenShift deps.
Controller wiring
pkg/controllers/externaloidc/externaloidc_controller.go
Introduces authConfigGenerator interface and field; NewExternalOIDCController selects kubeapiserver vs oauthapiserver generator by feature gate; sync calls GenerateAuthenticationConfiguration and uses the returned runtime.Object; removes in-controller generation/validation; getExpectedApplyConfig now accepts any.
Controller tests
pkg/controllers/externaloidc/externaloidc_controller_test.go
Rewrites sync test to inject mockAuthConfigGenerator, uses fixed issuer and static CA string, updates delete assertions to apierrors.IsNotFound, and removes network-backed validation tests and helpers.
Generation commons
pkg/controllers/externaloidc/generation/common.go
Adds OidcGenerationState, constants, ValidateCACert (HTTPS discovery fetch with CA pool and proxy support), CEL compile wrappers, and ValidateEmailVerifiedUsage with AST helpers.
Common tests
pkg/controllers/externaloidc/generation/common_test.go
Adds TLS test-server scaffolding and TestValidateCACert covering valid/mismatched CA, unknown URL, nil/empty pools, and server error cases.
Kube-apiserver generator core
pkg/controllers/externaloidc/generation/kubeapiserver/generate.go
Adds AuthenticationConfigurationGenerator, constructor, and GenerateAuthenticationConfiguration producing apiserverv1beta1 AuthenticationConfiguration as runtime.Object; implements issuer/discovery validation, optional CA ConfigMap loading, claim mappings (username/groups/UID/extra) with CEL validation, claim/user validation rules, aggregates provider errors, supports optional validator hook.
Kube-apiserver validator
pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
Adds AuthenticationConfigurationValidator that builds per-issuer cert pools, derives discovery URL, and validates discovery endpoint via ValidateCACert, returning descriptive errors.
Kube-apiserver tests & docs
pkg/controllers/externaloidc/generation/kubeapiserver/*
Adds comprehensive generator and validator tests covering CA/configmap errors, discovery URL rules, CEL/claim mapping validation, indexer failures, and package doc.
OAuth-apiserver generator core
pkg/controllers/externaloidc/generation/oauthapiserver/generate.go
Adds AuthenticationConfigurationGenerator producing authenticationv1alpha1 AuthenticationConfiguration; implements issuer/discovery validation, optional CA ConfigMap loading, claim mappings/validation, UID/extra mappings, aggregated errors, optional validator hook, and external-claims-sourcing generation behind feature gate.
OAuth-apiserver validator
pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go
Adds AuthenticationConfigurationValidator mirroring kube-apiserver validator behavior using ValidateCACert.
OAuth-apiserver tests
pkg/controllers/externaloidc/generation/oauthapiserver/*
Adds extensive table-driven tests covering CA/secret/configmap lister failures, discovery validation, claim mapping/CEL validation, external claims sourcing scenarios, and validator TLS tests.

Sequence Diagram(s)

sequenceDiagram
    participant Controller as Controller Sync
    participant Generator as AuthConfig Generator
    participant CMLister as ConfigMap Lister
    participant SecretLister as Secret Lister
    participant Discovery as OIDC Discovery Endpoint
    participant Applier as Server-Side Apply

    Controller->>Generator: GenerateAuthenticationConfiguration(auth)
    Generator->>CMLister: Get CA bundle ConfigMap (optional)
    Generator->>SecretLister: Get client secret (external-claims, optional)
    Generator->>Generator: Compile/validate CEL expressions, build Issuers/Claims
    Generator->>Discovery: GET /.well-known/openid-configuration
    Discovery-->>Generator: Discovery response
    Generator-->>Controller: AuthenticationConfiguration or aggregated errors
    Controller->>Applier: Apply generated config to ConfigMap
    Applier-->>Controller: Apply result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

🚥 Pre-merge checks | ✅ 10 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.23% 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 Custom check specifies Ginkgo test requirements (It blocks, BeforeEach/AfterEach), but all tests use standard Go testing.T and t.Run, not Ginkgo framework. Check criteria target Ginkgo but code uses standard Go tests. Clarify if check applies or provide standard Go testing criteria.
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main objective: updating external OIDC config generation to support external claims sourcing, which aligns with the significant refactoring and new generation code across kubeapiserver and oauthapiserver packages.
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 are stable and deterministic with no dynamic content like timestamps, UUIDs, or variables. All tests use static literal string descriptions.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests are added. All test files use standard Go testing with testing.T patterns, not Ginkgo (It(), Describe(), Context(), etc.). Check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests added. All test additions are standard Go unit tests in pkg/controllers/externaloidc/. The custom SNO check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed No scheduling constraints introduced. PR refactors OIDC authentication config generation logic only, with no deployment manifest or pod spec modifications.
Ote Binary Stdout Contract ✅ Passed PR only modifies pkg/controllers/externaloidc/ code. OTE binary and test/e2e files unchanged. No process-level stdout code affected.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed This PR does not add Ginkgo e2e tests. All new tests use standard Go testing.T framework and are unit tests in pkg/controllers/externaloidc/, not e2e tests. The custom check does not apply.

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

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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 1, 2026
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: 4

Caution

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

⚠️ Outside diff range comments (3)
pkg/controllers/externaloidc/externaloidc_controller_test.go (1)

438-443: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Populate authConfigGenerator in these sync tests.

sync() now always dereferences c.authConfigGenerator; leaving it unset here makes every OIDC testcase panic before the assertions run. A small stub generator per testcase is enough to keep this suite testing controller behavior instead of crashing.

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

In `@pkg/controllers/externaloidc/externaloidc_controller_test.go` around lines
438 - 443, Tests instantiate externalOIDCController without setting
authConfigGenerator, but sync() now dereferences c.authConfigGenerator causing
panics; update the test setup that builds externalOIDCController to set
c.authConfigGenerator to a simple stub generator (e.g., a small function or
struct implementing the generator interface that returns a static/empty auth
config and no error) so each testcase provides a non-nil authConfigGenerator;
reference the externalOIDCController struct instantiation and the sync() call to
locate where to add the stub.
pkg/controllers/externaloidc/externaloidc_controller.go (2)

103-118: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Don't persist secret-bearing oauth config into a ConfigMap.

On the oauth-apiserver path, the generator resolves client-secret values from Secrets into the returned auth object, and this code marshals that object straight into openshift-config-managed/auth-config. That downgrades credential material from Secret storage to plain ConfigMap data.

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

In `@pkg/controllers/externaloidc/externaloidc_controller.go` around lines 103 -
118, The code is persisting secret-bearing oauth client secrets into the managed
ConfigMap (openshift-config-managed/auth-config) by applying the full object
returned from getExpectedApplyConfig; modify the flow so secret material is not
written into a ConfigMap: either strip/omit secret fields (e.g., remove
client-secret entries) from the returned object in getExpectedApplyConfig (or
call a new sanitizeAuthConfig function) before calling
c.configMaps.ConfigMaps(...).Apply, or persist the sensitive parts into a Secret
(use c.secrets.Secrets(...).Apply) and leave only non-secret references in the
ConfigMap; update references to targetAuthConfigCMName/managedNamespace and
ensure c.getExistingApplyConfig comparison uses the sanitized form to avoid
reapplying secrets.

73-84: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Watch Secrets on the external-claims-sourcing path.

When FeatureGateExternalOIDCExternalClaimsSourcing is on, the selected generator reads referenced Secrets via SecretLister(), but this controller only resyncs on Authentication and ConfigMap events. Secret rotation or client-credential updates will leave the rendered auth config stale until some unrelated event happens.

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

In `@pkg/controllers/externaloidc/externaloidc_controller.go` around lines 73 -
84, The controller currently only watches ConfigMaps and Authentications but
must also watch Secrets used by the external-claims-sourcing generator; update
the informer registration in the factory chain (the block starting with
factory.New().WithInformers(...) and WithFilteredEventsInformers(...)) to add a
Secrets informer—e.g., include
kubeInformersForNamespaces.InformersFor(managedNamespace).Core().V1().Secrets().Informer()
(or a NamesFilter-wrapped Secrets informer for the specific secret names) so
that SecretLister() updates trigger c.sync; only add this Secrets informer when
FeatureGateExternalOIDCExternalClaimsSourcing is enabled so the controller
resyncs on secret rotation/client-credential changes.
🤖 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 137-139: In go.mod remove the two local replace directives that
point to ../api/ and ../oauth-apiserver/ so module resolution uses the pinned
upstream pseudo-versions instead; specifically delete the replace lines
referencing github.com/openshift/api => ../api/ and
github.com/openshift/oauth-apiserver => ../oauth-apiserver/ to avoid breaking CI
or downstream consumers that don’t have the sibling paths.

In `@pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go`:
- Around line 3-1551: The entire test suite is commented out with a block
comment starting at the top of generate_test.go, so none of the tests (e.g.
TestExternalOIDCController_generateAuthConfig,
TestExternalOIDCController_validateAuthConfig,
TestExternalOIDCController_validateCACert and helpers like everFailingIndexer,
generateCAKeyPair, generateServingCert) run; remove the surrounding /* ... */
block (or otherwise restore the file to valid Go test source) so the imports and
test functions are active again, ensure the package declaration and imports
compile, then run go test to verify the suite executes.

In `@pkg/controllers/externaloidc/generation/kubeapiserver/generate.go`:
- Around line 695-721: The custom Proxy lambda on the http.Transport only checks
HTTPS_PROXY and ignores standard proxy rules; also the request passed to
client.Do is not bound to the retry context so the 10s retryCtx timeout is
ineffective. Replace the Transport.Proxy assignment with
http.ProxyFromEnvironment and, inside the retry closure passed to
retry.RetryOnConnectionErrors, call req.Clone(ctx) and use client.Do(clonedReq)
so each attempt inherits the retry attempt context (retryCtx). Apply the same
change to the equivalent code in oauthapiserver generate logic.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go`:
- Around line 884-910: The custom proxy function in the http.Client Transport
(where Proxy is currently using httpproxy.FromEnvironment and parsing
HTTPSProxy) should be replaced with the standard http.ProxyFromEnvironment to
respect NO_PROXY, and the retry loop that calls client.Do(req) inside
retry.RetryOnConnectionErrors must pass the per-attempt context so the 10s
deadline cancels in-flight requests; update the retry invocation to call
client.Do(req.Clone(ctx)) (or recreate the request with
http.NewRequestWithContext) instead of reusing req, and remove the custom Proxy
lambda in favor of http.ProxyFromEnvironment in the http.Client construction.

---

Outside diff comments:
In `@pkg/controllers/externaloidc/externaloidc_controller_test.go`:
- Around line 438-443: Tests instantiate externalOIDCController without setting
authConfigGenerator, but sync() now dereferences c.authConfigGenerator causing
panics; update the test setup that builds externalOIDCController to set
c.authConfigGenerator to a simple stub generator (e.g., a small function or
struct implementing the generator interface that returns a static/empty auth
config and no error) so each testcase provides a non-nil authConfigGenerator;
reference the externalOIDCController struct instantiation and the sync() call to
locate where to add the stub.

In `@pkg/controllers/externaloidc/externaloidc_controller.go`:
- Around line 103-118: The code is persisting secret-bearing oauth client
secrets into the managed ConfigMap (openshift-config-managed/auth-config) by
applying the full object returned from getExpectedApplyConfig; modify the flow
so secret material is not written into a ConfigMap: either strip/omit secret
fields (e.g., remove client-secret entries) from the returned object in
getExpectedApplyConfig (or call a new sanitizeAuthConfig function) before
calling c.configMaps.ConfigMaps(...).Apply, or persist the sensitive parts into
a Secret (use c.secrets.Secrets(...).Apply) and leave only non-secret references
in the ConfigMap; update references to targetAuthConfigCMName/managedNamespace
and ensure c.getExistingApplyConfig comparison uses the sanitized form to avoid
reapplying secrets.
- Around line 73-84: The controller currently only watches ConfigMaps and
Authentications but must also watch Secrets used by the external-claims-sourcing
generator; update the informer registration in the factory chain (the block
starting with factory.New().WithInformers(...) and
WithFilteredEventsInformers(...)) to add a Secrets informer—e.g., include
kubeInformersForNamespaces.InformersFor(managedNamespace).Core().V1().Secrets().Informer()
(or a NamesFilter-wrapped Secrets informer for the specific secret names) so
that SecretLister() updates trigger c.sync; only add this Secrets informer when
FeatureGateExternalOIDCExternalClaimsSourcing is enabled so the controller
resyncs on secret rotation/client-credential changes.
🪄 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: 61c219d4-b89b-4932-a2b5-f6d28261ac00

📥 Commits

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

⛔ Files ignored due to path filters (84)
  • go.sum is excluded by !**/*.sum
  • 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/types.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/github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/.golangci.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_apiserver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_authentication.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_dns.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_infrastructure.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_kmsencryption.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1alpha1/types_cluster_monitoring.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/envtest-releases.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/install.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/types_pacemakercluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/etcd/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/etcd/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/etcd/v1alpha1/types_pacemakercluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/features.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/features/features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/machine/v1beta1/types_machineset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/types_ingress.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/types_network.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-CustomNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-CustomNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-CustomNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1alpha1/types_clusterapi.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/quota/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/quota/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/quota/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/security/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/security/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/security/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/security/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yq.mk is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.conversion.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (6)
  • go.mod
  • pkg/controllers/externaloidc/externaloidc_controller.go
  • pkg/controllers/externaloidc/externaloidc_controller_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate.go

Comment thread go.mod Outdated
Comment thread pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go Outdated
Comment thread pkg/controllers/externaloidc/generation/kubeapiserver/generate.go Outdated
Comment thread pkg/controllers/externaloidc/generation/oauthapiserver/generate.go Outdated
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 4, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

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

@openshift-ci openshift-ci Bot removed the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 4, 2026
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

Caution

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

⚠️ Outside diff range comments (1)
pkg/controllers/externaloidc/externaloidc_controller_test.go (1)

3-44: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove unused imports and dead helper functions.

The crypto-related imports (crypto, crypto/ecdsa, crypto/elliptic, crypto/rand, crypto/rsa, crypto/tls, crypto/x509, crypto/x509/pkix, net, and certutil) are only used within the helper functions generateCAKeyPair() and generateServingCert() (lines 472–526), which are never called in this test file. These functions and their associated imports should be removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/externaloidc_controller_test.go` around lines 3
- 44, Remove the unused crypto-related imports (crypto, crypto/ecdsa,
crypto/elliptic, crypto/rand, crypto/rsa, crypto/tls, crypto/x509,
crypto/x509/pkix, net, and certutil) and delete the dead helper functions
generateCAKeyPair() and generateServingCert() which are not referenced anywhere
in the test file; ensure you only remove those specific imports and the two
functions so no other tests or helpers are affected, and run `go vet`/`go test`
to confirm there are no remaining unused-import or undefined-symbol errors.
♻️ Duplicate comments (1)
pkg/controllers/externaloidc/generation/common.go (1)

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

Use standard proxy resolver and bind requests to retry context.

The custom Proxy function only checks HTTPS_PROXY and ignores standard proxy environment variables like NO_PROXY, HTTP_PROXY (lowercase variants), etc. Additionally, client.Do(req) uses the original request without binding to the retry context, so the 10-second retryCtx timeout doesn't actually limit in-flight requests.

Proposed fix
+	"net/http"
-	"golang.org/x/net/http/httpproxy"
...
 	client := &http.Client{
 		Transport: &http.Transport{
 			TLSClientConfig: &tls.Config{RootCAs: caCertPool},
-			Proxy: func(*http.Request) (*url.URL, error) {
-				if proxyConfig := httpproxy.FromEnvironment(); len(proxyConfig.HTTPSProxy) > 0 {
-					return url.Parse(proxyConfig.HTTPSProxy)
-				}
-				return nil, nil
-			},
+			Proxy: http.ProxyFromEnvironment,
 		},
 		Timeout: 5 * time.Second,
 	}
...
 	retry.RetryOnConnectionErrors(retryCtx, func(ctx context.Context) (done bool, err error) {
-		resp, connErr = client.Do(req)
+		resp, connErr = client.Do(req.Clone(ctx))
 		return connErr == nil, connErr
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common.go` around lines 38 - 68, In
ValidateCACert replace the custom Transport.Proxy implementation with the
standard http.ProxyFromEnvironment so all proxy env vars
(HTTP_PROXY/HTTPS_PROXY/no_proxy etc.) and their canonicalization are respected,
and ensure requests executed in retry.RetryOnConnectionErrors are bound to the
retry context by using req.WithContext(ctx) (or creating a new request inside
the retry closure) so the 10s retryCtx deadline actually cancels in-flight
client.Do calls; reference ValidateCACert, the Transport.Proxy field,
client.Do(req), retryCtx and req.WithContext(ctx) when making the changes.
🧹 Nitpick comments (4)
pkg/controllers/externaloidc/generation/common.go (1)

40-41: 💤 Low value

Consider setting TLS MinVersion for production security.

The tls.Config lacks a MinVersion setting. While Go defaults to TLS 1.2 for clients, explicitly setting MinVersion: tls.VersionTLS12 (or tls.VersionTLS13 if legacy OIDC providers aren't a concern) documents the security posture and prevents accidental downgrades if defaults change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common.go` around lines 40 - 41, The
TLS configuration for the HTTP client (the http.Transport with TLSClientConfig
currently set to &tls.Config{RootCAs: caCertPool}) lacks an explicit MinVersion;
update the TLSConfig used by Transport to include MinVersion: tls.VersionTLS12
(or tls.VersionTLS13 if you can drop legacy OIDC support) so the client enforces
a minimum TLS protocol version and prevents downgrades.
pkg/controllers/externaloidc/generation/kubeapiserver/generate.go (1)

336-352: 💤 Low value

UID mapping default case may be unreachable.

The switch statement handles uid == nil, claim-only, expression-only, and both-set cases. The default case at line 350 would only be reached if both Claim and Expression are empty strings (not nil), which seems like it should either be handled explicitly or fall through to the uid == nil case to default to "sub".

Consider simplifying
 switch {
 case uid == nil:
 	out.Claim = "sub"
+case len(uid.Claim) == 0 && len(uid.Expression) == 0:
+	out.Claim = "sub"
 case len(uid.Claim) > 0 && len(uid.Expression) == 0:
 	out.Claim = uid.Claim
 case len(uid.Expression) > 0 && len(uid.Claim) == 0:
 	// ... CEL validation
 case len(uid.Claim) > 0 && len(uid.Expression) > 0:
 	return apiserverv1beta1.ClaimOrExpression{}, fmt.Errorf("uid mapping must set either claim or expression, not both: %v", uid)
-default:
-	return apiserverv1beta1.ClaimOrExpression{}, fmt.Errorf("unable to handle uid mapping: %v", uid)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/kubeapiserver/generate.go` around
lines 336 - 352, The default branch in the switch handling uid mapping is
effectively unreachable for the case where uid is non-nil but both Claim and
Expression are empty; update the logic in generate.go (the switch operating on
uid that sets out.Claim/out.Expression and calls
generation.ValidateClaimsCELExpression) to explicitly treat a non-nil uid with
empty Claim and Expression the same as uid == nil (i.e., set out.Claim = "sub")
or otherwise return a clear error; remove or replace the current default branch
that returns "unable to handle uid mapping" so the function consistently handles
the empty-strings case (either by defaulting to "sub" or by returning a
validation error) and keep references to generation.ValidateClaimsCELExpression
and authenticationcel.ClaimMappingExpression as needed.
pkg/controllers/externaloidc/generation/common_test.go (1)

91-108: 💤 Low value

Test relies on fragile timing assumption.

The "well-known request error" test uses a 6-second sleep to trigger the 5-second client timeout. This could be flaky if CI environments are slow or if timeout values change. Consider using a handler that immediately closes the connection or returns after the context is cancelled.

That said, the current approach works and is straightforward to understand.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common_test.go` around lines 91 -
108, The test "well-known request error" should avoid relying on a 6s sleep to
trigger the client timeout; replace the handlerFunc used with createTestServer
so it immediately simulates a broken connection (for example by using
http.Hijacker on the ResponseWriter and closing the underlying net.Conn) or
otherwise immediately close the connection/return an error, then assert
ValidateCACert(testServer.URL, certPool) returns an error; update the
handlerFunc in the test to perform the immediate-close hijack (referencing
handlerFunc, createTestServer, and ValidateCACert) instead of time.Sleep to make
the test deterministic and CI-stable.
pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go (1)

149-1221: ⚡ Quick win

Add focused cases for ExternalClaimsSources generation path.

This suite is strong on core claim-mapping/issuer behavior, but it currently doesn’t exercise provider ExternalClaimsSources payloads (URL/path expression, auth mode, TLS CA, mappings, predicates). Given this PR’s scope, adding at least one happy-path and one invalid-path case would materially reduce regression risk.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go`
around lines 149 - 1221, Add focused test cases covering ExternalClaimsSources
in TestAuthenticationConfigurationGeneratorGenerateAuthenticationConfiguration:
create one "happy-path" case where
auth.Spec.OIDCProviders[].ExternalClaimsSources has a valid source (URL,
PathExpression, AuthMode, TLS CA referencing baseCABundleConfigMap, mappings and
predicates) and assert expectedAuthConfig via authConfigWithUpdates to include
the generated external claims mapping; and one "invalid-path" case (e.g. bad
URL, missing PathExpression, unsupported AuthMode, or missing TLS CA) that sets
expectError=true. Ensure both cases enable the
features.FeatureGateExternalOIDCExternalClaimsSourcing in featureGates and,
where TLS CA is used, supply caBundleConfigMap/baseCABundleConfigMap; use
authWithUpdates to modify baseAuthResource and reference authConfigWithUpdates
to build expectedAuthConfig.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator_test.go`:
- Around line 126-135: The test case in validator_test.go incorrectly expects
CEL compilation errors even though AuthenticationConfigurationValidator only
validates CA certificates; update the failing case that mutates
authConfig.JWT[0].ClaimMappings.UID (the ClaimOrExpression with Expression
"#@!$&*(^)") to not expect an error (set expectError to false) or remove the
case entirely, or alternatively extend AuthenticationConfigurationValidator to
perform CEL syntax validation if you intend to keep the expectError=true
behavior; reference AuthenticationConfigurationValidator, authConfigWithUpdates,
and ClaimOrExpression to locate the change.

In
`@pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go`:
- Around line 36-42: The error message in the validation block misplaces
certMessage where the validated URL should appear; update the fmt.Errorf call in
the validator (the block calling generation.ValidateCACert) to include the
actual url variable and also mention certMessage for context—e.g. format the
message to contain url first and then certMessage (or both) before the error, so
the output shows the IDP URL being validated and whether system or specified CAs
were used.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go`:
- Around line 709-724: The loop currently accumulates validation errors into
errs but still appends every predicate to out and always returns nil; change the
logic in the loop so that when validation.ValidateExternalSourceCondition(...)
returns an error you append a formatted error to errs and do NOT append that
invalid predicate to out, and after the loop if errs is non-empty return an
aggregated error (e.g. utilerrors.NewAggregate or fmt.Errorf combined) instead
of nil; update references in this code path (externalSourcePredicates,
seenConditions, validation.ValidateExternalSourceCondition,
kubeErrorListToGoError, out) so callers receive a non-nil error for validation
failures.
- Around line 672-673: The call to ValidateExternalClaimsSourceURLPathExpression
is wired to the wrong field: it currently passes &sourceURL.Hostname so path
expressions are never validated; change the argument to
&sourceURL.PathExpression (keeping externaloidccel.NewCompiler(),
field.NewPath(""), and the kubeErrorListToGoError wrapping intact) so the
validator runs against the actual PathExpression field.

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`:
- Around line 126-135: The test fails because
ValidateAuthenticationConfiguration() does not validate CEL expressions; either
update the validator to run CEL checks or remove the test case. To fix, add CEL
validation calls inside
AuthenticationConfigurationValidator.ValidateAuthenticationConfiguration(): for
JWT/claim mappings call generation.ValidateClaimsCELExpression() (and
generation.ValidateUserCELExpression() for user-related expressions) on fields
like JWT[0].ClaimMappings.UID.Expression and other ClaimOrExpression entries,
return an error if those validations fail; alternatively, if you prefer not to
change runtime validation, remove or change the "cel expression can not compile"
test case so it no longer expects an error.

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go`:
- Around line 36-42: The error message in validator.go inside the
generation.ValidateCACert error path is missing the actual URL and misplaces the
cert description; update the fmt.Errorf call in that block (where
generation.ValidateCACert(url, caCertPool) is checked) to include the URL and
then the certMessage (e.g., "could not validate IDP URL %s using %s: %v", url,
certMessage, err) so the returned error includes both the IDP URL and which CA
set was used.

---

Outside diff comments:
In `@pkg/controllers/externaloidc/externaloidc_controller_test.go`:
- Around line 3-44: Remove the unused crypto-related imports (crypto,
crypto/ecdsa, crypto/elliptic, crypto/rand, crypto/rsa, crypto/tls, crypto/x509,
crypto/x509/pkix, net, and certutil) and delete the dead helper functions
generateCAKeyPair() and generateServingCert() which are not referenced anywhere
in the test file; ensure you only remove those specific imports and the two
functions so no other tests or helpers are affected, and run `go vet`/`go test`
to confirm there are no remaining unused-import or undefined-symbol errors.

---

Duplicate comments:
In `@pkg/controllers/externaloidc/generation/common.go`:
- Around line 38-68: In ValidateCACert replace the custom Transport.Proxy
implementation with the standard http.ProxyFromEnvironment so all proxy env vars
(HTTP_PROXY/HTTPS_PROXY/no_proxy etc.) and their canonicalization are respected,
and ensure requests executed in retry.RetryOnConnectionErrors are bound to the
retry context by using req.WithContext(ctx) (or creating a new request inside
the retry closure) so the 10s retryCtx deadline actually cancels in-flight
client.Do calls; reference ValidateCACert, the Transport.Proxy field,
client.Do(req), retryCtx and req.WithContext(ctx) when making the changes.

---

Nitpick comments:
In `@pkg/controllers/externaloidc/generation/common_test.go`:
- Around line 91-108: The test "well-known request error" should avoid relying
on a 6s sleep to trigger the client timeout; replace the handlerFunc used with
createTestServer so it immediately simulates a broken connection (for example by
using http.Hijacker on the ResponseWriter and closing the underlying net.Conn)
or otherwise immediately close the connection/return an error, then assert
ValidateCACert(testServer.URL, certPool) returns an error; update the
handlerFunc in the test to perform the immediate-close hijack (referencing
handlerFunc, createTestServer, and ValidateCACert) instead of time.Sleep to make
the test deterministic and CI-stable.

In `@pkg/controllers/externaloidc/generation/common.go`:
- Around line 40-41: The TLS configuration for the HTTP client (the
http.Transport with TLSClientConfig currently set to &tls.Config{RootCAs:
caCertPool}) lacks an explicit MinVersion; update the TLSConfig used by
Transport to include MinVersion: tls.VersionTLS12 (or tls.VersionTLS13 if you
can drop legacy OIDC support) so the client enforces a minimum TLS protocol
version and prevents downgrades.

In `@pkg/controllers/externaloidc/generation/kubeapiserver/generate.go`:
- Around line 336-352: The default branch in the switch handling uid mapping is
effectively unreachable for the case where uid is non-nil but both Claim and
Expression are empty; update the logic in generate.go (the switch operating on
uid that sets out.Claim/out.Expression and calls
generation.ValidateClaimsCELExpression) to explicitly treat a non-nil uid with
empty Claim and Expression the same as uid == nil (i.e., set out.Claim = "sub")
or otherwise return a clear error; remove or replace the current default branch
that returns "unable to handle uid mapping" so the function consistently handles
the empty-strings case (either by defaulting to "sub" or by returning a
validation error) and keep references to generation.ValidateClaimsCELExpression
and authenticationcel.ClaimMappingExpression as needed.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go`:
- Around line 149-1221: Add focused test cases covering ExternalClaimsSources in
TestAuthenticationConfigurationGeneratorGenerateAuthenticationConfiguration:
create one "happy-path" case where
auth.Spec.OIDCProviders[].ExternalClaimsSources has a valid source (URL,
PathExpression, AuthMode, TLS CA referencing baseCABundleConfigMap, mappings and
predicates) and assert expectedAuthConfig via authConfigWithUpdates to include
the generated external claims mapping; and one "invalid-path" case (e.g. bad
URL, missing PathExpression, unsupported AuthMode, or missing TLS CA) that sets
expectError=true. Ensure both cases enable the
features.FeatureGateExternalOIDCExternalClaimsSourcing in featureGates and,
where TLS CA is used, supply caBundleConfigMap/baseCABundleConfigMap; use
authWithUpdates to modify baseAuthResource and reference authConfigWithUpdates
to build expectedAuthConfig.
🪄 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: ba40a147-7651-4efa-860b-c5de82336230

📥 Commits

Reviewing files that changed from the base of the PR and between 4f4e613 and 834e097.

⛔ Files ignored due to path filters (78)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/coreos/go-oidc/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/.travis.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/DCO is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/MAINTAINERS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/NOTICE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/code-of-conduct.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/jose.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/jwks.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/oidc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/test is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/go-oidc/verify.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_authentication.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/conversion/conversion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/validation/validation.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/cel/accessors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/cel/compiler.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/cel/mappers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/oidc/externalclaims/resolver/resolver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/oidc/externalclaims/tokengetters/anonymous.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/oidc/externalclaims/tokengetters/clientcredential.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/oidc/externalclaims/tokengetters/requestprovided.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/oidc/oidc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/.travis.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/api.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/cacheobject/directive.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/cacheobject/lex.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/cacheobject/object.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/cacheobject/reasons.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/cacheobject/warning.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/pquerna/cachecontrol/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/crypto/ed25519/ed25519.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go is excluded by !**/vendor/**, !vendor/**
  • vendor/golang.org/x/oauth2/clientcredentials/clientcredentials.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/.gitcookies.sh.enc is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/.travis.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/asymmetric.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/cipher/cbc_hmac.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/cipher/concat_kdf.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/cipher/ecdh_es.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/cipher/key_wrap.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/crypter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/encoding.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/decode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/encode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/indent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/scanner.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/stream.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/json/tags.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/jwe.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/jwk.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/jws.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/opaque.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/shared.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/signing.go is excluded by !**/vendor/**, !vendor/**
  • vendor/gopkg.in/go-jose/go-jose.v2/symmetric.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/apiserver/pkg/authentication/token/jwt/jwt.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (13)
  • go.mod
  • pkg/controllers/externaloidc/externaloidc_controller_test.go
  • pkg/controllers/externaloidc/generation/common.go
  • pkg/controllers/externaloidc/generation/common_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • go.mod

Comment on lines +36 to +42
if err := generation.ValidateCACert(url, caCertPool); err != nil {
certMessage := "using the specified CA cert"
if caCertPool == nil {
certMessage = "using the system CAs"
}
return fmt.Errorf("could not validate IDP URL %s: %v", certMessage, 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 | 🟡 Minor | ⚡ Quick win

Error message format issue - same as oauthapiserver validator.

Same issue as the oauthapiserver validator: the error message substitutes certMessage where the URL is expected. The actual URL being validated should be included for debugging.

Proposed fix
 		if err := generation.ValidateCACert(url, caCertPool); err != nil {
 			certMessage := "using the specified CA cert"
 			if caCertPool == nil {
 				certMessage = "using the system CAs"
 			}
-			return fmt.Errorf("could not validate IDP URL %s: %v", certMessage, err)
+			return fmt.Errorf("could not validate IDP URL %q (%s): %v", url, certMessage, 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
`@pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go`
around lines 36 - 42, The error message in the validation block misplaces
certMessage where the validated URL should appear; update the fmt.Errorf call in
the validator (the block calling generation.ValidateCACert) to include the
actual url variable and also mention certMessage for context—e.g. format the
message to contain url first and then certMessage (or both) before the error, so
the output shows the IDP URL being validated and whether system or specified CAs
were used.

Comment on lines +672 to +673
if err := validation.ValidateExternalClaimsSourceURLPathExpression(externaloidccel.NewCompiler(), &sourceURL.Hostname, field.NewPath("")); err != nil {
return nil, fmt.Errorf("validating path expression: %w", kubeErrorListToGoError(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 | 🔴 Critical | ⚡ Quick win

Path-expression validation is wired to the wrong input field.

On Line 672, ValidateExternalClaimsSourceURLPathExpression receives &sourceURL.Hostname instead of &sourceURL.PathExpression, so path expressions are not actually validated.

Proposed fix
-	if err := validation.ValidateExternalClaimsSourceURLPathExpression(externaloidccel.NewCompiler(), &sourceURL.Hostname, field.NewPath("")); err != nil {
+	if err := validation.ValidateExternalClaimsSourceURLPathExpression(externaloidccel.NewCompiler(), &sourceURL.PathExpression, field.NewPath("")); err != nil {
 		return nil, fmt.Errorf("validating path expression: %w", kubeErrorListToGoError(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
if err := validation.ValidateExternalClaimsSourceURLPathExpression(externaloidccel.NewCompiler(), &sourceURL.Hostname, field.NewPath("")); err != nil {
return nil, fmt.Errorf("validating path expression: %w", kubeErrorListToGoError(err))
if err := validation.ValidateExternalClaimsSourceURLPathExpression(externaloidccel.NewCompiler(), &sourceURL.PathExpression, field.NewPath("")); err != nil {
return nil, fmt.Errorf("validating path expression: %w", kubeErrorListToGoError(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 `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go` around
lines 672 - 673, The call to ValidateExternalClaimsSourceURLPathExpression is
wired to the wrong field: it currently passes &sourceURL.Hostname so path
expressions are never validated; change the argument to
&sourceURL.PathExpression (keeping externaloidccel.NewCompiler(),
field.NewPath(""), and the kubeErrorListToGoError wrapping intact) so the
validator runs against the actual PathExpression field.

Comment on lines +709 to +724
errs := []error{}
seenConditions := sets.New[string]()
for i, predicate := range externalSourcePredicates {
cond := authentication.ExternalSourceCondition{
Expression: &predicate.Expression,
}
if err := validation.ValidateExternalSourceCondition(externaloidccel.NewCompiler(), cond, seenConditions, field.NewPath("")); err != nil {
errs = append(errs, fmt.Errorf("validating predicates[%d]: validating expression %q: %w", i, predicate.Expression, kubeErrorListToGoError(err)))
}

out = append(out, authenticationv1alpha1.ExternalSourceCondition{
Expression: &predicate.Expression,
})
}

return out, nil
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

Predicate validation errors are dropped, so invalid conditions can be emitted.

errs is accumulated but never returned; Line 724 always returns nil error. That bypasses validation failures in predicates.

Proposed fix
 	for i, predicate := range externalSourcePredicates {
 		cond := authentication.ExternalSourceCondition{
 			Expression: &predicate.Expression,
 		}
 		if err := validation.ValidateExternalSourceCondition(externaloidccel.NewCompiler(), cond, seenConditions, field.NewPath("")); err != nil {
 			errs = append(errs, fmt.Errorf("validating predicates[%d]: validating expression %q: %w", i, predicate.Expression, kubeErrorListToGoError(err)))
+			continue
 		}
 
 		out = append(out, authenticationv1alpha1.ExternalSourceCondition{
 			Expression: &predicate.Expression,
 		})
 	}
 
-	return out, nil
+	return out, errors.Join(errs...)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go` around
lines 709 - 724, The loop currently accumulates validation errors into errs but
still appends every predicate to out and always returns nil; change the logic in
the loop so that when validation.ValidateExternalSourceCondition(...) returns an
error you append a formatted error to errs and do NOT append that invalid
predicate to out, and after the loop if errs is non-empty return an aggregated
error (e.g. utilerrors.NewAggregate or fmt.Errorf combined) instead of nil;
update references in this code path (externalSourcePredicates, seenConditions,
validation.ValidateExternalSourceCondition, kubeErrorListToGoError, out) so
callers receive a non-nil error for validation failures.

Comment on lines +126 to +135
name: "cel expression can not compile",
authConfig: authConfigWithUpdates(baseAuthConfig, []func(*authenticationv1alpha1.AuthenticationConfiguration){
func(authConfig *authenticationv1alpha1.AuthenticationConfiguration) {
authConfig.JWT[0].ClaimMappings.UID = authenticationv1alpha1.ClaimOrExpression{
Expression: "#@!$&*(^)",
}
},
}),
expectError: true,
},
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:

#!/bin/bash
# Check if the validator validates CEL expressions
rg -n "CEL|Expression|ValidateClaims" pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go

Repository: openshift/cluster-authentication-operator

Length of output: 67


🏁 Script executed:

# Read the validator.go file to see what it actually validates
cat -n pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go

Repository: openshift/cluster-authentication-operator

Length of output: 1792


🏁 Script executed:

# Read the test file around the CEL test case to understand the structure
sed -n '75,160p' pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go

Repository: openshift/cluster-authentication-operator

Length of output: 2918


🏁 Script executed:

# Search for CEL validation in related files
rg -n "ValidateCEL|compileCEL|CEL.*Expression" --type go pkg/controllers/externaloidc/

Repository: openshift/cluster-authentication-operator

Length of output: 3722


Test expects CEL validation that the validator doesn't perform.

The test case "cel expression can not compile" expects an error when UID.Expression is set to invalid CEL syntax. However, the AuthenticationConfigurationValidator.ValidateAuthenticationConfiguration() method only validates CA certificates and HTTPS URLs—it does not validate CEL expressions at all. The test will fail because the validator returns nil (no error) for this case, but the test expects an error.

CEL validation functions exist in the codebase (generation.ValidateClaimsCELExpression(), generation.ValidateUserCELExpression()) and are used in the generator code, but not in the validator. Either extend the validator to validate CEL expressions or remove this test case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`
around lines 126 - 135, The test fails because
ValidateAuthenticationConfiguration() does not validate CEL expressions; either
update the validator to run CEL checks or remove the test case. To fix, add CEL
validation calls inside
AuthenticationConfigurationValidator.ValidateAuthenticationConfiguration(): for
JWT/claim mappings call generation.ValidateClaimsCELExpression() (and
generation.ValidateUserCELExpression() for user-related expressions) on fields
like JWT[0].ClaimMappings.UID.Expression and other ClaimOrExpression entries,
return an error if those validations fail; alternatively, if you prefer not to
change runtime validation, remove or change the "cel expression can not compile"
test case so it no longer expects an error.

Comment on lines +36 to +42
if err := generation.ValidateCACert(url, caCertPool); err != nil {
certMessage := "using the specified CA cert"
if caCertPool == nil {
certMessage = "using the system CAs"
}
return fmt.Errorf("could not validate IDP URL %s: %v", certMessage, 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 | 🟡 Minor | ⚡ Quick win

Error message is confusing - URL not included.

The error format string "could not validate IDP URL %s: %v" substitutes certMessage (e.g., "using the specified CA cert") for %s, making the message read awkwardly like "could not validate IDP URL using the specified CA cert: ...". The actual URL being validated is not included, making debugging harder.

Proposed fix
 		if err := generation.ValidateCACert(url, caCertPool); err != nil {
 			certMessage := "using the specified CA cert"
 			if caCertPool == nil {
 				certMessage = "using the system CAs"
 			}
-			return fmt.Errorf("could not validate IDP URL %s: %v", certMessage, err)
+			return fmt.Errorf("could not validate IDP URL %q (%s): %v", url, certMessage, 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
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go`
around lines 36 - 42, The error message in validator.go inside the
generation.ValidateCACert error path is missing the actual URL and misplaces the
cert description; update the fmt.Errorf call in that block (where
generation.ValidateCACert(url, caCertPool) is checked) to include the URL and
then the certMessage (e.g., "could not validate IDP URL %s using %s: %v", url,
certMessage, err) so the returned error includes both the IDP URL and which CA
set was used.

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 7, 2026
@everettraven everettraven force-pushed the feature/ext-claims-impl branch from 834e097 to 7438b6f Compare May 8, 2026 16:26
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

🧹 Nitpick comments (5)
pkg/controllers/externaloidc/generation/oauthapiserver/generate.go (1)

578-578: ⚡ Quick win

Unused variable printableASCIIRegexp.

This regexp is defined but never referenced in the code. It appears to be leftover from commented-out validation code.

Proposed fix
-var printableASCIIRegexp = regexp.MustCompile(`^[[:print:]]+$`)

Or add a comment indicating this will be used when validation is enabled:

+// printableASCIIRegexp is used for client secret validation when enabled.
+// TODO: Remove this comment when validation is uncommented.
 var printableASCIIRegexp = regexp.MustCompile(`^[[:print:]]+$`)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go` at line
578, The declared variable printableASCIIRegexp in generate.go is unused; either
remove the declaration or document why it remains (e.g., add a comment stating
it is reserved for future validation) so linters won't flag it. Locate the
regexp variable named printableASCIIRegexp and either delete that line or
replace it with a short explanatory comment referencing its intended use in
future validation logic (e.g., for username/label printable-ASCII checks).
pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go (1)

1789-1790: 💤 Low value

Generator validator field is set directly instead of through constructor.

The test sets c.validator directly after construction. Consider adding a WithValidator option or setter method to the generator for cleaner API design.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go`
around lines 1789 - 1790, The test directly assigns the private validator field
(c.validator) on the object returned by NewAuthenticationConfigurationGenerator;
instead, add a public option or setter to inject the validator (e.g., implement
a WithValidator functional option or a SetValidator method on
AuthenticationConfigurationGenerator) and update
NewAuthenticationConfigurationGenerator to accept options or expose the setter,
then change tests to use NewAuthenticationConfigurationGenerator(...,
WithValidator(tt.configValidator)) or c.SetValidator(tt.configValidator) and
remove direct field assignment.
pkg/controllers/externaloidc/generation/common_test.go (2)

43-48: 💤 Low value

Duplicate test cases testing the same scenario.

Both "nil CA cert to use system CAs" (line 43) and "nil cert pool" (line 77) test the same condition - passing nil to ValidateCACert. Consider removing one to avoid redundancy.

Also applies to: 77-82

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common_test.go` around lines 43 - 48,
Two tests duplicate the same scenario by calling ValidateCACert with nil (test
names "nil CA cert to use system CAs" and "nil cert pool"); remove one of the
duplicate cases (either the t.Run block using "nil CA cert to use system CAs" or
the "nil cert pool" block) and keep a single clearly named test for the nil-CA
behavior (e.g., "nil CA cert uses system CAs") to avoid redundancy; ensure the
remaining test continues to call ValidateCACert(testServer.URL, nil) and asserts
an error as before.

91-108: ⚡ Quick win

Test with 6-second sleep may slow CI.

The "well-known request error" test waits 6 seconds for a timeout. Since ValidateCACert has a 5-second client timeout and 10-second retry context, consider reducing the sleep or using a handler that closes the connection immediately to speed up tests.

Alternative: close connection immediately
 	t.Run("well-known request error", func(t *testing.T) {
-		handlerFunc := func(w http.ResponseWriter, r *http.Request) {
-			time.Sleep(6 * time.Second)
-			w.WriteHeader(http.StatusOK)
-		}
+		handlerFunc := func(w http.ResponseWriter, r *http.Request) {
+			// Hijack and close connection to simulate network error
+			hj, ok := w.(http.Hijacker)
+			if ok {
+				conn, _, _ := hj.Hijack()
+				conn.Close()
+			}
+		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common_test.go` around lines 91 -
108, The "well-known request error" test uses a 6s sleep in handlerFunc which
slows CI; update the handler in this test (the closure used to createTestServer)
to either close the connection immediately (e.g., by calling Hijack/Close on the
ResponseWriter) or use a much shorter sleep well below the client timeout (e.g.,
500–1000ms) so ValidateCACert still triggers its error path without waiting 6
seconds; change the handlerFunc in this test accordingly and keep the test name
and call to ValidateCACert unchanged.
pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go (1)

149-239: ⚖️ Poor tradeoff

Consider extracting shared test helpers to reduce duplication.

The createTestServer, generateCAKeyPair, generateServingCert, and authConfigWithUpdates functions are duplicated across multiple test files (common_test.go, kubeapiserver/validation/validator_test.go, and this file). Consider extracting to a shared testutil package.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`
around lines 149 - 239, Extract the duplicated test helpers createTestServer,
generateCAKeyPair, generateServingCert, and authConfigWithUpdates into a shared
testutil package: create a new pkg/.../testutil package (or internal testutil)
containing these functions, update their package names/visibility if needed,
replace the local copies in common_test.go,
kubeapiserver/validation/validator_test.go and this file to import testutil and
call testutil.createTestServer / testutil.generateCAKeyPair /
testutil.generateServingCert / testutil.authConfigWithUpdates, and run/update
imports and any references to types (e.g., change unexported identifiers to
exported if cross-package usage requires it) so all tests compile and use the
single shared helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controllers/externaloidc/generation/common.go`:
- Around line 42-47: The custom Proxy func currently calls
httpproxy.FromEnvironment().HTTPSProxy which ignores NO_PROXY; replace that
lambda with the standard http.ProxyFromEnvironment function so proxy resolution
respects NO_PROXY and other env rules. Locate the Proxy: func(*http.Request)
(*url.URL, error) block in common.go and assign http.ProxyFromEnvironment (or
return its result) instead of manually calling httpproxy.FromEnvironment and
url.Parse, ensuring the Proxy field uses the http.ProxyFromEnvironment handler.
- Around line 60-65: The retry loop creates retryCtx but still calls
client.Do(req) with the original request context, so in-flight requests won't be
cancelled when the 10s timeout expires; update the call inside the
retry.RetryOnConnectionErrors closure to use a request bound to retryCtx (e.g.,
clone or call req.WithContext/retryCtx to produce reqWithCtx) and call
client.Do(reqWithCtx) instead of client.Do(req), keeping the existing cancel()
defer as-is.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go`:
- Around line 667-676: In generateExternalClaimsSourceTLS, validate that
externalSourceTLS.CertificateAuthority is non-nil and that
externalSourceTLS.CertificateAuthority.Name is not empty before calling
getCertificateAuthorityFromConfigMap; if missing, return a clear error (e.g.,
"missing certificate authority name for external source") instead of attempting
a ConfigMap lookup with an empty name so callers get a descriptive failure;
reference the function generateExternalClaimsSourceTLS and the helper
getCertificateAuthorityFromConfigMap and use cmLister only after the name check.

---

Nitpick comments:
In `@pkg/controllers/externaloidc/generation/common_test.go`:
- Around line 43-48: Two tests duplicate the same scenario by calling
ValidateCACert with nil (test names "nil CA cert to use system CAs" and "nil
cert pool"); remove one of the duplicate cases (either the t.Run block using
"nil CA cert to use system CAs" or the "nil cert pool" block) and keep a single
clearly named test for the nil-CA behavior (e.g., "nil CA cert uses system CAs")
to avoid redundancy; ensure the remaining test continues to call
ValidateCACert(testServer.URL, nil) and asserts an error as before.
- Around line 91-108: The "well-known request error" test uses a 6s sleep in
handlerFunc which slows CI; update the handler in this test (the closure used to
createTestServer) to either close the connection immediately (e.g., by calling
Hijack/Close on the ResponseWriter) or use a much shorter sleep well below the
client timeout (e.g., 500–1000ms) so ValidateCACert still triggers its error
path without waiting 6 seconds; change the handlerFunc in this test accordingly
and keep the test name and call to ValidateCACert unchanged.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go`:
- Around line 1789-1790: The test directly assigns the private validator field
(c.validator) on the object returned by NewAuthenticationConfigurationGenerator;
instead, add a public option or setter to inject the validator (e.g., implement
a WithValidator functional option or a SetValidator method on
AuthenticationConfigurationGenerator) and update
NewAuthenticationConfigurationGenerator to accept options or expose the setter,
then change tests to use NewAuthenticationConfigurationGenerator(...,
WithValidator(tt.configValidator)) or c.SetValidator(tt.configValidator) and
remove direct field assignment.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go`:
- Line 578: The declared variable printableASCIIRegexp in generate.go is unused;
either remove the declaration or document why it remains (e.g., add a comment
stating it is reserved for future validation) so linters won't flag it. Locate
the regexp variable named printableASCIIRegexp and either delete that line or
replace it with a short explanatory comment referencing its intended use in
future validation logic (e.g., for username/label printable-ASCII checks).

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`:
- Around line 149-239: Extract the duplicated test helpers createTestServer,
generateCAKeyPair, generateServingCert, and authConfigWithUpdates into a shared
testutil package: create a new pkg/.../testutil package (or internal testutil)
containing these functions, update their package names/visibility if needed,
replace the local copies in common_test.go,
kubeapiserver/validation/validator_test.go and this file to import testutil and
call testutil.createTestServer / testutil.generateCAKeyPair /
testutil.generateServingCert / testutil.authConfigWithUpdates, and run/update
imports and any references to types (e.g., change unexported identifiers to
exported if cross-package usage requires it) so all tests compile and use the
single shared helpers.
🪄 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: 282d5019-9d77-476a-9a3d-5b7916ce231a

📥 Commits

Reviewing files that changed from the base of the PR and between 834e097 and 7438b6f.

⛔ Files ignored due to path filters (89)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/xform.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/types.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/github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/.golangci.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_apiserver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_authentication.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_dns.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_infrastructure.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_kmsencryption.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1alpha1/types_cluster_monitoring.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/envtest-releases.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/install.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/types_pacemakercluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/etcd/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/etcd/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/etcd/v1alpha1/types_pacemakercluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/etcd/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/features.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/features/features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/machine/v1beta1/types_machineset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/types_ingress.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/types_network.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_20_kube-apiserver_01_kubeapiservers.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-CustomNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_csi-driver_01_clustercsidrivers-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-CustomNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-CustomNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-Default.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-DevPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-OKD.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_network_01_networks-TechPreviewNoUpgrade.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1alpha1/types_clusterapi.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/quota/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/quota/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/quota/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/security/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/security/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/security/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/security/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yq.mk is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.conversion.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (14)
  • go.mod
  • pkg/controllers/externaloidc/externaloidc_controller.go
  • pkg/controllers/externaloidc/externaloidc_controller_test.go
  • pkg/controllers/externaloidc/generation/common.go
  • pkg/controllers/externaloidc/generation/common_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/externaloidc_controller_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go
  • pkg/controllers/externaloidc/externaloidc_controller.go

Comment on lines +42 to +47
Proxy: func(*http.Request) (*url.URL, error) {
if proxyConfig := httpproxy.FromEnvironment(); len(proxyConfig.HTTPSProxy) > 0 {
return url.Parse(proxyConfig.HTTPSProxy)
}
return nil, nil
},
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

Custom proxy function ignores NO_PROXY environment variable.

The manual httpproxy.FromEnvironment().HTTPSProxy lookup bypasses the standard http.ProxyFromEnvironment behavior that respects NO_PROXY. This can cause issues in environments where certain hosts should bypass the proxy.

Proposed fix
 	client := &http.Client{
 		Transport: &http.Transport{
 			TLSClientConfig: &tls.Config{RootCAs: caCertPool},
-			Proxy: func(*http.Request) (*url.URL, error) {
-				if proxyConfig := httpproxy.FromEnvironment(); len(proxyConfig.HTTPSProxy) > 0 {
-					return url.Parse(proxyConfig.HTTPSProxy)
-				}
-				return nil, nil
-			},
+			Proxy: http.ProxyFromEnvironment,
 		},
 		Timeout: 5 * time.Second,
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common.go` around lines 42 - 47, The
custom Proxy func currently calls httpproxy.FromEnvironment().HTTPSProxy which
ignores NO_PROXY; replace that lambda with the standard
http.ProxyFromEnvironment function so proxy resolution respects NO_PROXY and
other env rules. Locate the Proxy: func(*http.Request) (*url.URL, error) block
in common.go and assign http.ProxyFromEnvironment (or return its result) instead
of manually calling httpproxy.FromEnvironment and url.Parse, ensuring the Proxy
field uses the http.ProxyFromEnvironment handler.

Comment on lines +60 to +65
retryCtx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
defer cancel()
retry.RetryOnConnectionErrors(retryCtx, func(ctx context.Context) (done bool, err error) {
resp, connErr = client.Do(req)
return connErr == nil, connErr
})
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

Retry context not attached to requests, so in-flight requests won't be cancelled.

The retryCtx controls the retry loop's deadline but client.Do(req) uses the original request without context. This means an in-flight request won't be cancelled when the 10-second deadline expires.

Proposed fix
 	var resp *http.Response
 	var connErr error
 	retryCtx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
 	defer cancel()
 	retry.RetryOnConnectionErrors(retryCtx, func(ctx context.Context) (done bool, err error) {
-		resp, connErr = client.Do(req)
+		resp, connErr = client.Do(req.Clone(ctx))
 		return connErr == nil, connErr
 	})
📝 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
retryCtx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
defer cancel()
retry.RetryOnConnectionErrors(retryCtx, func(ctx context.Context) (done bool, err error) {
resp, connErr = client.Do(req)
return connErr == nil, connErr
})
retryCtx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
defer cancel()
retry.RetryOnConnectionErrors(retryCtx, func(ctx context.Context) (done bool, err error) {
resp, connErr = client.Do(req.Clone(ctx))
return connErr == nil, connErr
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common.go` around lines 60 - 65, The
retry loop creates retryCtx but still calls client.Do(req) with the original
request context, so in-flight requests won't be cancelled when the 10s timeout
expires; update the call inside the retry.RetryOnConnectionErrors closure to use
a request bound to retryCtx (e.g., clone or call req.WithContext/retryCtx to
produce reqWithCtx) and call client.Do(reqWithCtx) instead of client.Do(req),
keeping the existing cancel() defer as-is.

Comment on lines +667 to +676
func generateExternalClaimsSourceTLS(externalSourceTLS configv1.ExternalSourceTLS, cmLister corev1listers.ConfigMapLister) (*authenticationv1alpha1.TLS, error) {
caData, err := getCertificateAuthorityFromConfigMap(externalSourceTLS.CertificateAuthority.Name, cmLister)
if err != nil {
return nil, fmt.Errorf("getting certificate authority for external source: %w", err)
}

return &authenticationv1alpha1.TLS{
CertificateAuthority: &caData,
}, nil
}
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 | 🟡 Minor | ⚡ Quick win

Missing nil check for externalSourceTLS.CertificateAuthority.Name.

If CertificateAuthority.Name is empty, this will attempt to look up a ConfigMap with an empty name, which will fail with a confusing error. Consider validating that the name is provided.

Proposed fix
 func generateExternalClaimsSourceTLS(externalSourceTLS configv1.ExternalSourceTLS, cmLister corev1listers.ConfigMapLister) (*authenticationv1alpha1.TLS, error) {
+	if len(externalSourceTLS.CertificateAuthority.Name) == 0 {
+		return nil, fmt.Errorf("external source TLS certificate authority name is required")
+	}
 	caData, err := getCertificateAuthorityFromConfigMap(externalSourceTLS.CertificateAuthority.Name, cmLister)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/oauthapiserver/generate.go` around
lines 667 - 676, In generateExternalClaimsSourceTLS, validate that
externalSourceTLS.CertificateAuthority is non-nil and that
externalSourceTLS.CertificateAuthority.Name is not empty before calling
getCertificateAuthorityFromConfigMap; if missing, return a clear error (e.g.,
"missing certificate authority name for external source") instead of attempting
a ConfigMap lookup with an empty name so callers get a descriptive failure;
reference the function generateExternalClaimsSourceTLS and the helper
getCertificateAuthorityFromConfigMap and use cmLister only after the name check.

@everettraven everettraven force-pushed the feature/ext-claims-impl branch from 7438b6f to 76f1602 Compare May 8, 2026 17:13
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 8, 2026
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

🧹 Nitpick comments (2)
pkg/controllers/externaloidc/generation/common_test.go (1)

43-48: 💤 Low value

Duplicate test cases for nil cert pool.

The test cases "nil CA cert to use system CAs" (line 43) and "nil cert pool" (line 77) both pass nil to ValidateCACert and expect an error. Consider consolidating them into a single test case or differentiating their purpose.

Also applies to: 77-82

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common_test.go` around lines 43 - 48,
The two duplicate tests both pass nil to ValidateCACert ("nil CA cert to use
system CAs" and "nil cert pool")—consolidate them into a single test or make
their intent distinct; update the test suite by removing one of the duplicated
t.Run blocks and keeping a single case that calls ValidateCACert(testServer.URL,
nil) and asserts an error, or rename and change one test to exercise a different
scenario (e.g., an empty x509.CertPool vs. nil) so both ValidateCACert and the
test names clearly reflect unique behaviors; ensure the unique identifiers
ValidateCACert and the t.Run names are adjusted accordingly.
pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go (1)

149-239: ⚖️ Poor tradeoff

Consider extracting shared test helpers to reduce duplication.

The helper functions createTestServer, generateCAKeyPair, and generateServingCert are duplicated across pkg/controllers/externaloidc/generation/common_test.go, this file, and kubeapiserver/validation/validator_test.go. Consider extracting them into a shared testutil package under the generation directory.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`
around lines 149 - 239, Extract the duplicated helpers createTestServer,
generateCAKeyPair, and generateServingCert into a shared test helper package
(e.g., generation/testutil); move the implementations from this file and the
other locations into that package, export them if needed, update callers in
pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go,
pkg/controllers/externaloidc/generation/common_test.go and
kubeapiserver/validation/validator_test.go to import the new testutil package
and call testutil.CreateTestServer, testutil.GenerateCAKeyPair, and
testutil.GenerateServingCert, and remove the now-duplicate local definitions so
all tests use the single shared implementation.
🤖 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 `@go.mod`:
- Line 19: Replace the all-zero sentinel pseudo-version in go.mod for module
github.com/openshift/oauth-apiserver with the valid pseudo-version provided;
locate the line containing "github.com/openshift/oauth-apiserver
v0.0.0-00010101000000-000000000000" and change that version to
"v0.0.0-20260430140618-160ac7fb4ea6c0d5" so the module resolves without the
local replace directive.

In `@pkg/controllers/externaloidc/generation/common.go`:
- Around line 39-50: The TLS config used to create the HTTP client in the
http.Client/http.Transport setup (see tls.Config initialized with RootCAs:
caCertPool) needs a minimum TLS version; update the tls.Config in the Transport
to include MinVersion: tls.VersionTLS12 so the OIDC certificate validation
enforces TLS 1.2+.

---

Nitpick comments:
In `@pkg/controllers/externaloidc/generation/common_test.go`:
- Around line 43-48: The two duplicate tests both pass nil to ValidateCACert
("nil CA cert to use system CAs" and "nil cert pool")—consolidate them into a
single test or make their intent distinct; update the test suite by removing one
of the duplicated t.Run blocks and keeping a single case that calls
ValidateCACert(testServer.URL, nil) and asserts an error, or rename and change
one test to exercise a different scenario (e.g., an empty x509.CertPool vs. nil)
so both ValidateCACert and the test names clearly reflect unique behaviors;
ensure the unique identifiers ValidateCACert and the t.Run names are adjusted
accordingly.

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`:
- Around line 149-239: Extract the duplicated helpers createTestServer,
generateCAKeyPair, and generateServingCert into a shared test helper package
(e.g., generation/testutil); move the implementations from this file and the
other locations into that package, export them if needed, update callers in
pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go,
pkg/controllers/externaloidc/generation/common_test.go and
kubeapiserver/validation/validator_test.go to import the new testutil package
and call testutil.CreateTestServer, testutil.GenerateCAKeyPair, and
testutil.GenerateServingCert, and remove the now-duplicate local definitions so
all tests use the single shared implementation.
🪄 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: 45c6e8a9-3a74-47f1-8efe-8cb145dafac5

📥 Commits

Reviewing files that changed from the base of the PR and between 7438b6f and 76f1602.

⛔ Files ignored due to path filters (29)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/xform.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/types.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/github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_authentication.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yq.mk is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.conversion.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (14)
  • go.mod
  • pkg/controllers/externaloidc/externaloidc_controller.go
  • pkg/controllers/externaloidc/externaloidc_controller_test.go
  • pkg/controllers/externaloidc/generation/common.go
  • pkg/controllers/externaloidc/generation/common_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate.go
  • pkg/controllers/externaloidc/externaloidc_controller_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go
  • pkg/controllers/externaloidc/externaloidc_controller.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go

Comment thread go.mod Outdated
Comment on lines +39 to +50
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: caCertPool},
Proxy: func(*http.Request) (*url.URL, error) {
if proxyConfig := httpproxy.FromEnvironment(); len(proxyConfig.HTTPSProxy) > 0 {
return url.Parse(proxyConfig.HTTPSProxy)
}
return nil, nil
},
},
Timeout: 5 * time.Second,
}
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 | 🟡 Minor | ⚡ Quick win

Add MinVersion: tls.VersionTLS12 to the TLS configuration.

The TLS config lacks a MinVersion setting. In production code validating OIDC provider certificates, enforcing a minimum TLS version (at least TLS 1.2) is a security best practice to prevent downgrade attacks.

🔒 Proposed fix
 	client := &http.Client{
 		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{RootCAs: caCertPool},
+			TLSClientConfig: &tls.Config{
+				RootCAs:    caCertPool,
+				MinVersion: tls.VersionTLS12,
+			},
 			Proxy: func(*http.Request) (*url.URL, error) {
📝 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
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: caCertPool},
Proxy: func(*http.Request) (*url.URL, error) {
if proxyConfig := httpproxy.FromEnvironment(); len(proxyConfig.HTTPSProxy) > 0 {
return url.Parse(proxyConfig.HTTPSProxy)
}
return nil, nil
},
},
Timeout: 5 * time.Second,
}
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
MinVersion: tls.VersionTLS12,
},
Proxy: func(*http.Request) (*url.URL, error) {
if proxyConfig := httpproxy.FromEnvironment(); len(proxyConfig.HTTPSProxy) > 0 {
return url.Parse(proxyConfig.HTTPSProxy)
}
return nil, nil
},
},
Timeout: 5 * time.Second,
}
🧰 Tools
🪛 ast-grep (0.42.1)

[warning] 40-40: MinVersionis missing from this TLS configuration. By default, TLS 1.2 is currently used as the minimum when acting as a client, and TLS 1.0 when acting as a server. General purpose web applications should default to TLS 1.3 with all other protocols disabled. Only where it is known that a web server must support legacy clients with unsupported an insecure browsers (such as Internet Explorer 10), it may be necessary to enable TLS 1.0 to provide support. AddMinVersion: tls.VersionTLS13' to the TLS configuration to bump the minimum version to TLS 1.3.
Context: tls.Config{RootCAs: caCertPool}
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
https://owasp.org/Top10/A02_2021-Cryptographic_Failures

(missing-ssl-minversion-go)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common.go` around lines 39 - 50, The
TLS config used to create the HTTP client in the http.Client/http.Transport
setup (see tls.Config initialized with RootCAs: caCertPool) needs a minimum TLS
version; update the tls.Config in the Transport to include MinVersion:
tls.VersionTLS12 so the OIDC certificate validation enforces TLS 1.2+.

@everettraven everettraven force-pushed the feature/ext-claims-impl branch from 76f1602 to f786628 Compare May 11, 2026 18:22
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.

♻️ Duplicate comments (2)
pkg/controllers/externaloidc/generation/common.go (2)

39-50: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add MinVersion: tls.VersionTLS12 to the TLS configuration and use http.ProxyFromEnvironment.

The TLS configuration lacks a minimum version setting, and the custom proxy function bypasses NO_PROXY environment variable handling. These issues were flagged in previous reviews and by static analysis.

🔒 Proposed fix
 	client := &http.Client{
 		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{RootCAs: caCertPool},
-			Proxy: func(*http.Request) (*url.URL, error) {
-				if proxyConfig := httpproxy.FromEnvironment(); len(proxyConfig.HTTPSProxy) > 0 {
-					return url.Parse(proxyConfig.HTTPSProxy)
-				}
-				return nil, nil
-			},
+			TLSClientConfig: &tls.Config{
+				RootCAs:    caCertPool,
+				MinVersion: tls.VersionTLS12,
+			},
+			Proxy: http.ProxyFromEnvironment,
 		},
 		Timeout: 5 * time.Second,
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common.go` around lines 39 - 50, The
TLS config for the http client (constructed as client := &http.Client{
Transport: &http.Transport{ TLSClientConfig: &tls.Config{RootCAs: caCertPool},
Proxy: func... }}) should enforce a minimum TLS version and delegate proxy
resolution to the stdlib; update the tls.Config used in the Transport to include
MinVersion: tls.VersionTLS12 and replace the custom Proxy func with Proxy:
http.ProxyFromEnvironment so NO_PROXY/NOHTTP/NOHTTPS semantics are respected.

58-68: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Attach retry context to the request so in-flight requests are cancelled on timeout.

The retryCtx controls the retry loop but client.Do(req) uses the original request context. In-flight requests won't be cancelled when the 10-second deadline expires.

🐛 Proposed fix
 	var resp *http.Response
 	var connErr error
 	retryCtx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
 	defer cancel()
 	retry.RetryOnConnectionErrors(retryCtx, func(ctx context.Context) (done bool, err error) {
-		resp, connErr = client.Do(req)
+		resp, connErr = client.Do(req.Clone(ctx))
 		return connErr == nil, connErr
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common.go` around lines 58 - 68, The
retry loop uses retryCtx but client.Do(req) still uses the original request
context; update the request to carry retryCtx so in-flight HTTP calls are
cancelled on timeout. Create a contextualized request (e.g., reqWithCtx :=
req.WithContext(retryCtx) or req.Clone(retryCtx)) and call client.Do(reqWithCtx)
inside the RetryOnConnectionErrors callback (or recreate per-attempt if needed)
so RetryOnConnectionErrors, client.Do, retryCtx, resp and connErr continue to
work with the 10s deadline.
🧹 Nitpick comments (3)
pkg/controllers/externaloidc/generation/common_test.go (1)

70-75: 💤 Low value

Variable shadowing: err is reassigned but the original outer-scope error is not rechecked.

At line 71, err is reassigned from ValidateCACert, but the outer-scope err from generateCAKeyPair at line 58 is not re-verified before the check at line 64. While this works because the generateCAKeyPair error path returns early at line 60-61, the shadowing could cause confusion.

Consider using a different variable name or restructuring:

♻️ Proposed fix
 	t.Run("mismatched CA cert", func(t *testing.T) {
 		anotherCACert, _, err := generateCAKeyPair()
 		if err != nil {
 			t.Errorf("could not generate CA keypair: %v", err)
 		}
 		certPool := x509.NewCertPool()
 		certPool.AddCert(anotherCACert)
-		err = ValidateCACert(testServer.URL, certPool)
+		validateErr := ValidateCACert(testServer.URL, certPool)
-		if err == nil {
+		if validateErr == nil {
 			t.Errorf("did not get an error while expecting one")
 		}
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/generation/common_test.go` around lines 70 - 75,
The test shadows the outer err from generateCAKeyPair by reassigning err inside
the t.Run closure when calling ValidateCACert, which is confusing; update the
test so the ValidateCACert call uses a new local variable name (e.g., vErr or
validateErr) or explicitly reuse the outer err in a clear way to avoid
shadowing, ensuring generateCAKeyPair's returned error remains distinct and
still handled; update references in the closure accordingly (look for
generateCAKeyPair, ValidateCACert, and the err variable in the t.Run "unknown
URL" block).
pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go (1)

149-239: ⚖️ Poor tradeoff

Consider extracting shared test helpers to reduce duplication.

The createTestServer, generateCAKeyPair, and generateServingCert functions are duplicated across multiple test files. Consider extracting these to a shared test utilities package (e.g., pkg/controllers/externaloidc/testutil/) to improve maintainability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`
around lines 149 - 239, Extract the duplicated helpers createTestServer,
generateCAKeyPair, and generateServingCert into a shared test utility package
(e.g., pkg/controllers/externaloidc/testutil) and export them (rename to
CreateTestServer, GenerateCAKeyPair, GenerateServingCert) so other test packages
can import and reuse them; move their implementations into a new .go file under
that package, update all test files that currently define those functions to
import the new testutil package and call the exported names, and run `go test
./...` to ensure imports and signatures match.
pkg/controllers/externaloidc/externaloidc_controller_test.go (1)

472-532: 💤 Low value

Remove unused helper functions to reduce code duplication.

The generateCAKeyPair and generateServingCert helper functions are not called in this test file. These functions are already defined and actively used in common_test.go and validator_test.go, making the copies here redundant. Removing them will reduce maintenance burden.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/externaloidc/externaloidc_controller_test.go` around lines
472 - 532, Delete the unused helper functions generateCAKeyPair and
generateServingCert from this test file (they're duplicates of implementations
in common_test.go / validator_test.go); remove any now-unused imports that only
supported these functions and run tests/build to verify nothing else references
them.
🤖 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.

Duplicate comments:
In `@pkg/controllers/externaloidc/generation/common.go`:
- Around line 39-50: The TLS config for the http client (constructed as client
:= &http.Client{ Transport: &http.Transport{ TLSClientConfig:
&tls.Config{RootCAs: caCertPool}, Proxy: func... }}) should enforce a minimum
TLS version and delegate proxy resolution to the stdlib; update the tls.Config
used in the Transport to include MinVersion: tls.VersionTLS12 and replace the
custom Proxy func with Proxy: http.ProxyFromEnvironment so
NO_PROXY/NOHTTP/NOHTTPS semantics are respected.
- Around line 58-68: The retry loop uses retryCtx but client.Do(req) still uses
the original request context; update the request to carry retryCtx so in-flight
HTTP calls are cancelled on timeout. Create a contextualized request (e.g.,
reqWithCtx := req.WithContext(retryCtx) or req.Clone(retryCtx)) and call
client.Do(reqWithCtx) inside the RetryOnConnectionErrors callback (or recreate
per-attempt if needed) so RetryOnConnectionErrors, client.Do, retryCtx, resp and
connErr continue to work with the 10s deadline.

---

Nitpick comments:
In `@pkg/controllers/externaloidc/externaloidc_controller_test.go`:
- Around line 472-532: Delete the unused helper functions generateCAKeyPair and
generateServingCert from this test file (they're duplicates of implementations
in common_test.go / validator_test.go); remove any now-unused imports that only
supported these functions and run tests/build to verify nothing else references
them.

In `@pkg/controllers/externaloidc/generation/common_test.go`:
- Around line 70-75: The test shadows the outer err from generateCAKeyPair by
reassigning err inside the t.Run closure when calling ValidateCACert, which is
confusing; update the test so the ValidateCACert call uses a new local variable
name (e.g., vErr or validateErr) or explicitly reuse the outer err in a clear
way to avoid shadowing, ensuring generateCAKeyPair's returned error remains
distinct and still handled; update references in the closure accordingly (look
for generateCAKeyPair, ValidateCACert, and the err variable in the t.Run
"unknown URL" block).

In
`@pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go`:
- Around line 149-239: Extract the duplicated helpers createTestServer,
generateCAKeyPair, and generateServingCert into a shared test utility package
(e.g., pkg/controllers/externaloidc/testutil) and export them (rename to
CreateTestServer, GenerateCAKeyPair, GenerateServingCert) so other test packages
can import and reuse them; move their implementations into a new .go file under
that package, update all test files that currently define those functions to
import the new testutil package and call the exported names, and run `go test
./...` to ensure imports and signatures match.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: ddf5b43b-3cca-4043-aeb6-3bc9656989fa

📥 Commits

Reviewing files that changed from the base of the PR and between 76f1602 and f786628.

⛔ Files ignored due to path filters (29)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/go-cmp/cmp/cmpopts/xform.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/types.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/github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/types_authentication.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/build-machinery-go/make/targets/openshift/yq.mk is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.conversion.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/oauth-apiserver/pkg/externaloidc/apis/authentication/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (14)
  • go.mod
  • pkg/controllers/externaloidc/externaloidc_controller.go
  • pkg/controllers/externaloidc/externaloidc_controller_test.go
  • pkg/controllers/externaloidc/generation/common.go
  • pkg/controllers/externaloidc/generation/common_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator_test.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/controllers/externaloidc/generation/kubeapiserver/doc.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • pkg/controllers/externaloidc/generation/oauthapiserver/validation/validator.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/validation/validator.go
  • pkg/controllers/externaloidc/externaloidc_controller.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate.go
  • pkg/controllers/externaloidc/generation/oauthapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate_test.go
  • pkg/controllers/externaloidc/generation/kubeapiserver/generate.go

…ion generation

Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
…rate package

Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
@everettraven everettraven force-pushed the feature/ext-claims-impl branch from f786628 to 8d4a671 Compare May 14, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants