From 177b520b59a947a4a7ab8a8d0d7498be749432ac Mon Sep 17 00:00:00 2001 From: Matt Braun Date: Fri, 1 May 2026 13:22:20 -0500 Subject: [PATCH] Fix GitHub App response processor to match GitHub's 201 status GitHub's installation token endpoint returns 201 Created on success, not 200 OK. The response processor was checking for 200 and silently passing the unwrapped response (containing the plaintext installation token) through to the caller, defeating the sealing protection. Tests still asserted 200 for the GitHub fixtures, so they passed despite the mismatch with the real API. Ref: https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app --- processor.go | 4 +++- processor_test.go | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/processor.go b/processor.go index c23897d..83a0088 100644 --- a/processor.go +++ b/processor.go @@ -965,7 +965,9 @@ func (c *GitHubAppProcessorConfig) ResponseProcessor(_ map[string]string, sctx * } return func(resp *http.Response) error { - if resp.StatusCode != http.StatusOK { + // GitHub's installation token endpoint returns 201 Created on success. + // https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app + if resp.StatusCode != http.StatusCreated { return nil } diff --git a/processor_test.go b/processor_test.go index c7f712d..4cd8cfb 100644 --- a/processor_test.go +++ b/processor_test.go @@ -1387,7 +1387,7 @@ func TestGitHubAppProcessorConfig_ResponseProcessor_SealsInstallationToken(t *te expiresAt := time.Now().Add(time.Hour).UTC().Format(time.RFC3339) githubResp := fmt.Sprintf(`{"token":"ghs_installationtokenXYZ","expires_at":%q,"permissions":{"contents":"read"}}`, expiresAt) resp := &http.Response{ - StatusCode: 200, + StatusCode: 201, Body: io.NopCloser(strings.NewReader(githubResp)), Header: make(http.Header), } @@ -1446,7 +1446,7 @@ func TestGitHubAppProcessorConfig_ResponseProcessor_PinsToAPIHostWithoutOuterVal expiresAt := time.Now().Add(time.Hour).UTC().Format(time.RFC3339) githubResp := fmt.Sprintf(`{"token":"ghs_abc","expires_at":%q}`, expiresAt) resp := &http.Response{ - StatusCode: 200, + StatusCode: 201, Body: io.NopCloser(strings.NewReader(githubResp)), Header: make(http.Header), } @@ -1487,7 +1487,7 @@ func TestGitHubAppProcessorConfig_ResponseProcessor_MissingToken(t *testing.T) { assert.NoError(t, err) resp := &http.Response{ - StatusCode: 200, + StatusCode: 201, Body: io.NopCloser(strings.NewReader(`{"not_token":"nope"}`)), Header: make(http.Header), }