diff --git a/internal/githubclient/githubclient_test.go b/internal/githubclient/githubclient_test.go index 65e14f446..dfb0320c4 100644 --- a/internal/githubclient/githubclient_test.go +++ b/internal/githubclient/githubclient_test.go @@ -6,7 +6,9 @@ package githubclient import ( "context" "net/http" + "net/url" "strings" + "sync" "testing" "time" @@ -81,22 +83,42 @@ func TestNewGitHubClient(t *testing.T) { t.Run(test.name, func(t *testing.T) { t.Parallel() - called := false + var mu sync.Mutex + var receivedAuthHeaders [][]string testServer, testServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Len(t, r.Header["Authorization"], 1) - require.Equal(t, "Bearer "+test.token, r.Header.Get("Authorization")) - called = true + mu.Lock() + defer mu.Unlock() + receivedAuthHeaders = append(receivedAuthHeaders, r.Header.Values("Authorization")) }), nil) t.Cleanup(func() { - require.True(t, (test.wantErr == "" && called) || (test.wantErr != "" && !called)) + mu.Lock() + defer mu.Unlock() + if test.wantErr != "" { + require.Empty(t, receivedAuthHeaders) + } }) + testServerURL, err := url.Parse(testServer.URL) + require.NoError(t, err) + pool, err := cert.NewPoolFromBytes(testServerCA) require.NoError(t, err) httpClient := phttp.Default(pool) + // go-github only adds the Authorization header to requests whose origin matches the client's base URL + // or upload URL. Redirect every request to the test server below that check, so that requests to the + // (fake) base URL can be observed. + originalTransport := httpClient.Transport + httpClient.Transport = roundTripperFunc(func(req *http.Request) (*http.Response, error) { + req = req.Clone(req.Context()) + req.URL.Scheme = testServerURL.Scheme + req.URL.Host = testServerURL.Host + req.Host = "" + return originalTransport.RoundTrip(req) + }) + actualI, err := NewGitHubClient(httpClient, test.apiBaseURL, test.token) if test.wantErr != "" { @@ -111,12 +133,24 @@ func TestNewGitHubClient(t *testing.T) { require.Equal(t, test.wantBaseURL, actual.client.BaseURL()) // Force the githubClient's httpClient roundTrippers to run and add the Authorization header - - req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, testServer.URL, nil) + // for a request to the base URL. + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, actual.client.BaseURL()+"user", nil) require.NoError(t, err) _, err = actual.client.Client().Do(req) //nolint:bodyclose require.NoError(t, err) + + // A request to any other origin should not carry the token (starting in go-github/v93). + req, err = http.NewRequestWithContext(context.Background(), http.MethodGet, testServer.URL, nil) + require.NoError(t, err) + + _, err = actual.client.Client().Do(req) //nolint:bodyclose + require.NoError(t, err) + + mu.Lock() + defer mu.Unlock() + // Assert that the first request had the expected auth token and the second request had none. + require.Equal(t, [][]string{{"Bearer " + test.token}, nil}, receivedAuthHeaders) } }) } @@ -946,3 +980,9 @@ func TestGetTeamMembership(t *testing.T) { }) } } + +type roundTripperFunc func(req *http.Request) (*http.Response, error) + +func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +}