diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-11 18:24:16 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-11 18:24:16 +0200 |
| commit | 1c12325c64bb734dd0ae95a0c803de1ff45d2b4c (patch) | |
| tree | e57c97d5b77e9b542dea887176bb11b533501b23 /internal/github/github_test.go | |
| parent | 224d9059e5c51eaab9295ea5266c64c4dd7fa218 (diff) | |
fix(github): stop logging token diagnostics
Diffstat (limited to 'internal/github/github_test.go')
| -rw-r--r-- | internal/github/github_test.go | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/internal/github/github_test.go b/internal/github/github_test.go new file mode 100644 index 0000000..a65e00a --- /dev/null +++ b/internal/github/github_test.go @@ -0,0 +1,111 @@ +package github + +import ( + "bytes" + "io" + "net/http" + "os" + "strings" + "testing" +) + +type roundTripFunc func(*http.Request) (*http.Response, error) + +func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +func TestNewClient_DoesNotLogTokenDetails(t *testing.T) { + t.Setenv("GITHUB_TOKEN", " test-token \n") + + output := captureStdout(t, func() { + client := NewClient("", "snonux") + if !client.HasToken() { + t.Fatal("expected token to be loaded") + } + if client.token != "test-token" { + t.Fatalf("expected trimmed token, got %q", client.token) + } + }) + + if output != "" { + t.Fatalf("expected no stdout output, got %q", output) + } +} + +func TestClientRepoExists_DoesNotLogAuthorizationHeaderOnUnauthorized(t *testing.T) { + const token = "super-secret-token" + + originalTransport := http.DefaultTransport + http.DefaultTransport = roundTripFunc(func(req *http.Request) (*http.Response, error) { + if got := req.Header.Get("Authorization"); got != "Bearer "+token { + t.Fatalf("expected bearer token header, got %q", got) + } + + return &http.Response{ + StatusCode: http.StatusUnauthorized, + Body: io.NopCloser(strings.NewReader(`{"message":"bad credentials"}`)), + Header: make(http.Header), + }, nil + }) + t.Cleanup(func() { + http.DefaultTransport = originalTransport + }) + + client := NewClient(token, "snonux") + + output := captureStdout(t, func() { + exists, err := client.RepoExists("gitsyncer") + if err == nil { + t.Fatal("expected unauthorized error") + } + if exists { + t.Fatal("expected repo existence check to fail") + } + if !strings.Contains(err.Error(), "authentication failed (401)") { + t.Fatalf("expected 401 error, got %v", err) + } + }) + + if strings.Contains(output, token) { + t.Fatalf("expected output to omit token, got %q", output) + } + if strings.Contains(output, "Authorization header") { + t.Fatalf("expected output to omit authorization header log, got %q", output) + } +} + +func captureStdout(t *testing.T, fn func()) string { + t.Helper() + + originalStdout := os.Stdout + reader, writer, err := os.Pipe() + if err != nil { + t.Fatalf("failed to create pipe: %v", err) + } + + os.Stdout = writer + defer func() { + os.Stdout = originalStdout + }() + + outputCh := make(chan string, 1) + go func() { + var buffer bytes.Buffer + _, _ = io.Copy(&buffer, reader) + outputCh <- buffer.String() + }() + + fn() + + if err := writer.Close(); err != nil { + t.Fatalf("failed to close stdout writer: %v", err) + } + + output := <-outputCh + if err := reader.Close(); err != nil { + t.Fatalf("failed to close stdout reader: %v", err) + } + + return output +} |
