Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions pkg/tools/mcp/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package mcp
import (
"os"
"testing"
"time"

"github.com/docker/docker-agent/pkg/httpclient"
)

// TestMain swaps the OAuth helpers' SSRF-safe HTTP client for the
// loopback-allowing variant so tests can hit httptest.NewServer (which
// binds to 127.0.0.1). Production code keeps the safe client.
// binds to 127.0.0.1). Production code keeps the safe client. The variant
// carries its own connection pool, so parallel tests closing httptest
// servers (which prunes http.DefaultTransport's pool) can't break its
// in-flight requests.
func TestMain(m *testing.M) {
oauthHTTPClient = httpclient.NewSafeClient(30*time.Second, true)
oauthHTTPClient = oauthHTTPClientForAllowPrivateIPs(true)
os.Exit(m.Run())
}
9 changes: 8 additions & 1 deletion pkg/tools/mcp/oauth_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ var oauthHTTPClient = httpclient.NewSafeClient(30*time.Second, false)

func oauthHTTPClientForAllowPrivateIPs(allowPrivateIPs bool) *http.Client {
if allowPrivateIPs {
return &http.Client{Timeout: 30 * time.Second}
// Clone keeps the default proxy/HTTP2/timeout behavior but gives the
// client its own connection pool: a nil Transport would share
// http.DefaultTransport's pool, which third parties may prune via
// CloseIdleConnections (httptest.Server.Close does).
return &http.Client{
Timeout: 30 * time.Second,
Transport: http.DefaultTransport.(*http.Transport).Clone(),
}
}
return oauthHTTPClient
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/tools/mcp/oauth_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func TestCallbackServer_DuplicateCallbacksDoNotBlock(t *testing.T) {
cs.SetExpectedState("expected-state")
callbackURL := cs.GetRedirectURI() + "?code=authcode&state=expected-state"

client := &http.Client{Timeout: 2 * time.Second}
client := &http.Client{Timeout: 2 * time.Second, Transport: newTestTransport(t)}

// Fire several callbacks back-to-back. Each one must complete (so the
// handler goroutine isn't stuck) regardless of whether anyone is
Expand Down
2 changes: 1 addition & 1 deletion pkg/tools/mcp/oauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
// test's in-flight request ("transport connection broken").
func newTestTransport(t *testing.T) *http.Transport {
t.Helper()
tr := &http.Transport{}
tr := http.DefaultTransport.(*http.Transport).Clone()
t.Cleanup(tr.CloseIdleConnections)
return tr
}
Expand Down
Loading