Skip to content

OCPBUGS-86025: Close HTTP response bodies to prevent goroutine and connection leaks#8560

Open
vismishr wants to merge 1 commit into
openshift:mainfrom
vismishr:OCPBUGS-86025/fix-http-body-close
Open

OCPBUGS-86025: Close HTTP response bodies to prevent goroutine and connection leaks#8560
vismishr wants to merge 1 commit into
openshift:mainfrom
vismishr:OCPBUGS-86025/fix-http-body-close

Conversation

@vismishr
Copy link
Copy Markdown
Contributor

@vismishr vismishr commented May 20, 2026

What this PR does / why we need it:

Adds defer resp.Body.Close() to healthCheckKASEndpoint and explicit resp.Body.Close() on error paths in the two CONNECT tunnel dialers, where HTTP response bodies are not closed after use. Without closing, each unclosed response leaks ~3 goroutines and holds an open TCP connection. In healthCheckKASEndpoint (called from the HCP reconcile loop every ~10s), this accumulates ~26,000 leaked goroutines/day and ~200MB memory/day, potentially causing CPO pods to OOM on long-running management clusters.

Files changed:

  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.gohealthCheckKASEndpoint
  • support/konnectivityproxy/dialer.goKonnectivityDialer.DialContext
  • support/konnectivityproxy/proxy_dialer.gohttpProxyDialer.Dial

All three were identified via the bodyclose linter (golangci-lint).

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/OCPBUGS-86025

Special notes for your reviewer:

  • healthCheckKASEndpoint: uses defer resp.Body.Close() — standard pattern for a regular HTTP GET.
  • The two konnectivity dialers use explicit resp.Body.Close() on error paths only. These are CONNECT tunnels where the response body is the tunnel connection — a defer would close the tunnel on the success return path.

Checklist:

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

Summary by CodeRabbit

  • Bug Fixes
    • Fixed HTTP response body leaks in health check monitoring operations to prevent resource exhaustion.
    • Fixed HTTP response body leaks in proxy connection handling during error scenarios to ensure proper resource cleanup.

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

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

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

This repository is configured in: LGTM mode

@openshift-ci 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 20, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 20, 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 openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels May 20, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@vismishr: This pull request references Jira Issue OCPBUGS-86025, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

What this PR does / why we need it:

Adds defer resp.Body.Close() to three locations where HTTP response bodies are not closed after use. Without closing, each unclosed response leaks ~3 goroutines and holds an open TCP connection. In healthCheckKASEndpoint (called from the HCP reconcile loop every ~10s), this accumulates ~26,000 leaked goroutines/day and ~200MB memory/day, potentially causing CPO pods to OOM on long-running management clusters.

Files changed:

  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.gohealthCheckKASEndpoint
  • support/konnectivityproxy/dialer.goKonnectivityDialer.DialContext
  • support/konnectivityproxy/proxy_dialer.gohttpProxyDialer.Dial

All three were identified via the bodyclose linter (golangci-lint).

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/OCPBUGS-86025

Special notes for your reviewer:

Each fix is a single defer resp.Body.Close() line added after the HTTP error check, per Go net/http documentation: "The caller should close resp.Body when done reading from it." No behavioral changes — response handling remains identical.

Checklist:

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

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: ffa1eddb-83ae-45a6-a955-070034bcb963

📥 Commits

Reviewing files that changed from the base of the PR and between d86f3d4 and 0a73668.

📒 Files selected for processing (3)
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • support/konnectivityproxy/dialer.go
  • support/konnectivityproxy/proxy_dialer.go

📝 Walkthrough

Walkthrough

This PR adds three explicit closes for HTTP response bodies: a deferred resp.Body.Close() in healthCheckKASEndpoint, closes of res.Body in konnectivityProxy.DialContext for non-200 CONNECT responses and when buffered data is present, and a close of resp.Body in httpProxyDialer.Dial on non-200 CONNECT responses. Each close is performed immediately on the applicable success or error path to avoid leaking response streams.

