Skip to content

CNTRLPLANE-3423: TLS config tests for console-operator - #31436

Open
kaleemsiddiqu wants to merge 1 commit into
openshift:mainfrom
kaleemsiddiqu:pr-console-operator-1196
Open

CNTRLPLANE-3423: TLS config tests for console-operator#31436
kaleemsiddiqu wants to merge 1 commit into
openshift:mainfrom
kaleemsiddiqu:pr-console-operator-1196

Conversation

@kaleemsiddiqu

@kaleemsiddiqu kaleemsiddiqu commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

e2e tests for openshift/console-operator#1196

Summary by CodeRabbit

  • Tests
    • Added coverage verifying that console TLS settings match the cluster’s configured TLS security profile.
    • Added validation of console route behavior across TLS 1.2 and TLS 1.3 settings.
    • Added checks for TLS profile transitions between Intermediate and Modern modes, including restoration to the original configuration.

Signed-off-by: Kaleemullah Siddiqui <ksiddiqu@redhat.com>
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

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

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

This repository is configured in: automatic mode

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

openshift-ci-robot commented Jul 27, 2026

Copy link
Copy Markdown

@kaleemsiddiqu: This pull request references CNTRLPLANE-3423 which is a valid jira issue.

Details

In response to this:

e2e tests for openshift/console-operator#1196

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

@openshift-ci

openshift-ci Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: kaleemsiddiqu

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

The pull request process is described here

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

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

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

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Walkthrough

Added console-operator TLS observed-configuration tests and disruptive console-route checks covering Intermediate and Modern TLS profiles, with helpers for route target discovery, TLS dialing, reconciliation polling, and profile restoration.

Changes

Console operator TLS validation

Layer / File(s) Summary
Console TLS test scenarios
test/extended/tls/tls_observed_config.go
Adds Serial suites validating console servingInfo against the APIServer TLS profile and testing console-route TLS 1.2/TLS 1.3 behavior across profile changes.
Console route TLS polling helpers
test/extended/tls/tls_observed_config.go
Adds console route target discovery, fixed-version TLS dialing, and polling until expected TLS behavior is observed.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant APIServer
  participant console-operator
  participant ConsoleRouteTLSClient
  APIServer->>console-operator: Update tlsSecurityProfile
  console-operator->>ConsoleRouteTLSClient: Reconcile console route TLS settings
  ConsoleRouteTLSClient->>APIServer: Test TLS 1.2 and TLS 1.3 behavior
Loading

Suggested reviewers: ingvagabund


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error The new console-operator tests log consoleHost in success/error paths, exposing the cluster's console route hostname in CI logs. Redact or omit the hostname from e2e.Logf/errors in testConsoleRouteTLS and the setup log; keep only a generic label or masked host.
Test Structure And Quality ⚠️ Warning The disruptive console-route It has a 60m outer timeout but a 105m worst-case wait budget, so it can self-cancel mid-flow. Raise the outer [Timeout] and context to at least 105m (e.g. 120m), or reduce the per-step waits so the worst case fits inside the budget.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main change: adding console-operator TLS configuration tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All Ginkgo titles in the changed file are literal static strings; no dynamic data, generated IDs, or changing values appear in test names.
Microshift Test Compatibility ✅ Passed PASS: The new console-operator suites touch openshift-console/config.openshift.io resources, but both are wrapped in g.BeforeAll with exutil.IsMicroShiftCluster() g.Skip guards.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The new console TLS tests only change API server TLS and probe the console route/config; they don’t count nodes or schedule across hosts.
Topology-Aware Scheduling Compatibility ✅ Passed PR only adds TLS e2e tests in test/extended/tls/tls_observed_config.go; no manifests, replicas, nodeSelectors, affinities, or PDBs were introduced.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes found: the new test file has no init/TestMain/BeforeSuite/RunSpecs writes, and its logs use framework.Logf/GinkgoWriter.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed New console route tests use cluster-internal route host and net.JoinHostPort; no hardcoded IPv4 or public internet dependencies found.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret/token comparisons were added; only strong TLS 1.2/1.3 ciphers appear.
Container-Privileges ✅ Passed Only changed file is a Go test; no container/K8s manifests or privilege flags (privileged, hostPID/Network/IPC, allowPrivilegeEscalation, SYS_ADMIN) were added.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
test/extended/tls/tls_observed_config.go (4)

2008-2042: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

