From 47dc0afb0409b1e7410b9dd01ced72cb2f23f403 Mon Sep 17 00:00:00 2001 From: YEVHENII SHCHERBINA Date: Thu, 18 Sep 2025 20:03:43 +0000 Subject: [PATCH 1/3] test: add connect tests for proxy package --- proxy/proxy_test.go | 96 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index a70c9e7..6d3b269 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -6,6 +6,7 @@ import ( "log" "log/slog" "net/http" + "net/url" "os" "os/user" "strconv" @@ -200,3 +201,98 @@ func TestProxyServerBasicHTTPS(t *testing.T) { err = server.Stop() require.NoError(t, err) } + +// TestProxyServerCONNECT tests HTTP CONNECT method for HTTPS tunneling +func TestProxyServerCONNECT(t *testing.T) { + // Create test logger + logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ + Level: slog.LevelError, + })) + + // Create test rules (allow all for testing) + testRules, err := rules.ParseAllowSpecs([]string{"*"}) + if err != nil { + t.Fatalf("Failed to parse test rules: %v", err) + } + + // Create rule engine + ruleEngine := rules.NewRuleEngine(testRules, logger) + + // Create mock auditor + auditor := &mockAuditor{} + + // Get current user for TLS setup + currentUser, err := user.Current() + if err != nil { + log.Fatal(err) + } + + uid, _ := strconv.Atoi(currentUser.Uid) + gid, _ := strconv.Atoi(currentUser.Gid) + + // Create TLS certificate manager + certManager, err := boundary_tls.NewCertificateManager(boundary_tls.Config{ + Logger: logger, + ConfigDir: "/tmp/boundary_connect_test", + Uid: uid, + Gid: gid, + }) + require.NoError(t, err) + + // Setup TLS to get cert path for proxy + tlsConfig, caCertPath, configDir, err := certManager.SetupTLSAndWriteCACert() + require.NoError(t, err) + _, _ = caCertPath, configDir + + // Create proxy server + server := NewProxyServer(Config{ + HTTPPort: 8080, + + RuleEngine: ruleEngine, + Auditor: auditor, + Logger: logger, + TLSConfig: tlsConfig, + }) + + // Start server + err = server.Start() + require.NoError(t, err) + + // Give server time to start + time.Sleep(100 * time.Millisecond) + + // Test HTTPS request through proxy transport (automatic CONNECT) + t.Run("HTTPSRequestThroughProxyTransport", func(t *testing.T) { + // Create proxy URL + proxyURL, err := url.Parse("http://localhost:8080") + require.NoError(t, err) + + // Create HTTP client with proxy transport + client := &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyURL(proxyURL), + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, // Skip cert verification for testing + }, + }, + Timeout: 10 * time.Second, + } + + // Because this is HTTPS, Go will issue CONNECT localhost:8080 → dev.coder.com:443 + resp, err := client.Get("https://dev.coder.com/api/v2") + require.NoError(t, err) + defer resp.Body.Close() + + // Read response + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + // Verify response contains expected content + expectedResponse := `{"message":"👋"} +` + require.Equal(t, expectedResponse, string(body)) + }) + + err = server.Stop() + require.NoError(t, err) +} From c57c94782791da45cf551952b5b3ff1ec0e8eac8 Mon Sep 17 00:00:00 2001 From: YEVHENII SHCHERBINA Date: Thu, 18 Sep 2025 20:07:45 +0000 Subject: [PATCH 2/3] test: add http connect tests for proxy package --- proxy/proxy_test.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index 6d3b269..7a029f4 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -293,6 +293,40 @@ func TestProxyServerCONNECT(t *testing.T) { require.Equal(t, expectedResponse, string(body)) }) + // Test HTTP request through proxy transport + t.Run("HTTPRequestThroughProxyTransport", func(t *testing.T) { + // Create proxy URL + proxyURL, err := url.Parse("http://localhost:8080") + require.NoError(t, err) + + // Create HTTP client with proxy transport + client := &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyURL(proxyURL), + }, + Timeout: 10 * time.Second, + } + + // For HTTP requests, Go will send the request directly to the proxy + // The proxy will forward it to the target server + resp, err := client.Get("http://jsonplaceholder.typicode.com/todos/1") + require.NoError(t, err) + defer resp.Body.Close() + + // Read response + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + // Verify response contains expected content + expectedResponse := `{ + "userId": 1, + "id": 1, + "title": "delectus aut autem", + "completed": false +}` + require.Equal(t, expectedResponse, string(body)) + }) + err = server.Stop() require.NoError(t, err) } From 093e4c78af82b000a9f725b21f2412368d11a38e Mon Sep 17 00:00:00 2001 From: YEVHENII SHCHERBINA Date: Thu, 18 Sep 2025 20:12:23 +0000 Subject: [PATCH 3/3] fix: linter --- proxy/proxy_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index 7a029f4..fe61391 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -281,11 +281,11 @@ func TestProxyServerCONNECT(t *testing.T) { // Because this is HTTPS, Go will issue CONNECT localhost:8080 → dev.coder.com:443 resp, err := client.Get("https://dev.coder.com/api/v2") require.NoError(t, err) - defer resp.Body.Close() // Read response body, err := io.ReadAll(resp.Body) require.NoError(t, err) + require.NoError(t, resp.Body.Close()) // Verify response contains expected content expectedResponse := `{"message":"👋"} @@ -311,11 +311,11 @@ func TestProxyServerCONNECT(t *testing.T) { // The proxy will forward it to the target server resp, err := client.Get("http://jsonplaceholder.typicode.com/todos/1") require.NoError(t, err) - defer resp.Body.Close() // Read response body, err := io.ReadAll(resp.Body) require.NoError(t, err) + require.NoError(t, resp.Body.Close()) // Verify response contains expected content expectedResponse := `{