🚥 Pre-merge checks | ✅ 11 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main change: adding HTTP response body closes to prevent resource leaks, which directly matches the core objective and all three files modified in the changeset.
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 PR contains no Ginkgo tests. It only modifies source code (hostedcontrolplane_controller.go, dialer.go, proxy_dialer.go) to add HTTP response body closes; check is inapplicable.
Test Structure And Quality ✅ Passed The PR modifies source files to close HTTP response bodies and includes unit tests, but these tests use standard Go testing, not Ginkgo. The custom check applies only to Ginkgo tests.
Microshift Test Compatibility ✅ Passed PR fixes HTTP response body closes in production code only. No new Ginkgo e2e tests added, so MicroShift compatibility check does not apply.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests added. PR contains only bugfix changes to HTTP response body closes in source files. Check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed PR adds only HTTP response body cleanup in Go source files; no deployment manifests, scheduling constraints, affinity rules, replicas, nodeSelectors, or topology logic introduced.
Ote Binary Stdout Contract ✅ Passed PR only adds http.Response.Body.Close() resource cleanup calls; introduces no stdout writes, logging, or changes to main/init/suite functions that could violate the OTE contract.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR adds no new Ginkgo e2e tests; only production code bug fixes for HTTP body closing. Check is not applicable.

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

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@openshift-ci openshift-ci Bot added area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release and removed do-not-merge/needs-area labels May 20, 2026
@vismishr vismishr force-pushed the OCPBUGS-86025/fix-http-body-close branch from 5180fc9 to 70a9e42 Compare May 20, 2026 19:27
@vismishr vismishr marked this pull request as ready for review May 20, 2026 19:30
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 20, 2026
@openshift-ci openshift-ci Bot requested review from muraee and sdminonne May 20, 2026 19:32
@openshift-ci-robot
Copy link
Copy Markdown

@vismishr: This pull request references Jira Issue OCPBUGS-86025, which is invalid:

  • expected the bug to target only the "5.0.0" version, but multiple target versions were set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

Details

In response to this:

What this PR does / why we need it:

Adds defer resp.Body.Close() to three locations where HTTP response bodies are not closed after use. Without closing, each unclosed response leaks ~3 goroutines and holds an open TCP connection. In healthCheckKASEndpoint (called from the HCP reconcile loop every ~10s), this accumulates ~26,000 leaked goroutines/day and ~200MB memory/day, potentially causing CPO pods to OOM on long-running management clusters.

Files changed:

  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.gohealthCheckKASEndpoint
  • support/konnectivityproxy/dialer.goKonnectivityDialer.DialContext
  • support/konnectivityproxy/proxy_dialer.gohttpProxyDialer.Dial

All three were identified via the bodyclose linter (golangci-lint).

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/OCPBUGS-86025

Special notes for your reviewer:

Each fix is a single defer resp.Body.Close() line added after the HTTP error check, per Go net/http documentation: "The caller should close resp.Body when done reading from it." No behavioral changes — response handling remains identical.

Checklist:

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

Summary by CodeRabbit

  • Bug Fixes
  • Fixed resource leak in health-check logic by ensuring HTTP responses are properly closed.
  • Fixed resource leaks in Konnectivity proxy to prevent leftover response bodies after network operations.
  • Fixed resource leak in HTTP proxy handling to avoid connection exhaustion and improve long-running reliability.

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.

@vismishr
Copy link
Copy Markdown
Contributor Author

/jira refresh

@openshift-ci-robot
Copy link
Copy Markdown

@vismishr: This pull request references Jira Issue OCPBUGS-86025, which is invalid:

  • expected the bug to target only the "5.0.0" version, but multiple target versions were set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

Details

In response to this:

/jira refresh

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.

@vismishr
Copy link
Copy Markdown
Contributor Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added the jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. label May 20, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@vismishr: This pull request references Jira Issue OCPBUGS-86025, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

