Skip to content

OCPBUGS-55621: Replace konnectivity Dial with DialContext in konnectivity-https-proxy/cmd.go#8550

Open
PoornimaSingour wants to merge 3 commits into
openshift:mainfrom
PoornimaSingour:DialwithDialContext
Open

OCPBUGS-55621: Replace konnectivity Dial with DialContext in konnectivity-https-proxy/cmd.go#8550
PoornimaSingour wants to merge 3 commits into
openshift:mainfrom
PoornimaSingour:DialwithDialContext

Conversation

@PoornimaSingour

@PoornimaSingour PoornimaSingour commented May 20, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

Replacing deprecated Dial with DialContext in konnectivity-https-proxy/cmd.go so that golangci-lint passes without needing nolint suppressions.
If we uncomment nolint in cmd.go its giving below error:

konnectivity-https-proxy/cmd.go uses the deprecated Dial field on http.Transport (deprecated since Go 1.7) instead of DialContext. A // nolint:staticcheck comment on line 182 suppresses the lint warning.

Which issue(s) this PR fixes:

Fixes ---> https://redhat.atlassian.net/browse/OCPBUGS-55621

Special notes for your reviewer:

Checklist:

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

Summary by CodeRabbit

  • Improvements

    • HTTPS proxy connection handling now uses context-aware networking, improving support for request timeouts and cancellations.
    • Dialing behavior updated to rely on modern connection APIs for cleaner lifecycle management and more reliable setup/teardown.
  • Tests

    • Added unit tests validating direct vs. proxy dialing selection, successful direct dialing, and correct propagation of dialing errors.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

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

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

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added jira/severity-low Referenced Jira bug's severity is low for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. labels May 20, 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 20, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@PoornimaSingour: This pull request references Jira Issue OCPBUGS-55621, which is invalid:

  • expected the bug to target either version "5.0." or "openshift-5.0.", but it targets "4.20.z" instead

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:

Replacing deprecated Dial with DialContext in konnectivity-https-proxy/cmd.go so that golangci-lint passes without needing nolint suppressions.
If we uncomment nolint in cmd.go its giving below error:

konnectivity-https-proxy/cmd.go uses the deprecated Dial field on http.Transport (deprecated since Go 1.7) instead of DialContext. A // nolint:staticcheck comment on line 182 suppresses the lint warning.

Which issue(s) this PR fixes:

Fixes ---> https://redhat.atlassian.net/browse/OCPBUGS-55621

Special notes for your reviewer:

Checklist:

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

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

openshift-ci Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

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

openshift-ci Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: PoornimaSingour
Once this PR has been reviewed and has the lgtm label, please assign muraee 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 added area/documentation Indicates the PR includes changes for documentation and removed do-not-merge/needs-area labels May 20, 2026
@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR replaces deprecated transport Dial usage with context-aware DialContext. It adds a context import, updates the HTTP transport wiring to use konnectivityDialer.DialContext, and changes the direct-dial wrapper to call httpProxy.Tr.DialContext with context.Background().

🚥 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 title accurately and specifically describes the main change: replacing the deprecated Dial with DialContext in konnectivity-https-proxy/cmd.go, which is the primary purpose of this PR.
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 Tests use standard Go testing with t.Run(), not Ginkgo. Ginkgo check is not applicable to this PR. All t.Run() subtest names are static and descriptive with no dynamic values.
Test Structure And Quality ✅ Passed Tests added (TestDialDirectFunc, TestConnectDialFunc) use standard Go testing with *testing.T, not Ginkgo DSL; custom check applies only to Ginkgo tests.
Microshift Test Compatibility ✅ Passed The PR adds standard Go unit tests (TestDialDirectFunc, TestConnectDialFunc) using the testing package and Gomega assertion library, not Ginkgo e2e tests. The custom check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests added. PR adds standard Go unit tests using *testing.T, not Ginkgo patterns (It/Describe/Context). Check applies only to Ginkgo e2e tests.
Topology-Aware Scheduling Compatibility ✅ Passed PR modifies only konnectivity-https-proxy networking code (replacing deprecated Dial with DialContext). No deployment manifests, scheduling constraints, or topology assumptions are introduced.
Ote Binary Stdout Contract ✅ Passed PR changes only internal dialing logic and tests. No process-level stdout writes found: errors use os.Stderr, logger defaults to os.Stderr per controller-runtime.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The new test functions TestDialDirectFunc and TestConnectDialFunc are standard Go unit tests, not Ginkgo e2e tests. The check applies only to Ginkgo e2e tests, so it 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
konnectivity-https-proxy/cmd.go (1)

184-189: 💤 Low value

Context parameter is discarded in proxy dial function due to goproxy API limitation.

The dialThroughProxyFunc wrapper correctly maps the context-aware signature but NewConnectDialToProxyWithHandler returns a function without context support, so request cancellation and timeouts won't affect proxy connection establishment. This is a limitation of goproxy's convenience API, not a regression—dialDirectFunc properly handles context via httpProxy.Tr.DialContext.

