use required headers for GitHub API connection probe request

This commit is contained in:
Ryan Richard
2024-10-14 11:12:34 -07:00
parent c3afa55738
commit f36298c542
2 changed files with 42 additions and 1 deletions
@@ -63,6 +63,13 @@ const (
apiDotGithubDotCom = "api.github.com"
githubDotCom = "github.com"
headerNameAPIVersion = "X-GitHub-Api-Version"
headerValueAPIVersion2022 = "2022-11-28"
headerNameUserAgent = "User-Agent"
headerValueUserAgentConcierge = "pinniped-concierge/v1"
headerNameAccept = "Accept"
headerValueAcceptGitHubJSON = "application/vnd.github+json"
)
// UpstreamGitHubIdentityProviderICache is a thread safe cache that holds a list of validated upstream GitHub IDP configurations.
@@ -515,7 +522,7 @@ func (c *gitHubWatcherController) validateGitHubConnection(
}
// ProbeURL is the production code for how to probe a GitHub URL to test our connection to the GitHub API.
// It can be replaced via constructor injection for testing.
// It can be replaced via constructor injection for testing. Implements ProbeURLFunc.
func ProbeURL(ctx context.Context, client *http.Client, url string) error {
probeRequestCtx, probeRequestCancel := context.WithTimeout(ctx, 30*time.Second)
defer probeRequestCancel()
@@ -526,6 +533,12 @@ func ProbeURL(ctx context.Context, client *http.Client, url string) error {
return err
}
// GitHub API docs say that these headers are required for all requests.
// See https://docs.github.com/en/rest/using-the-rest-api/getting-started-with-the-rest-api?apiVersion=2022-11-28#headers.
probeRequest.Header.Set(headerNameAPIVersion, headerValueAPIVersion2022)
probeRequest.Header.Set(headerNameUserAgent, headerValueUserAgentConcierge)
probeRequest.Header.Set(headerNameAccept, headerValueAcceptGitHubJSON)
probeResponse, err := client.Do(probeRequest)
if err != nil {
return err
@@ -81,6 +81,34 @@ func fakeGithubProbeFuncDisallowsAllProbes(t *testing.T) ProbeURLFunc {
}
}
// TestProbeURL tests the production version of the ProbeURLFunc type.
func TestProbeURL(t *testing.T) {
serverEndpointReached := false
testServer, testServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, []string{"2022-11-28"}, r.Header.Values("X-GitHub-Api-Version"))
require.Equal(t, []string{"pinniped-concierge/v1"}, r.Header.Values("User-Agent"))
require.Equal(t, []string{"application/vnd.github+json"}, r.Header.Values("Accept"))
serverEndpointReached = true
}), nil)
testServerCertPool := x509.NewCertPool()
testServerCertPool.AppendCertsFromPEM(testServerCA)
httpClient := phttp.Default(testServerCertPool)
// Happy path.
err := ProbeURL(context.Background(), httpClient, testServer.URL)
require.NoError(t, err)
require.True(t, serverEndpointReached)
// Invalid URL.
err = ProbeURL(context.Background(), httpClient, "https://invalid hostname")
require.EqualError(t, err, `parse "https://invalid hostname": invalid character " " in host name`)
// Did not trust server's CA, as an example of a failed connection.
err = ProbeURL(context.Background(), phttp.Default(nil), testServer.URL)
require.EqualError(t, err, fmt.Sprintf("Get %q: tls: failed to verify certificate: x509: certificate signed by unknown authority", testServer.URL))
}
func TestController(t *testing.T) {
require.Equal(t, 6, countExpectedConditions)