/jira refresh

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-robot openshift-ci-robot removed the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label May 20, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 40.34%. Comparing base (d86f3d4) to head (0a73668).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
support/konnectivityproxy/dialer.go 0.00% 2 Missing ⚠️
...ostedcontrolplane/hostedcontrolplane_controller.go 0.00% 1 Missing ⚠️
support/konnectivityproxy/proxy_dialer.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8560      +/-   ##
==========================================
- Coverage   40.34%   40.34%   -0.01%     
==========================================
  Files         755      755              
  Lines       93167    93172       +5     
==========================================
  Hits        37587    37587              
- Misses      52877    52882       +5     
  Partials     2703     2703              
Files with missing lines Coverage Δ
...ostedcontrolplane/hostedcontrolplane_controller.go 44.98% <0.00%> (-0.04%) ⬇️
support/konnectivityproxy/proxy_dialer.go 0.00% <0.00%> (ø)
support/konnectivityproxy/dialer.go 25.46% <0.00%> (-0.20%) ⬇️
Flag Coverage Δ
cmd-support 34.30% <0.00%> (-0.01%) ⬇️
cpo-hostedcontrolplane 41.76% <0.00%> (-0.01%) ⬇️
cpo-other 40.14% <ø> (ø)
hypershift-operator 50.72% <ø> (ø)
other 31.54% <ø> (ø)

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

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

Copy link
Copy Markdown
Contributor

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

Caution

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

⚠️ Outside diff range comments (2)
support/konnectivityproxy/proxy_dialer.go (1)

62-69: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Avoid deferred body close when returning a successful CONNECT tunnel.

At line 62, defer resp.Body.Close() executes before returning the connection on status 200, which can interfere with the tunnel. Instead, explicitly close the body only in the error path (non-200 status).

💡 Proposed fix
 	resp, err := http.ReadResponse(br, connectReq)
 	if err != nil {
 		conn.Close()
 		return nil, err
 	}
-	defer resp.Body.Close()
 
 	if resp.StatusCode != 200 {
+		_ = resp.Body.Close()
 		conn.Close()
 		f := strings.SplitN(resp.Status, " ", 2)
 		return nil, errors.New(f[1])
 	}
 	return conn, nil
🤖 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 `@support/konnectivityproxy/proxy_dialer.go` around lines 62 - 69, Remove the
deferred resp.Body.Close() that runs before returning a successful CONNECT
tunnel; instead only close resp.Body in the non-200 error path where you also
call conn.Close(). In the function handling the CONNECT response (the code
around defer resp.Body.Close(), resp.StatusCode check, conn.Close(), and return
statements), delete the defer and explicitly call resp.Body.Close() inside the
if resp.StatusCode != 200 block before returning the error so the body is not
closed when returning conn on success.
support/konnectivityproxy/dialer.go (1)

329-344: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove unconditional defer of response body close on the CONNECT success path.

At line 335, defer res.Body.Close() closes the tunnel connection before the function returns konnectivityConnection at line 351. In HTTP CONNECT tunnels, the response body is the tunnel itself. Close the body only on non-200 and error paths; on success, return the connection without deferring the close.

💡 Proposed fix
 	res, err := http.ReadResponse(br, nil)
 	if err != nil {
 		_ = konnectivityConnection.Close()
 		return nil, fmt.Errorf("reading HTTP response from CONNECT to %s via proxy %s failed: %v",
 			requestAddress, konnectivityServerAddress, err)
 	}
-	defer res.Body.Close()
 	if res.StatusCode != 200 {
+		_ = res.Body.Close()
 		log.Info("Status code was not 200", "statusCode", res.StatusCode)
 		_ = konnectivityConnection.Close()
 		return nil, fmt.Errorf("proxy error from %s while dialing %s: %v", konnectivityServerAddress, requestAddress, res.Status)
 	}
🤖 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 `@support/konnectivityproxy/dialer.go` around lines 329 - 344, Remove the
unconditional defer res.Body.Close() at the start of the CONNECT handling; the
response body is the tunnel and must remain open on success. Instead, call
res.Body.Close() explicitly on all error paths before returning (e.g., when
res.StatusCode != 200 in the block that logs and returns an error referencing
konnectivityServerAddress/requestAddress, and when br.Buffered() > 0 before
returning the buffered-data error), and ensure the successful return of
konnectivityConnection does not close res.Body. Keep references to
konnectivityConnection, res, res.StatusCode, res.Status, br.Buffered(),
requestAddress and konnectivityServerAddress so the fixes are applied to the
correct places.
🤖 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.

Outside diff comments:
In `@support/konnectivityproxy/dialer.go`:
- Around line 329-344: Remove the unconditional defer res.Body.Close() at the
start of the CONNECT handling; the response body is the tunnel and must remain
open on success. Instead, call res.Body.Close() explicitly on all error paths
before returning (e.g., when res.StatusCode != 200 in the block that logs and
returns an error referencing konnectivityServerAddress/requestAddress, and when
br.Buffered() > 0 before returning the buffered-data error), and ensure the
successful return of konnectivityConnection does not close res.Body. Keep
references to konnectivityConnection, res, res.StatusCode, res.Status,
br.Buffered(), requestAddress and konnectivityServerAddress so the fixes are
applied to the correct places.

In `@support/konnectivityproxy/proxy_dialer.go`:
- Around line 62-69: Remove the deferred resp.Body.Close() that runs before
returning a successful CONNECT tunnel; instead only close resp.Body in the
non-200 error path where you also call conn.Close(). In the function handling
the CONNECT response (the code around defer resp.Body.Close(), resp.StatusCode
check, conn.Close(), and return statements), delete the defer and explicitly
call resp.Body.Close() inside the if resp.StatusCode != 200 block before
returning the error so the body is not closed when returning conn on success.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 3edace4b-06b4-4418-8092-d287468205b3

📥 Commits

Reviewing files that changed from the base of the PR and between 5180fc9 and 70a9e42.

📒 Files selected for processing (3)
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • support/konnectivityproxy/dialer.go
  • support/konnectivityproxy/proxy_dialer.go

…eaks

Commit-Message-Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
@vismishr vismishr force-pushed the OCPBUGS-86025/fix-http-body-close branch from 70a9e42 to 0a73668 Compare May 20, 2026 19:39
@openshift-ci-robot
Copy link
Copy Markdown

@vismishr: This pull request references Jira Issue OCPBUGS-86025, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

What this PR does / why we need it:

Adds defer resp.Body.Close() to three locations where HTTP response bodies are not closed after use. Without closing, each unclosed response leaks ~3 goroutines and holds an open TCP connection. In healthCheckKASEndpoint (called from the HCP reconcile loop every ~10s), this accumulates ~26,000 leaked goroutines/day and ~200MB memory/day, potentially causing CPO pods to OOM on long-running management clusters.

Files changed:

  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.gohealthCheckKASEndpoint
  • support/konnectivityproxy/dialer.goKonnectivityDialer.DialContext
  • support/konnectivityproxy/proxy_dialer.gohttpProxyDialer.Dial

All three were identified via the bodyclose linter (golangci-lint).

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/OCPBUGS-86025

Special notes for your reviewer:

Each fix is a single defer resp.Body.Close() line added after the HTTP error check, per Go net/http documentation: "The caller should close resp.Body when done reading from it." No behavioral changes — response handling remains identical.

Checklist:

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

Summary by CodeRabbit

  • Bug Fixes
  • Ensured HTTP responses are always closed during health checks to prevent resource leaks.
  • Closed response bodies in the Konnectivity proxy error paths to avoid leftover open streams.
  • Closed CONNECT responses in the HTTP proxy flow on failure to prevent connection exhaustion and improve reliability.

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.

@vismishr
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

✅ Actions performed

Full review triggered.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 20, 2026

@vismishr: 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.

@vismishr
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

✅ Actions performed

Full review triggered.