Improving this would require either using a different goproxy mechanism or implementing a custom proxy dialer with context awareness, which may not be worth the complexity for this use 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 `@konnectivity-https-proxy/cmd.go` around lines 184 - 189, dialThroughProxyFunc
discards the incoming context because goproxy.NewConnectDialToProxyWithHandler
returns a non‑context dialer; update dialThroughProxyFunc to document this
limitation and point to the alternative used elsewhere: mention that
dialDirectFunc uses httpProxy.Tr.DialContext for context-aware dialing, and note
that making proxy dialing context-aware would require replacing
NewConnectDialToProxyWithHandler with a custom dialer or different goproxy
mechanism; keep the wrapper as-is but add a clear comment in the
dialThroughProxyFunc body referencing NewConnectDialToProxyWithHandler,
dialDirectFunc, and the reason for not implementing a context-aware proxy
dialer.
🤖 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 `@docs/content/how-to/automated-machine-management/nodepool-lifecycle.md`:
- Around line 89-99: The example uses a fenced YAML block but the repo requires
indented code blocks (markdownlint MD046); replace the fenced block with an
indented code block by removing the triple backticks and indenting each YAML
line (e.g., the lines starting with "apiVersion:
hypershift.openshift.io/v1beta1" and "kind: NodePool" through "# ...other
fields...") by four spaces so the NodePool example is rendered as an indented
code block in nodepool-lifecycle.md.

---

Nitpick comments:
In `@konnectivity-https-proxy/cmd.go`:
- Around line 184-189: dialThroughProxyFunc discards the incoming context
because goproxy.NewConnectDialToProxyWithHandler returns a non‑context dialer;
update dialThroughProxyFunc to document this limitation and point to the
alternative used elsewhere: mention that dialDirectFunc uses
httpProxy.Tr.DialContext for context-aware dialing, and note that making proxy
dialing context-aware would require replacing NewConnectDialToProxyWithHandler
with a custom dialer or different goproxy mechanism; keep the wrapper as-is but
add a clear comment in the dialThroughProxyFunc body referencing
NewConnectDialToProxyWithHandler, dialDirectFunc, and the reason for not
implementing a context-aware proxy dialer.
🪄 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: a140c514-9429-49e2-9037-a4ca9b0206eb

📥 Commits

Reviewing files that changed from the base of the PR and between 9e283ae and d61d5d8.

⛔ Files ignored due to path filters (1)
  • docs/content/reference/aggregated-docs.md is excluded by !docs/content/reference/aggregated-docs.md
📒 Files selected for processing (2)
  • docs/content/how-to/automated-machine-management/nodepool-lifecycle.md
  • konnectivity-https-proxy/cmd.go

Comment thread docs/content/how-to/automated-machine-management/nodepool-lifecycle.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@konnectivity-https-proxy/cmd.go`:
- Around line 185-188: The current dialThroughProxyFunc wrapper ignores the
passed context (it discards ctx and returns a func that calls dialFn(network,
addr)), breaking cancellation/timeouts; replace this with a context-aware
CONNECT dialer by using or implementing a DialContext-capable CONNECT function:
either swap httpProxy.NewConnectDialToProxyWithHandler for a library that
exposes DialContext (e.g., github.com/elastic/proxy-connect-dialer-go) and call
its DialContext with the incoming ctx, or implement a custom CONNECT handshake
inside dialThroughProxyFunc that performs dial + CONNECT while selecting on
ctx.Done() to cancel the operation; ensure you still add basic auth via
addBasicAuthHeader(proxyURLUser) and keep the returned signature func(ctx
context.Context, network, addr string) (net.Conn, error) so context cancellation
and timeouts propagate.
🪄 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: 62e90aab-65d5-498c-aab9-984b6d139230

📥 Commits

Reviewing files that changed from the base of the PR and between d61d5d8 and 48f1889.

📒 Files selected for processing (1)
  • konnectivity-https-proxy/cmd.go

Comment thread konnectivity-https-proxy/cmd.go Outdated
Comment on lines +185 to +188
dialFn := httpProxy.NewConnectDialToProxyWithHandler(proxyURL, addBasicAuthHeader(proxyURLUser))
return func(_ context.Context, network, addr string) (net.Conn, error) {
return dialFn(network, addr)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

❓ Verification inconclusive

In github.com/elazarl/goproxy v1.7.2, is there a context-aware alternative to NewConnectDialToProxyWithHandler (or a recommended pattern) to support context cancellation/timeouts during CONNECT proxy dialing?


In github.com/elazarl/goproxy v1.7.2, the NewConnectDialToProxyWithHandler function does not natively support context.Context for cancellation or timeouts during the CONNECT dialing phase [1]. The function signature returns a standard func(network, addr string) (net.Conn, error) [2][1], which lacks the context parameter required for modern Go cancellation patterns. To achieve context-aware dialing in goproxy, the recommended pattern is to manually assign a custom dialer to the ProxyHttpServer.ConnectDial field [3][4]. While goproxy evolved in later versions to support context-aware signatures (e.g., func(ctx context.Context, network string, addr string) (net.Conn, error)) [3][4], in v1.7.2, you can implement a wrapper that respects context by using a third-party library or a custom implementation that performs the CONNECT handshake while respecting ctx.Done() [5][6][7]. Recommended approach: 1. Do not use NewConnectDialToProxyWithHandler if context support is required. 2. Implement a custom dialer that satisfies the context.Context requirement. You can use libraries like github.com/elastic/proxy-connect-dialer-go [5][6] or github.com/vladvalkov/connectdial [7], which provide DialContext methods specifically designed for this purpose. 3. Assign this custom DialContext logic to the proxy.ConnectDial field of your ProxyHttpServer instance [3]. If you are able to upgrade, later versions of goproxy have improved support for context-aware dialing [3][4]. If you must remain on v1.7.2, you are effectively responsible for implementing the CONNECT handshake (sending the CONNECT request, reading the response, and handling the context) within your own custom dialer function [2][5].

Citations:


Script executed:

# Find the file and context
find . -type f -name "cmd.go" | grep -i konnectivity

Repository: openshift/hypershift


Repository: openshift/hypershift
Exit code: 0

stdout:

./konnectivity-https-proxy/cmd.go


Script executed:

# Search for goproxy imports and version
rg "github.com/elazarl/goproxy" --type go -A 2 -B 2

Repository: openshift/hypershift


Repository: openshift/hypershift
Exit code: 0

stdout:

vendor/github.com/elazarl/goproxy/doc.go-Example use cases:
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go:1. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-avgsize
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go-To measure the average size of an Html served in your site. One can ask
--
vendor/github.com/elazarl/goproxy/doc.go-request, it'll send a warning email.
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go:3. https://github.com/elazarl/goproxy/blob/master/examples/goproxy-httpdump/
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go-Generate a real traffic to your website by real users using through
vendor/github.com/elazarl/goproxy/doc.go-proxy. Record the traffic, and try it again for more real load testing.
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go:4. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-no-reddit-at-worktime
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go-Will allow browsing to reddit.com between 8:00am and 17:00pm
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go:5. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-jquery-version
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go-Will warn if multiple versions of jquery are used in the same domain.
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go:6. https://github.com/elazarl/goproxy/blob/master/examples/goproxy-upside-down-ternet/
vendor/github.com/elazarl/goproxy/doc.go-
vendor/github.com/elazarl/goproxy/doc.go-Modifies image files in an HTTP response via goproxy's image extension found in ext/.
--
vendor/github.com/elazarl/goproxy/https.go-	"sync/atomic"
vendor/github.com/elazarl/goproxy/https.go-
vendor/github.com/elazarl/goproxy/https.go:	"github.com/elazarl/goproxy/internal/http1parser"
vendor/github.com/elazarl/goproxy/https.go:	"github.com/elazarl/goproxy/internal/signer"
vendor/github.com/elazarl/goproxy/https.go-)
vendor/github.com/elazarl/goproxy/https.go-
--
konnectivity-https-proxy/cmd.go-	"sigs.k8s.io/controller-runtime/pkg/log/zap"
konnectivity-https-proxy/cmd.go-
konnectivity-https-proxy/cmd.go:	"github.com/elazarl/goproxy"
konnectivity-https-proxy/cmd.go-	"github.com/spf13/cobra"
konnectivity-https-proxy/cmd.go-	"go.uber.org/zap/zapcore"


Script executed:

# Check go.mod for goproxy version
cat go.mod | grep -i goproxy

Repository: openshift/hypershift


Repository: openshift/hypershift
Exit code: 0

stdout:

	github.com/elazarl/goproxy v1.7.2


Script executed:

# Examine the full function context around lines 185-188
fd "cmd.go" -p "*konnectivity*" --exec head -c 20000 {} \;

Repository: openshift/hypershift


Repository: openshift/hypershift
Exit code: 1

stderr:

[fd error]: Search path '*konnectivity*' is not a directory.
[fd error]: No valid search paths given.


Script executed:

cat -n ./konnectivity-https-proxy/cmd.go | head -200

Repository: openshift/hypershift


Repository: openshift/hypershift
Exit code: 0

stdout:

     1	package konnectivityhttpsproxy
     2	
     3	import (
     4		"context"
     5		"crypto/tls"
     6		"encoding/base64"
     7		"fmt"
     8		"net"
     9		"net/http"
    10		"net/url"
    11		"os"
    12	
    13		"github.com/openshift/hypershift/support/konnectivityproxy"
    14		"github.com/openshift/hypershift/support/netutil"
    15		"github.com/openshift/hypershift/support/supportedversion"
    16	
    17		"k8s.io/apimachinery/pkg/util/sets"
    18		"k8s.io/utils/ptr"
    19	
    20		ctrl "sigs.k8s.io/controller-runtime"
    21		"sigs.k8s.io/controller-runtime/pkg/client"
    22		"sigs.k8s.io/controller-runtime/pkg/log"
    23		"sigs.k8s.io/controller-runtime/pkg/log/zap"
    24	
    25		"github.com/elazarl/goproxy"
    26		"github.com/spf13/cobra"
    27		"go.uber.org/zap/zapcore"
    28		"golang.org/x/net/http/httpproxy"
    29	)
    30	
    31	func NewStartCommand() *cobra.Command {
    32		zLogger := zap.New(
    33			zap.JSONEncoder(func(o *zapcore.EncoderConfig) {
    34				o.EncodeTime = zapcore.RFC3339TimeEncoder
    35			}),
    36		)
    37		log.SetLogger(zLogger)
    38		l := log.Log.WithName("konnectivity-https-proxy")
    39		cmd := &cobra.Command{
    40			Use:   "konnectivity-https-proxy",
    41			Short: "Runs the konnectivity https proxy server.",
    42			Long: ` Runs the konnectivity https proxy server.
    43			This proxy accepts request and tunnels them through the designated Konnectivity Server.`,
    44		}
    45	
    46		opts := konnectivityproxy.Options{
    47			ResolveBeforeDial:          true,
    48			ResolveFromGuestClusterDNS: true,
    49		}
    50	
    51		var servingPort uint32
    52		var httpProxyURL string
    53		var httpsProxyURL string
    54		var noProxy string
    55	
    56		cmd.Flags().StringVar(&opts.KonnectivityHost, "konnectivity-hostname", "konnectivity-server-local", "The hostname of the konnectivity service.")
    57		cmd.Flags().Uint32Var(&opts.KonnectivityPort, "konnectivity-port", 8090, "The konnectivity port that https proxy should connect to.")
    58		cmd.Flags().Uint32Var(&servingPort, "serving-port", 8090, "The port that https proxy should serve on.")
    59	
    60		cmd.Flags().StringVar(&opts.CAFile, "ca-cert-path", "/etc/konnectivity/proxy-ca/ca.crt", "The path to the konnectivity client's ca-cert.")
    61		cmd.Flags().StringVar(&opts.ClientCertFile, "tls-cert-path", "/etc/konnectivity/proxy-client/tls.crt", "The path to the konnectivity client's tls certificate.")
    62		cmd.Flags().StringVar(&opts.ClientKeyFile, "tls-key-path", "/etc/konnectivity/proxy-client/tls.key", "The path to the konnectivity client's private key.")
    63	
    64		cmd.Flags().StringVar(&httpProxyURL, "http-proxy", "", "HTTP proxy to use on hosted cluster requests")
    65		cmd.Flags().StringVar(&httpsProxyURL, "https-proxy", "", "HTTPS proxy to use on hosted cluster requests")
    66		cmd.Flags().StringVar(&noProxy, "no-proxy", "", "URLs that should not use the provided http-proxy and https-proxy")
    67	
    68		cmd.Flags().BoolVar(&opts.ConnectDirectlyToCloudAPIs, "connect-directly-to-cloud-apis", false, "If true, bypass konnectivity to connect to cloud APIs while still honoring management proxy config")
    69	
    70		cmd.Run = func(cmd *cobra.Command, args []string) {
    71			l.Info("Starting proxy", "version", supportedversion.String())
    72			c, err := client.New(ctrl.GetConfigOrDie(), client.Options{})
    73			if err != nil {
    74				fmt.Fprintf(os.Stderr, "Error: failed to get kubernetes client: %v", err)
    75				os.Exit(1)
    76			}
    77			opts.Client = c
    78			opts.Log = l
    79	
    80			var proxyTLS *tls.Config
    81			var proxyURLHostPort *string
    82			var proxyURLUser *url.Userinfo
    83			proxyHostNames := sets.New[string]()
    84	
    85			if len(httpsProxyURL) > 0 {
    86				u, err := url.Parse(httpsProxyURL)
    87				if err != nil {
    88					fmt.Fprintf(os.Stderr, "Error: failed to parse HTTPS proxy URL: %v", err)
    89					os.Exit(1)
    90				}
    91				proxyURLUser = u.User
    92				hostName, _, err := net.SplitHostPort(u.Host)
    93				if err == nil {
    94					proxyHostNames.Insert(hostName)
    95				}
    96				l.V(4).Info("Data plane HTTPS proxy is set", "hostname", hostName, "url", u.String())
    97				proxyURLHostPort = ptr.To(u.Host)
    98			}
    99			if len(httpProxyURL) > 0 {
   100				u, err := url.Parse(httpProxyURL)
   101				if err != nil {
   102					fmt.Fprintf(os.Stderr, "Error: failed to parse HTTP proxy URL: %v", err)
   103					os.Exit(1)
   104				}
   105				hostName, _, err := net.SplitHostPort(u.Host)
   106				if err == nil {
   107					proxyHostNames.Insert(hostName)
   108				}
   109				l.V(4).Info("Data plane HTTP proxy is set", "hostname", hostName, "url", u.String())
   110				if proxyURLHostPort == nil {
   111					proxyURLHostPort = ptr.To(u.Host)
   112				}
   113			}
   114			l.V(4).Info("Excluding API hosts from isCloudAPI check", "hosts", sets.List(proxyHostNames))
   115			opts.ExcludeCloudAPIHosts = sets.List(proxyHostNames)
   116	
   117			konnectivityDialer, err := konnectivityproxy.NewKonnectivityDialer(opts)
   118			if err != nil {
   119				fmt.Fprintf(os.Stderr, "Error: failed to initialize konnectivity dialer: %v", err)
   120				os.Exit(1)
   121			}
   122	
   123			userProxyConfig := &httpproxy.Config{
   124				HTTPProxy:  httpProxyURL,
   125				HTTPSProxy: httpsProxyURL,
   126				NoProxy:    noProxy,
   127			}
   128			userProxyFunc := userProxyConfig.ProxyFunc()
   129	
   130			httpProxy := goproxy.NewProxyHttpServer()
   131			httpProxy.Verbose = true
   132	
   133			if proxyURLHostPort != nil {
   134				host, _, err := net.SplitHostPort(*proxyURLHostPort)
   135				if err != nil {
   136					fmt.Fprintf(os.Stderr, "Error: failed to split proxy URL host port (%s): %v", *proxyURLHostPort, err)
   137				}
   138				proxyTLS = &tls.Config{
   139					MinVersion: tls.VersionTLS12,
   140					ServerName: host,
   141				}
   142			}
   143			httpProxy.Tr = &http.Transport{
   144				TLSClientConfig: proxyTLS,
   145				Proxy: func(req *http.Request) (*url.URL, error) {
   146					l.V(4).Info("Determining whether request should be proxied", "url", req.URL)
   147					u, err := userProxyFunc(req.URL)
   148					if err != nil {
   149						l.V(4).Error(err, "failed to determine whether request should be proxied")
   150						return nil, err
   151					}
   152					l.V(4).Info("Should proxy", "url", u)
   153					return u, nil
   154				},
   155				DialContext: konnectivityDialer.DialContext,
   156			}
   157			if httpsProxyURL != "" {
   158				httpProxy.ConnectDialWithReq = connectDialFunc(
   159					shouldDialDirectFunc(opts.ConnectDirectlyToCloudAPIs, konnectivityDialer.IsCloudAPI, userProxyFunc),
   160					dialDirectFunc(httpProxy),
   161					dialThroughProxyFunc(httpProxy, httpsProxyURL, proxyURLUser),
   162				)
   163			} else {
   164				httpProxy.ConnectDial = nil
   165				httpProxy.ConnectDialWithReq = nil
   166			}
   167			err = http.ListenAndServe(fmt.Sprintf(":%d", servingPort), httpProxy)
   168			if err != nil {
   169				fmt.Fprintf(os.Stderr, "Error: %v", err)
   170				os.Exit(1)
   171			}
   172		}
   173	
   174		return cmd
   175	}
   176	
   177	type dialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
   178	type dialRequestFunc func(req *http.Request, network, addr string) (net.Conn, error)
   179	
   180	func dialDirectFunc(httpProxy *goproxy.ProxyHttpServer) dialFunc {
   181		return httpProxy.Tr.DialContext
   182	}
   183	
   184	func dialThroughProxyFunc(httpProxy *goproxy.ProxyHttpServer, proxyURL string, proxyURLUser *url.Userinfo) dialFunc {
   185		dialFn := httpProxy.NewConnectDialToProxyWithHandler(proxyURL, addBasicAuthHeader(proxyURLUser))
   186		return func(_ context.Context, network, addr string) (net.Conn, error) {
   187			return dialFn(network, addr)
   188		}
   189	}
   190	
   191	func shouldDialDirectFunc(connectDirectlyToCloudAPIs bool, isCloudAPI func(string) bool, userProxyFunc func(*url.URL) (*url.URL, error)) func(*url.URL) (bool, error) {
   192		return func(u *url.URL) (bool, error) {
   193			if connectDirectlyToCloudAPIs {
   194				hostName, err := netutil.HostFromURL(u.String())
   195				if err != nil {
   196					return false, err
   197				}
   198				if isCloudAPI(hostName) {
   199					return true, nil
   200				}


Script executed:

# Find the dialThroughProxyFunc function and understand how it's used
rg "dialThroughProxyFunc" ./konnectivity-https-proxy/ -A 10 -B 5

Repository: openshift/hypershift


Repository: openshift/hypershift
Exit code: 0

stdout:

./konnectivity-https-proxy/cmd.go-		}
./konnectivity-https-proxy/cmd.go-		if httpsProxyURL != "" {
./konnectivity-https-proxy/cmd.go-			httpProxy.ConnectDialWithReq = connectDialFunc(
./konnectivity-https-proxy/cmd.go-				shouldDialDirectFunc(opts.ConnectDirectlyToCloudAPIs, konnectivityDialer.IsCloudAPI, userProxyFunc),
./konnectivity-https-proxy/cmd.go-				dialDirectFunc(httpProxy),
./konnectivity-https-proxy/cmd.go:				dialThroughProxyFunc(httpProxy, httpsProxyURL, proxyURLUser),
./konnectivity-https-proxy/cmd.go-			)
./konnectivity-https-proxy/cmd.go-		} else {
./konnectivity-https-proxy/cmd.go-			httpProxy.ConnectDial = nil
./konnectivity-https-proxy/cmd.go-			httpProxy.ConnectDialWithReq = nil
./konnectivity-https-proxy/cmd.go-		}
./konnectivity-https-proxy/cmd.go-		err = http.ListenAndServe(fmt.Sprintf(":%d", servingPort), httpProxy)
./konnectivity-https-proxy/cmd.go-		if err != nil {
./konnectivity-https-proxy/cmd.go-			fmt.Fprintf(os.Stderr, "Error: %v", err)
./konnectivity-https-proxy/cmd.go-			os.Exit(1)
./konnectivity-https-proxy/cmd.go-		}
--
./konnectivity-https-proxy/cmd.go-
./konnectivity-https-proxy/cmd.go-func dialDirectFunc(httpProxy *goproxy.ProxyHttpServer) dialFunc {
./konnectivity-https-proxy/cmd.go-	return httpProxy.Tr.DialContext
./konnectivity-https-proxy/cmd.go-}
./konnectivity-https-proxy/cmd.go-
./konnectivity-https-proxy/cmd.go:func dialThroughProxyFunc(httpProxy *goproxy.ProxyHttpServer, proxyURL string, proxyURLUser *url.Userinfo) dialFunc {
./konnectivity-https-proxy/cmd.go-	dialFn := httpProxy.NewConnectDialToProxyWithHandler(proxyURL, addBasicAuthHeader(proxyURLUser))
./konnectivity-https-proxy/cmd.go-	return func(_ context.Context, network, addr string) (net.Conn, error) {
./konnectivity-https-proxy/cmd.go-		return dialFn(network, addr)
./konnectivity-https-proxy/cmd.go-	}
./konnectivity-https-proxy/cmd.go-}
./konnectivity-https-proxy/cmd.go-
./konnectivity-https-proxy/cmd.go-func shouldDialDirectFunc(connectDirectlyToCloudAPIs bool, isCloudAPI func(string) bool, userProxyFunc func(*url.URL) (*url.URL, error)) func(*url.URL) (bool, error) {
./konnectivity-https-proxy/cmd.go-	return func(u *url.URL) (bool, error) {
./konnectivity-https-proxy/cmd.go-		if connectDirectlyToCloudAPIs {
./konnectivity-https-proxy/cmd.go-			hostName, err := netutil.HostFromURL(u.String())


Script executed:

# Check if context is used elsewhere in this file for dial operations
rg "context\." ./konnectivity-https-proxy/cmd.go -B 2 -A 2

Repository: openshift/hypershift


Repository: openshift/hypershift
Exit code: 0

stdout:

}

type dialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
type dialRequestFunc func(req *http.Request, network, addr string) (net.Conn, error)

--
func dialThroughProxyFunc(httpProxy *goproxy.ProxyHttpServer, proxyURL string, proxyURLUser *url.Userinfo) dialFunc {
	dialFn := httpProxy.NewConnectDialToProxyWithHandler(proxyURL, addBasicAuthHeader(proxyURLUser))
	return func(_ context.Context, network, addr string) (net.Conn, error) {
		return dialFn(network, addr)
	}


Implement context-aware HTTPS proxy CONNECT dialing to support request cancellation.

The dialThroughProxyFunc wrapper accepts context.Context but ignores it by discarding the parameter with _, breaking context cancellation and timeout propagation on this proxy path. The underlying goproxy.NewConnectDialToProxyWithHandler (v1.7.2) does not natively support context during CONNECT dialing. To align with Kubernetes/Go patterns where the direct dial path (dialDirectFunc) properly respects context via DialContext, implement a custom context-aware CONNECT dialer. Recommended approaches: (1) implement a custom CONNECT handshake that respects ctx.Done(), or (2) use a third-party library like github.com/elastic/proxy-connect-dialer-go that provides context-aware DialContext support for proxy CONNECT operations.

🤖 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 `@konnectivity-https-proxy/cmd.go` around lines 185 - 188, The current
dialThroughProxyFunc wrapper ignores the passed context (it discards ctx and
returns a func that calls dialFn(network, addr)), breaking
cancellation/timeouts; replace this with a context-aware CONNECT dialer by using
or implementing a DialContext-capable CONNECT function: either swap
httpProxy.NewConnectDialToProxyWithHandler for a library that exposes
DialContext (e.g., github.com/elastic/proxy-connect-dialer-go) and call its
DialContext with the incoming ctx, or implement a custom CONNECT handshake
inside dialThroughProxyFunc that performs dial + CONNECT while selecting on
ctx.Done() to cancel the operation; ensure you still add basic auth via
addBasicAuthHeader(proxyURLUser) and keep the returned signature func(ctx
context.Context, network, addr string) (net.Conn, error) so context cancellation
and timeouts propagate.

@codecov

codecov Bot commented May 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 41.45%. Comparing base (e25a87a) to head (3cd8363).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8550      +/-   ##
==========================================
+ Coverage   41.44%   41.45%   +0.01%     
==========================================
  Files         756      756              
  Lines       93644    93644              
==========================================
+ Hits        38807    38821      +14     
+ Misses      52114    52100      -14     
  Partials     2723     2723              
Files with missing lines Coverage Δ
konnectivity-https-proxy/cmd.go 18.39% <100.00%> (+8.04%) ⬆️
Flag Coverage Δ
cmd-support 34.87% <ø> (ø)
cpo-hostedcontrolplane 43.50% <ø> (ø)
cpo-other 42.79% <ø> (ø)
hypershift-operator 51.56% <ø> (ø)
other 31.78% <100.00%> (+0.14%) ⬆️

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
konnectivity-https-proxy/cmd.go (1)

181-183: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

context.Background() on Line 182 drops request cancellation/timeout propagation.

Using a background context here disconnects dialing from the incoming request lifecycle. This can leave dials running after client cancellation and weakens the DialContext migration.

Suggested fix
-type dialFunc func(network, addr string) (net.Conn, error)
+type dialFunc func(ctx context.Context, network, addr string) (net.Conn, error)

 func dialDirectFunc(httpProxy *goproxy.ProxyHttpServer) dialFunc {
-	return func(network, addr string) (net.Conn, error) {
-		return httpProxy.Tr.DialContext(context.Background(), network, addr)
-	}
+	return httpProxy.Tr.DialContext
 }

 func dialThroughProxyFunc(httpProxy *goproxy.ProxyHttpServer, proxyURL string, proxyURLUser *url.Userinfo) dialFunc {
-	return httpProxy.NewConnectDialToProxyWithHandler(proxyURL, addBasicAuthHeader(proxyURLUser))
+	dialFn := httpProxy.NewConnectDialToProxyWithHandler(proxyURL, addBasicAuthHeader(proxyURLUser))
+	return func(ctx context.Context, network, addr string) (net.Conn, error) {
+		select {
+		case <-ctx.Done():
+			return nil, ctx.Err()
+		default:
+		}
+		return dialFn(network, addr)
+	}
 }

 func connectDialFunc(shouldDialDirect func(*url.URL) (bool, error), dialDirectly dialFunc, dialThroughProxy dialFunc) dialRequestFunc {
 	return func(req *http.Request, network, addr string) (net.Conn, error) {
 		shouldDialDirectly, err := shouldDialDirect(req.URL)
 		if err != nil {
 			return nil, err
 		}
 		if shouldDialDirectly {
-			return dialDirectly(network, addr)
+			return dialDirectly(req.Context(), network, addr)
 		}
-		return dialThroughProxy(network, addr)
+		return dialThroughProxy(req.Context(), network, addr)
 	}
 }
#!/bin/bash
set -euo pipefail

# Verify goproxy version and dial signatures in this repo
rg -n 'github.com/elazarl/goproxy' go.mod
rg -n --glob '*.go' 'ConnectDialWithReq|NewConnectDialToProxyWithHandler|type .*ConnectDial' vendor/github.com/elazarl/goproxy -C2

# Verify current context propagation in this file
rg -n 'type dialFunc|dialDirectFunc|DialContext\(context.Background\)|connectDialFunc\(' konnectivity-https-proxy/cmd.go -C2

Expected verification outcome: goproxy CONNECT helpers are non-context signatures in current version, and this file currently hardcodes context.Background() at Line 182.

🤖 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 `@konnectivity-https-proxy/cmd.go` around lines 181 - 183, The dialer currently
calls httpProxy.Tr.DialContext(context.Background(), ...) which drops request
cancellation; replace the background context with the incoming request's context
so dials cancel with the client request: wherever the closure that returns
func(network, addr string) (net.Conn, error) is created, capture the request
context (e.g. req.Context()) from the goproxy CONNECT handler and call
httpProxy.Tr.DialContext(req.Context(), network, addr) instead of
context.Background(); if the CONNECT helper in use doesn't expose req, adapt the
factory that builds this dial func (the connectDial/ConnectDialWithReq wrapper)
to accept or capture a context and propagate it into httpProxy.Tr.DialContext.
🤖 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 `@konnectivity-https-proxy/cmd.go`:
- Around line 181-183: The dialer currently calls
httpProxy.Tr.DialContext(context.Background(), ...) which drops request
cancellation; replace the background context with the incoming request's context
so dials cancel with the client request: wherever the closure that returns
func(network, addr string) (net.Conn, error) is created, capture the request
context (e.g. req.Context()) from the goproxy CONNECT handler and call
httpProxy.Tr.DialContext(req.Context(), network, addr) instead of
context.Background(); if the CONNECT helper in use doesn't expose req, adapt the
factory that builds this dial func (the connectDial/ConnectDialWithReq wrapper)
to accept or capture a context and propagate it into httpProxy.Tr.DialContext.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 173ac80f-1b8f-400a-93ca-5fee6afc0bca

📥 Commits

Reviewing files that changed from the base of the PR and between 48f1889 and 424c65a.

📒 Files selected for processing (1)
  • konnectivity-https-proxy/cmd.go

@PoornimaSingour

Copy link
Copy Markdown
Contributor Author

/jira-refresh

@openshift-ci-robot

Copy link
Copy Markdown

@PoornimaSingour: This pull request references Jira Issue OCPBUGS-55621, 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)

No GitHub users were found matching the public email listed for the QA contact in Jira (jiezhao@redhat.com), skipping review request.

Details

In response to this:

What this PR does / why we need it:

Replacing deprecated Dial with DialContext in konnectivity-https-proxy/cmd.go so that golangci-lint passes without needing nolint suppressions.
If we uncomment nolint in cmd.go its giving below error:

konnectivity-https-proxy/cmd.go uses the deprecated Dial field on http.Transport (deprecated since Go 1.7) instead of DialContext. A // nolint:staticcheck comment on line 182 suppresses the lint warning.

Which issue(s) this PR fixes:

Fixes ---> https://redhat.atlassian.net/browse/OCPBUGS-55621

Special notes for your reviewer:

Checklist:

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

Summary by CodeRabbit

  • Improvements

  • HTTPS proxy connection handling now uses context-aware networking, improving support for request timeouts and cancellations.

  • Dialing behavior updated to rely on newer connection APIs for cleaner lifecycle management and more reliable setup/teardown.

  • Tests

  • Added unit tests validating direct vs. proxy dialing behavior and proper error propagation.

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

Copy link
Copy Markdown

@PoornimaSingour: This pull request references Jira Issue OCPBUGS-55621, 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)

No GitHub users were found matching the public email listed for the QA contact in Jira (jiezhao@redhat.com), skipping review request.

Details

In response to this:

What this PR does / why we need it:

Replacing deprecated Dial with DialContext in konnectivity-https-proxy/cmd.go so that golangci-lint passes without needing nolint suppressions.
If we uncomment nolint in cmd.go its giving below error:

konnectivity-https-proxy/cmd.go uses the deprecated Dial field on http.Transport (deprecated since Go 1.7) instead of DialContext. A // nolint:staticcheck comment on line 182 suppresses the lint warning.

Which issue(s) this PR fixes:

Fixes ---> https://redhat.atlassian.net/browse/OCPBUGS-55621

Special notes for your reviewer:

Checklist:

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

Summary by CodeRabbit

  • Improvements

  • HTTPS proxy connection handling now uses context-aware networking, improving support for request timeouts and cancellations.

  • Dialing behavior updated to rely on modern connection APIs for cleaner lifecycle management and more reliable setup/teardown.

  • Tests

  • Added unit tests validating direct vs. proxy dialing selection, successful direct dialing, and correct propagation of dialing errors.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
konnectivity-https-proxy/cmd_test.go (2)

155-162: ⚡ Quick win

Consider returning a valid mock connection or an error in stub dialers.

The stub directDial and proxyDial functions return (nil, nil), which violates Go's convention that a nil error should accompany a valid (non-nil) return value. While this works for tests that only verify which dialer is called, it's not realistic and could mask issues if connectDialFunc is later modified to use the returned connection.

Consider returning a mock connection (e.g., &net.TCPConn{} cast to net.Conn via a test helper, or a custom mock implementing net.Conn) with nil error to better match production behavior.

Also applies to: 182-189

🤖 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 `@konnectivity-https-proxy/cmd_test.go` around lines 155 - 162, The stub
dialers directDial and proxyDial currently return (nil, nil) which violates Go
conventions; update these stubs to return a valid mock net.Conn and nil error
(or return a non-nil error when simulating failure) so tests are realistic;
implement or reuse a small test helper mock that satisfies net.Conn (e.g., a
minimal struct implementing Read/Write/Close/etc.) and have directDial and
proxyDial return that mock, and update the same pattern for the other stub block
at lines 182-189; this ensures connectDialFunc and callers can safely use the
returned connection.

108-218: ⚖️ Poor tradeoff

Consider adding tests for context-aware dial behavior.

The current tests verify that DialContext is wired correctly and that routing logic works as expected. As an optional enhancement, you might consider adding tests that exercise context-aware behavior such as dial cancellation or timeout via context. This would more thoroughly validate the benefits of the DialContext migration.

Example scenarios:

  • Canceling a context before dial completes
  • Context timeout during a slow dial

This is not required for the current refactoring but could strengthen confidence in context propagation through the dial path.

🤖 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 `@konnectivity-https-proxy/cmd_test.go` around lines 108 - 218, Add tests that
exercise context-aware dialing by creating a transport with a DialContext
implementation that blocks until ctx.Done() (or respects context deadlines) and
then verifying that a canceled or timed-out context causes the dial to return
promptly with the context error; apply this pattern to test the DialContext path
used by dialDirectFunc and the connectDialFunc call paths (i.e., ensure you
invoke the DialContext directly or wire a proxy transport into
dialDirectFunc/connectDialFunc so the blocking DialContext is used) and assert
the returned error is context.Canceled or context.DeadlineExceeded as
appropriate.
🤖 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.

Nitpick comments:
In `@konnectivity-https-proxy/cmd_test.go`:
- Around line 155-162: The stub dialers directDial and proxyDial currently
return (nil, nil) which violates Go conventions; update these stubs to return a
valid mock net.Conn and nil error (or return a non-nil error when simulating
failure) so tests are realistic; implement or reuse a small test helper mock
that satisfies net.Conn (e.g., a minimal struct implementing
Read/Write/Close/etc.) and have directDial and proxyDial return that mock, and
update the same pattern for the other stub block at lines 182-189; this ensures
connectDialFunc and callers can safely use the returned connection.
- Around line 108-218: Add tests that exercise context-aware dialing by creating
a transport with a DialContext implementation that blocks until ctx.Done() (or
respects context deadlines) and then verifying that a canceled or timed-out
context causes the dial to return promptly with the context error; apply this
pattern to test the DialContext path used by dialDirectFunc and the
connectDialFunc call paths (i.e., ensure you invoke the DialContext directly or
wire a proxy transport into dialDirectFunc/connectDialFunc so the blocking
DialContext is used) and assert the returned error is context.Canceled or
context.DeadlineExceeded as appropriate.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 594733f7-1e01-437d-a803-03903fbdd62c

📥 Commits

Reviewing files that changed from the base of the PR and between b4b8d11 and 993f4ea.

📒 Files selected for processing (1)
  • konnectivity-https-proxy/cmd_test.go

@PoornimaSingour PoornimaSingour marked this pull request as ready for review May 25, 2026 09:36
@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 25, 2026
@openshift-ci openshift-ci Bot requested review from csrwng and jparrill May 25, 2026 09:37
@PoornimaSingour

Copy link
Copy Markdown
Contributor Author

/verified by me

Tested manually on a HyperShift hosted cluster
Management Cluster - api.hcpnewdgautam.india.aws.cee.support:6443
HostedCluster -clusters/dhruvhcp (OCP 4.21.16, 2 worker nodes)
Custom CPO Image - quay.io/rhn_support_psingour/control-plane-operator:dial-context-test

E2E Cluster Validation — ✅ PASSED

Validation Step Result
CPO deployed with custom image
CPO reconciled all components (etcd, kube-apiserver, openshift-apiserver, router, etc.)
Guest cluster oc get nodes (konnectivity tunnel) ✅ 2 nodes Ready
Guest cluster oc exec into router pod (SPDY via konnectivity)
Guest cluster oc logs from router pod (streaming via konnectivity)
All 19 ClusterOperators Available, not Degraded
No errors in konnectivity-proxy-https sidecar logs

Konnectivity Components Verified

Component Pods Proxy Type Status
konnectivity-agent 2 ✅ Running
kube-apiserver (konnectivity-server) 3 ✅ Running
openshift-apiserver 3 HTTPS ✅ Running
oauth-openshift 3 HTTPS + SOCKS5 ✅ Running
ingress-operator 1 HTTPS ✅ Running
olm-operator 1 SOCKS5 ✅ Running
catalog-operator 1 SOCKS5 ✅ Running
openshift-oauth-apiserver 3 SOCKS5 ✅ Running
packageserver 3 SOCKS5 ✅ Running

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

Copy link
Copy Markdown

@PoornimaSingour: This PR has been marked as verified by me.

Details

In response to this:

/verified by me

Tested manually on a HyperShift hosted cluster
Management Cluster - api.hcpnewdgautam.india.aws.cee.support:6443
HostedCluster -clusters/dhruvhcp (OCP 4.21.16, 2 worker nodes)
Custom CPO Image - quay.io/rhn_support_psingour/control-plane-operator:dial-context-test

E2E Cluster Validation — ✅ PASSED

Validation Step Result
CPO deployed with custom image
CPO reconciled all components (etcd, kube-apiserver, openshift-apiserver, router, etc.)
Guest cluster oc get nodes (konnectivity tunnel) ✅ 2 nodes Ready
Guest cluster oc exec into router pod (SPDY via konnectivity)
Guest cluster oc logs from router pod (streaming via konnectivity)
All 19 ClusterOperators Available, not Degraded
No errors in konnectivity-proxy-https sidecar logs

Konnectivity Components Verified

Component Pods Proxy Type Status
konnectivity-agent 2 ✅ Running
kube-apiserver (konnectivity-server) 3 ✅ Running
openshift-apiserver 3 HTTPS ✅ Running
oauth-openshift 3 HTTPS + SOCKS5 ✅ Running
ingress-operator 1 HTTPS ✅ Running
olm-operator 1 SOCKS5 ✅ Running
catalog-operator 1 SOCKS5 ✅ Running
openshift-oauth-apiserver 3 SOCKS5 ✅ Running
packageserver 3 SOCKS5 ✅ Running

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.

@jparrill jparrill left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Dropped some comments. Thanks!

})
}

func TestConnectDialFunc(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: this should be table-driven following Gherkin nomenclature, consistent with the other tests in this file (TestShouldDialDirectFunc, TestAddBasicAuthHeader). The three subtests share the same scaffold and only differ in the boolean + expectations.

Comment thread konnectivity-https-proxy/cmd_test.go Outdated
return true, nil
}

dialFn := connectDialFunc(shouldDirect, directDial, proxyDial)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: the error from http.NewRequest is silently discarded here (and on lines 191, 213). Maybe:

req, err := http.NewRequest("CONNECT", "https://example.com:443", nil)
g.Expect(err).NotTo(HaveOccurred())


import (
"context"
"crypto/tls"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Checked: removing Dial is safe — Go's http.Transport prefers DialContext when both are set, and goproxy's internal dial() also checks Tr.DialContext first. Good cleanup.

Comment thread konnectivity-https-proxy/cmd.go Outdated
// nolint:staticcheck
return httpProxy.Tr.Dial
return func(network, addr string) (net.Conn, error) {
return httpProxy.Tr.DialContext(context.Background(), network, addr)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In a separate work item, it'd be good to track the propagation of the original request context through the dial instead of introducing a context.Background() here.

Otherwise, lgtm

@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Jun 2, 2026
@PoornimaSingour PoornimaSingour force-pushed the DialwithDialContext branch 3 times, most recently from bf5bd87 to 7fd8035 Compare June 3, 2026 09:27
@PoornimaSingour

PoornimaSingour commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

Due to version mismatch in CI and local, the lint and verify is failing in CI but passing in my local.
CI uses go1.25.7, and local uses go1.26.3. Trying to fix it.

@hypershift-jira-solve-ci

Copy link
Copy Markdown

Now I have all the evidence. The two lint errors are crystal clear:

  1. fatcontext at line 188: capturedCtx = ctx — nested context in function literal
  2. usestdlibvars at line 179: "CONNECT" should be http.MethodConnect

Test Failure Analysis Complete

Job Information

Test Failure Analysis

Error

konnectivity-https-proxy/cmd_test.go:188:5: nested context in function literal (fatcontext)
				capturedCtx = ctx
				^
konnectivity-https-proxy/cmd_test.go:179:51: "CONNECT" can be replaced by http.MethodConnect (usestdlibvars)
			req, err := http.NewRequestWithContext(reqCtx, "CONNECT", "https://example.com:443", nil)
			                                               ^
2 issues:
* fatcontext: 1
* usestdlibvars: 1
make: *** [Makefile:120: lint] Error 1

Summary

The lint job failed due to two golangci-lint violations in the newly added test file konnectivity-https-proxy/cmd_test.go introduced by PR #8550. The first violation (fatcontext) flags the line capturedCtx = ctx inside a closure at line 188, where a context variable from an outer scope is being reassigned inside a function literal — the linter considers this a "nested context" anti-pattern. The second violation (usestdlibvars) flags the use of the string literal "CONNECT" at line 179, where the standard library constant http.MethodConnect should be used instead. Both issues are in the TestConnectDialFunc test function. The production code changes (cmd.go) passed lint cleanly — only the new test code has violations.

Root Cause

Two distinct lint rule violations in the new test code added by this PR:

  1. fatcontext at line 188 — Inside TestConnectDialFunc, the dialDirectly closure captures capturedCtx from the outer test scope and reassigns it with capturedCtx = ctx. The fatcontext linter flags this as a "nested context in function literal" because the context (ctx) is being stored into an outer-scope variable inside a closure, which the linter considers an anti-pattern (contexts should flow downward, not be captured upward). The fix is to restructure so the context assertion happens inside the closure, or to use a different mechanism to verify the context was passed correctly (e.g., check a value from the context directly inside the closure and store that result rather than the context itself).

  2. usestdlibvars at line 179 — The HTTP method string "CONNECT" is used as a literal in http.NewRequestWithContext(reqCtx, "CONNECT", ...). The usestdlibvars linter requires using the standard library constant http.MethodConnect instead of the raw string. This is a simple find-and-replace fix.

Neither issue is in the production code (cmd.go) — both are exclusively in the new test file. The API lint pass (on the api/ subdirectory) passed cleanly with 0 issues. The main lint pass found these 2 issues out of 964 total candidates after filtering.

Recommendations
  1. Fix usestdlibvars — Replace the string literal "CONNECT" with http.MethodConnect at line 179 of cmd_test.go:

    // Before:
    req, err := http.NewRequestWithContext(reqCtx, "CONNECT", "https://example.com:443", nil)
    // After:
    req, err := http.NewRequestWithContext(reqCtx, http.MethodConnect, "https://example.com:443", nil)
  2. Fix fatcontext — Restructure the context capture in the dialDirectly closure. Instead of assigning capturedCtx = ctx, verify the context inline or store a derived value. For example:

    var capturedTestValue string
    dialDirectly := func(ctx context.Context, network, addr string) (net.Conn, error) {
        directCalled = true
        if v, ok := ctx.Value(contextKey("test")).(string); ok {
            capturedTestValue = v
        }
        return nil, nil
    }
    // Then assert:
    if tc.expectDialDirect {
        g.Expect(capturedTestValue).To(Equal("value"))
    }

    Alternatively, if the full context identity check is important, you can suppress the lint with //nolint:fatcontext and a comment explaining why.

  3. Run linter locally before pushingmake lint will catch these issues locally and save CI round-trips.

Evidence
Evidence Detail
Lint error 1 cmd_test.go:188:5: nested context in function literal (fatcontext)capturedCtx = ctx in dialDirectly closure
Lint error 2 cmd_test.go:179:51: "CONNECT" can be replaced by http.MethodConnect (usestdlibvars)
Total issues found 2 (out of 964 candidates before filtering)
API lint result 0 issues (passed cleanly)
Main lint result 2 issues (both in new test code from PR)
golangci-lint version v2.11.4 with go1.25.7
Active linters (main) dupword, durationcheck, errcheck, errorlint, fatcontext, gci, gocyclo, govet, ineffassign, misspell, nilerr, noctx, staticcheck, unparam, unused, usestdlibvars
Exit code 2 (via make: *** [Makefile:120: lint] Error 1)
Changed files konnectivity-https-proxy/cmd.go (passed lint), konnectivity-https-proxy/cmd_test.go (2 violations)
Job URL https://github.com/openshift/hypershift/actions/runs/26895122131/job/79331803695

PoornimaSingour and others added 3 commits June 4, 2026 15:06
Replace the deprecated `net.Dial` with `DialContext` in
konnectivity-https-proxy and propagate the original request
context through the dial chain instead of using context.Background().

Introduce dialContextFunc type to carry context from
connectDialFunc (which has access to req.Context()) through
to dialDirectFunc.

Add unit tests for dialDirectFunc covering success and failure
scenarios.

Co-Authored-By: Poornima Singour <psingour@redhat.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@openshift-ci

openshift-ci Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

@PoornimaSingour: 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

area/documentation Indicates the PR includes changes for documentation jira/severity-low Referenced Jira bug's severity is low for the branch this PR is targeting. 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.

4 participants