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 | |
| parent | 224d9059e5c51eaab9295ea5266c64c4dd7fa218 (diff) | |
fix(github): stop logging token diagnostics
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/github/github.go | 60 | ||||
| -rw-r--r-- | internal/github/github_test.go | 111 |
2 files changed, 135 insertions, 36 deletions
diff --git a/internal/github/github.go b/internal/github/github.go index 238b486..c886e43 100644 --- a/internal/github/github.go +++ b/internal/github/github.go @@ -19,45 +19,35 @@ type Client struct { // NewClient creates a new GitHub API client func NewClient(token, org string) Client { - // If no token provided, try other sources - if token == "" { - fmt.Println(" No token in config, trying environment variable...") - // Try environment variable - token = os.Getenv("GITHUB_TOKEN") - - // If still no token, try reading from file - if token == "" { - fmt.Println(" No GITHUB_TOKEN env var, trying ~/.gitsyncer_github_token file...") - home, err := os.UserHomeDir() - if err == nil { - tokenFile := filepath.Join(home, ".gitsyncer_github_token") - data, err := os.ReadFile(tokenFile) - if err == nil { - token = strings.TrimSpace(string(data)) - fmt.Printf(" Loaded token from file (length: %d)\n", len(token)) - // Check for common issues - if strings.Contains(token, "\n") || strings.Contains(token, "\r") { - fmt.Println(" Warning: Token contains newline characters") - } - if strings.HasPrefix(token, " ") || strings.HasSuffix(token, " ") { - fmt.Println(" Warning: Token has leading/trailing spaces") - } - } else { - fmt.Printf(" Could not read token file: %v\n", err) - } - } - } else { - fmt.Printf(" Loaded token from env var (length: %d)\n", len(token)) - } - } else { - fmt.Printf(" Using token from config (length: %d)\n", len(token)) - } return Client{ - token: token, + token: loadToken(token), org: org, } } +func loadToken(token string) string { + if token != "" { + return strings.TrimSpace(token) + } + + if envToken := os.Getenv("GITHUB_TOKEN"); envToken != "" { + return strings.TrimSpace(envToken) + } + + home, err := os.UserHomeDir() + if err != nil { + return "" + } + + tokenFile := filepath.Join(home, ".gitsyncer_github_token") + data, err := os.ReadFile(tokenFile) + if err != nil { + return "" + } + + return strings.TrimSpace(string(data)) +} + // CreateRepoRequest represents the request to create a repository type CreateRepoRequest struct { Name string `json:"name"` @@ -94,7 +84,6 @@ func (c *Client) RepoExists(repoName string) (bool, error) { url := fmt.Sprintf("https://api.github.com/repos/%s/%s", c.org, repoName) fmt.Printf(" Checking URL: %s\n", url) - fmt.Printf(" Token present: %v (length: %d)\n", c.token != "", len(c.token)) req, err := http.NewRequest("GET", url, nil) if err != nil { @@ -118,7 +107,6 @@ func (c *Client) RepoExists(repoName string) (bool, error) { // Read the response body for 401 errors body, _ := io.ReadAll(resp.Body) fmt.Printf(" 401 Unauthorized - Response: %s\n", string(body)) - fmt.Printf(" Authorization header: %s\n", req.Header.Get("Authorization")) return false, fmt.Errorf("authentication failed (401): %s", string(body)) } 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 +} |