@muraee
Copy link
Copy Markdown
Contributor

muraee commented May 21, 2026

/approve

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 21, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: muraee, vismishr

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 May 21, 2026
@hypershift-jira-solve-ci
Copy link
Copy Markdown

I now have all the information needed for a complete analysis. Here is the final report:

Test Failure Analysis Complete

Job Information

  • Prow Job: codecov/patch (Codecov coverage gate, not a Prow CI job)
  • Build ID: GitHub Check Run 77140021007
  • PR: openshift/hypershift#8560
  • Target: main branch

Test Failure Analysis

Error

codecov/patch: 0.00% of diff hit (target 40.34%)
Patch coverage is 0% with 4 lines in your changes missing coverage.

Summary

The codecov/patch check failed because zero of the 4 new lines added by this PR are exercised by the existing unit test suite. The PR adds resp.Body.Close() calls in error-handling and post-response code paths across three files (hostedcontrolplane_controller.go, dialer.go, proxy_dialer.go). These code paths involve live HTTP connections (konnectivity proxy CONNECT tunnels, KAS health checks) and have no existing unit test coverage — the files proxy_dialer.go (0.00% overall) and dialer.go (25.46% overall) are largely untested. This is a coverage gate failure, not a product bug or test regression. The sibling check codecov/project passed because overall project coverage (40.34%) is unaffected.

Root Cause

The codecov/patch check requires that new or modified lines in a PR are covered by unit tests. This PR adds 4 lines — all resp.Body.Close() / res.Body.Close() calls — and none are hit during testing:

  1. hostedcontrolplane_controller.go (line ~1004): defer resp.Body.Close() added inside healthCheckKASEndpoint(), which makes a real http.Get() to a KAS ingress endpoint. No unit test mocks or exercises this function.

  2. dialer.go (lines ~331, ~338): Two res.Body.Close() calls added in konnectivityProxy.DialContext() error paths — one for non-200 CONNECT response, one for unexpected buffered data. The DialContext method establishes real konnectivity tunnel connections and its error paths are not unit-tested (file is at 25.46% coverage).

  3. proxy_dialer.go (line ~62): resp.Body.Close() added in httpProxyDialer.Dial() for non-200 CONNECT response. This file has 0.00% coverage — no unit tests exist for it at all.

All four lines are in code paths that handle live network connections (HTTP CONNECT proxying, KAS health endpoints), which are inherently difficult to unit test without mocking the network layer. The PR is a correct resource-leak fix — the codecov/patch failure is a false positive for this type of change.

Recommendations
  1. This failure is safe to override/ignore. The codecov/patch check is not a required status check for merge in this repository (branch protection rules don't enforce it). The sibling codecov/project check passed, confirming no regression in overall coverage.

  2. Proceed with merge. The changes are correct defensive-programming fixes (closing HTTP response bodies to prevent goroutine/connection leaks). Adding unit tests solely to satisfy the patch coverage gate would require mocking the entire konnectivity proxy and KAS health-check network stack, which is disproportionate effort for single-line Close() calls.

  3. If coverage is desired long-term, consider adding integration-style tests with httptest.Server for healthCheckKASEndpoint() and mock CONNECT proxy responses for DialContext() / Dial() — but this is a separate improvement, not a prerequisite for this bugfix.

Evidence
Evidence Detail
Check conclusion failure0.00% of diff hit (target 40.34%)
Lines missing coverage 4 lines across 3 files
proxy_dialer.go file coverage 0.00% — no unit tests exist for this file
dialer.go file coverage 25.46% — error paths in DialContext are untested
hostedcontrolplane_controller.go file coverage 44.98%healthCheckKASEndpoint is untested
codecov/project check Passed — overall project coverage unchanged at 40.34%
Codecov config (codecov.yml) No explicit patch threshold defined — uses Codecov default
Branch protection codecov/patch is not a required status check for merge
Nature of changes All 4 lines are resp.Body.Close() calls in error/post-response paths

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. 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