InsecureSkipVerify: true flagged by static analysis — confirm intent and document it.

Both OpenGrep and ast-grep flag InsecureSkipVerify: true here as a MITM risk (CWE-295). This mirrors the pre-existing pattern in captureTLSConfiguration (Lines 1393-1400) used elsewhere in this file, and appears intentional: the test only validates TLS protocol-version negotiation against the console route, not certificate identity, and the connection is torn down immediately. Given two SAST tools flag it, consider adding a short inline comment stating this rationale to prevent future confusion and repeated tool noise.

💡 Suggested clarifying comment
 	tlsConf := &tls.Config{
 		MinVersion:         tlsVersion,
 		MaxVersion:         tlsVersion,
+		// Cert identity is not under test here; only TLS version
+		// negotiation with the console route is being validated.
 		InsecureSkipVerify: true,
 		ServerName:         host,
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/extended/tls/tls_observed_config.go` around lines 2008 - 2042, Add a
concise inline comment next to InsecureSkipVerify in testConsoleRouteTLS
explaining that certificate verification is intentionally disabled because this
test only validates TLS protocol-version negotiation, matching the existing
captureTLSConfiguration pattern.

695-709: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse consoleTLSTargets.observedConfig[0] instead of duplicating the target.

This constructs a newObservedConfigTarget with identical parameters to the one already defined in consoleTLSTargets (Lines 2002-2006). Keeping two hand-written copies risks silent drift if one is updated without the other, making one of the tests validate the wrong resource without failing loudly.

♻️ Proposed fix
-		target := newObservedConfigTarget(
-			"openshift-console-operator",
-			gvr("operator.openshift.io", "v1", "consoles"),
-			"cluster",
-			[]string{"servingInfo"},
-		)
+		target := consoleTLSTargets.observedConfig[0]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/extended/tls/tls_observed_config.go` around lines 695 - 709, Update the
TLS test in the “should have TLS entries in the Console operator observedConfig”
case to reuse consoleTLSTargets.observedConfig[0] for the target passed to
testTLS, removing the duplicate newObservedConfigTarget construction while
preserving the existing expected configuration and assertion.

1999-2006: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate target definition — see the linked comment at Lines 695-709.

consoleTLSTargets duplicates the exact same newObservedConfigTarget call constructed independently in the "should have TLS entries in the Console operator observedConfig" test. Consider having that test source its target from here instead.

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

In `@test/extended/tls/tls_observed_config.go` around lines 1999 - 2006, Reuse the
target defined in consoleTLSTargets within the “should have TLS entries in the
Console operator observedConfig” test instead of constructing another identical
newObservedConfigTarget call. Keep the test behavior unchanged while making
consoleTLSTargets the single source of truth for this observedConfig target.

2044-2062: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Surface the last dial error when the poll times out.

On timeout, wait.PollUntilContextTimeout returns a generic deadline-exceeded error, discarding the last testConsoleRouteTLS failure captured inside the closure (Lines 2055-2059). When this test fails in CI, the reported error won't say whether the connection kept succeeding, kept failing, or hit a network error — only that it "timed out," making triage harder.

♻️ Proposed fix
 func waitForConsoleRouteTLSState(host string, tlsVersion uint16, shouldSucceed bool, ctx context.Context) error {
 	versionName := tlsVersionName(tlsVersion)
 	expected := "succeed"
 	if !shouldSucceed {
 		expected = "be rejected"
 	}
 
-	return wait.PollUntilContextTimeout(ctx, 10*time.Second, 5*time.Minute, true,
+	var lastErr error
+	err := wait.PollUntilContextTimeout(ctx, 10*time.Second, 5*time.Minute, true,
 		func(ctx context.Context) (bool, error) {
-			err := testConsoleRouteTLS(host, tlsVersion, shouldSucceed)
-			if err != nil {
-				e2e.Logf("Console route TLS %s should %s but: %v (retrying)", versionName, expected, err)
+			lastErr = testConsoleRouteTLS(host, tlsVersion, shouldSucceed)
+			if lastErr != nil {
+				e2e.Logf("Console route TLS %s should %s but: %v (retrying)", versionName, expected, lastErr)
 				return false, nil
 			}
 			return true, nil
 		})
+	if err != nil && lastErr != nil {
+		return fmt.Errorf("%w: last error: %v", err, lastErr)
+	}
+	return err
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/extended/tls/tls_observed_config.go` around lines 2044 - 2062, The
waitForConsoleRouteTLSState polling closure currently logs but discards the last
testConsoleRouteTLS failure when polling times out. Capture the most recent
error outside the closure, update it on each failed attempt, and after
wait.PollUntilContextTimeout returns an error, return a wrapped error that
includes the last dial failure while preserving the original polling error;
retain the existing success behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/extended/tls/tls_observed_config.go`:
- Around line 752-832: Increase the test’s outer timeout in the TLS profile
change test to cover the additive worst-case waits from waitForTLSReconciliation
and waitForConsoleRouteTLSState, updating both the context duration and the
[Timeout:60m] annotation to 120 minutes. Preserve the existing reconciliation
and route verification steps.

---

Nitpick comments:
In `@test/extended/tls/tls_observed_config.go`:
- Around line 2008-2042: Add a concise inline comment next to InsecureSkipVerify
in testConsoleRouteTLS explaining that certificate verification is intentionally
disabled because this test only validates TLS protocol-version negotiation,
matching the existing captureTLSConfiguration pattern.
- Around line 695-709: Update the TLS test in the “should have TLS entries in
the Console operator observedConfig” case to reuse
consoleTLSTargets.observedConfig[0] for the target passed to testTLS, removing
the duplicate newObservedConfigTarget construction while preserving the existing
expected configuration and assertion.
- Around line 1999-2006: Reuse the target defined in consoleTLSTargets within
the “should have TLS entries in the Console operator observedConfig” test
instead of constructing another identical newObservedConfigTarget call. Keep the
test behavior unchanged while making consoleTLSTargets the single source of
truth for this observedConfig target.
- Around line 2044-2062: The waitForConsoleRouteTLSState polling closure
currently logs but discards the last testConsoleRouteTLS failure when polling
times out. Capture the most recent error outside the closure, update it on each
failed attempt, and after wait.PollUntilContextTimeout returns an error, return
a wrapped error that includes the last dial failure while preserving the
original polling error; retain the existing success behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 323503f5-f2da-495c-b635-b8715af8ea38

📥 Commits

Reviewing files that changed from the base of the PR and between 621e171 and f7c166b.

📒 Files selected for processing (1)
  • test/extended/tls/tls_observed_config.go

Comment on lines +752 to +832
g.It("should enforce TLS versions through console route across profile changes [Timeout:60m]", func() {
configChangeCtx, configChangeCancel := context.WithTimeout(ctx, 60*time.Minute)
defer configChangeCancel()

g.By("getting console route hostname")
routeGVR := schema.GroupVersionResource{Group: "route.openshift.io", Version: "v1", Resource: "routes"}
route, err := oc.AdminDynamicClient().Resource(routeGVR).Namespace("openshift-console").Get(configChangeCtx, "console", metav1.GetOptions{})
o.Expect(err).NotTo(o.HaveOccurred(), "failed to get console route")
consoleHost, found, err := unstructured.NestedString(route.Object, "spec", "host")
o.Expect(err).NotTo(o.HaveOccurred())
o.Expect(found).To(o.BeTrue(), "console route should have spec.host")
e2e.Logf("Console route hostname: %s", consoleHost)

g.By("saving original TLS profile for restoration")
originalAPIServer, err := oc.AdminConfigClient().ConfigV1().APIServers().Get(configChangeCtx, "cluster", metav1.GetOptions{})
o.Expect(err).NotTo(o.HaveOccurred())
originalProfile := originalAPIServer.Spec.TLSSecurityProfile

defer func() {
g.By("restoring original TLS profile")
setAPIServerTLSProfile(oc, ctx, originalProfile, "original")
if err := waitForTLSReconciliation(oc, ctx, false, consoleTLSTargets, captureTLSConfiguration(originalProfile)); err != nil {
e2e.Logf("Warning: console TLS reconciliation during cleanup: %v", err)
}
}()

// Step 1: Set Intermediate profile and verify both TLS 1.2 and TLS 1.3 work
g.By("setting TLS profile to Intermediate")
intermediateProfile := &configv1.TLSSecurityProfile{
Type: configv1.TLSProfileIntermediateType,
Intermediate: &configv1.IntermediateTLSProfile{},
}
setAPIServerTLSProfile(oc, configChangeCtx, intermediateProfile, "Intermediate")
intermediateTLSConfig := captureTLSConfiguration(intermediateProfile)
err = waitForTLSReconciliation(oc, configChangeCtx, false, consoleTLSTargets, intermediateTLSConfig)
o.Expect(err).NotTo(o.HaveOccurred(), "console operator should reconcile to Intermediate profile")

g.By("verifying TLS 1.2 works with Intermediate profile")
err = waitForConsoleRouteTLSState(consoleHost, tls.VersionTLS12, true, configChangeCtx)
o.Expect(err).NotTo(o.HaveOccurred(), "TLS 1.2 should work with Intermediate profile")

g.By("verifying TLS 1.3 works with Intermediate profile")
err = waitForConsoleRouteTLSState(consoleHost, tls.VersionTLS13, true, configChangeCtx)
o.Expect(err).NotTo(o.HaveOccurred(), "TLS 1.3 should work with Intermediate profile")

// Step 2: Switch to Modern profile — only TLS 1.3 should work
g.By("switching to Modern TLS profile")
modernProfile := &configv1.TLSSecurityProfile{
Type: configv1.TLSProfileModernType,
Modern: &configv1.ModernTLSProfile{},
}
setAPIServerTLSProfile(oc, configChangeCtx, modernProfile, "Modern")
modernTLSConfig := captureTLSConfiguration(modernProfile)
err = waitForTLSReconciliation(oc, configChangeCtx, false, consoleTLSTargets, modernTLSConfig)
o.Expect(err).NotTo(o.HaveOccurred(), "console operator should reconcile to Modern profile")

g.By("verifying TLS 1.3 works with Modern profile")
err = waitForConsoleRouteTLSState(consoleHost, tls.VersionTLS13, true, configChangeCtx)
o.Expect(err).NotTo(o.HaveOccurred(), "TLS 1.3 should work with Modern profile")

g.By("verifying TLS 1.2 is rejected with Modern profile")
err = waitForConsoleRouteTLSState(consoleHost, tls.VersionTLS12, false, configChangeCtx)
o.Expect(err).NotTo(o.HaveOccurred(), "TLS 1.2 should be rejected with Modern profile")

// Step 3: Switch back to Intermediate — both TLS 1.2 and 1.3 should work again
g.By("switching back to Intermediate TLS profile")
setAPIServerTLSProfile(oc, configChangeCtx, intermediateProfile, "Intermediate")
err = waitForTLSReconciliation(oc, configChangeCtx, false, consoleTLSTargets, intermediateTLSConfig)
o.Expect(err).NotTo(o.HaveOccurred(), "console operator should reconcile back to Intermediate profile")

g.By("verifying TLS 1.2 works after downgrade to Intermediate")
err = waitForConsoleRouteTLSState(consoleHost, tls.VersionTLS12, true, configChangeCtx)
o.Expect(err).NotTo(o.HaveOccurred(), "TLS 1.2 should work after downgrade to Intermediate")

g.By("verifying TLS 1.3 works after downgrade to Intermediate")
err = waitForConsoleRouteTLSState(consoleHost, tls.VersionTLS13, true, configChangeCtx)
o.Expect(err).NotTo(o.HaveOccurred(), "TLS 1.3 should work after downgrade to Intermediate")

e2e.Logf("=== Console operator TLS profile change validation complete ===")
})
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Outer 60m timeout can't cover the worst-case additive wait budget.

The test wraps everything in a 60-minute configChangeCtx (Line 753) and is tagged [Timeout:60m], but it makes 3 calls to waitForTLSReconciliation (25m timeout each, Line 1566) and 6 calls to waitForConsoleRouteTLSState (5m timeout each, Line 2053) — a worst-case total of 105 minutes. Under slow reconciliation (plausible in CI), the outer context will cancel mid-step, producing a misleading "reconciliation timeout after 25m0s" failure that actually stems from the outer 60m budget being exhausted early, rather than genuine reconciliation failure.

Increase the outer timeout (and the [Timeout:60m] annotation) to comfortably cover the worst case, e.g. 120m, or reduce the per-call timeouts.

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

In `@test/extended/tls/tls_observed_config.go` around lines 752 - 832, Increase
the test’s outer timeout in the TLS profile change test to cover the additive
worst-case waits from waitForTLSReconciliation and waitForConsoleRouteTLSState,
updating both the context duration and the [Timeout:60m] annotation to 120
minutes. Preserve the existing reconciliation and route verification steps.

@openshift-ci

openshift-ci Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@kaleemsiddiqu: all tests passed!

Full PR test history. Your PR dashboard.

Details

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

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants