From 80edc5316eeaaec965ccab9ef8bd63dba69ddaeb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 14 Jan 2026 12:12:08 +0000 Subject: [PATCH 1/3] Add debug logging to auth header parser - Add logger declaration using auth:header namespace - Add sanitized logging to ParseAuthHeader function - Add validation logging to ValidateAPIKey function - Ensures secure logging with no sensitive data exposure --- internal/auth/header.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/internal/auth/header.go b/internal/auth/header.go index 9b732f097..8b9bee686 100644 --- a/internal/auth/header.go +++ b/internal/auth/header.go @@ -16,8 +16,12 @@ package auth import ( "errors" "strings" + + "github.com/githubnext/gh-aw-mcpg/internal/logger" ) +var log = logger.New("auth:header") + var ( // ErrMissingAuthHeader is returned when the Authorization header is missing ErrMissingAuthHeader = errors.New("missing Authorization header") @@ -38,33 +42,52 @@ var ( // - agentID: The extracted agent/session identifier // - error: ErrMissingAuthHeader if header is empty, nil otherwise func ParseAuthHeader(authHeader string) (apiKey string, agentID string, error error) { + // Sanitize header for logging (show only first 4 chars) + sanitized := "" + if len(authHeader) > 4 { + sanitized = authHeader[:4] + "..." + } else if len(authHeader) > 0 { + sanitized = "..." + } + log.Printf("Parsing auth header: sanitized=%s, length=%d", sanitized, len(authHeader)) + if authHeader == "" { + log.Print("Auth header missing, returning error") return "", "", ErrMissingAuthHeader } // Handle "Bearer " format (backward compatibility) if strings.HasPrefix(authHeader, "Bearer ") { + log.Print("Detected Bearer token format (backward compatibility)") token := strings.TrimPrefix(authHeader, "Bearer ") return token, token, nil } // Handle "Agent " format if strings.HasPrefix(authHeader, "Agent ") { + log.Print("Detected Agent ID format") agentIDValue := strings.TrimPrefix(authHeader, "Agent ") return agentIDValue, agentIDValue, nil } // Per MCP spec 7.1: Authorization header contains API key directly // Use the entire header value as both API key and agent/session ID + log.Print("Using plain API key format (MCP spec 7.1)") return authHeader, authHeader, nil } // ValidateAPIKey checks if the provided API key matches the expected key. // Returns true if they match, false otherwise. func ValidateAPIKey(provided, expected string) bool { + log.Printf("Validating API key: expected_configured=%t", expected != "") + if expected == "" { // No API key configured, authentication is disabled + log.Print("No API key configured, authentication disabled") return true } - return provided == expected + + matches := provided == expected + log.Printf("API key validation result: matches=%t", matches) + return matches } From 58ef5ab617ad2a53f91fe555556ba61cd4a9a81c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:10:19 +0000 Subject: [PATCH 2/3] Initial plan From 0e64d20da2722e1891df5d0e07f147399626858f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:13:14 +0000 Subject: [PATCH 3/3] Extract sanitization logic into sanitizeForLogging helper Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- internal/auth/header.go | 21 ++++++++++------ internal/auth/header_test.go | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/internal/auth/header.go b/internal/auth/header.go index 8b9bee686..8f371367b 100644 --- a/internal/auth/header.go +++ b/internal/auth/header.go @@ -29,6 +29,18 @@ var ( ErrInvalidAuthHeader = errors.New("invalid Authorization header format") ) +// sanitizeForLogging returns a sanitized version of the input string for safe logging. +// It shows only the first 4 characters followed by "..." to prevent exposing sensitive data. +// For strings with 4 or fewer characters, it returns only "...". +func sanitizeForLogging(input string) string { + if len(input) > 4 { + return input[:4] + "..." + } else if len(input) > 0 { + return "..." + } + return "" +} + // ParseAuthHeader parses the Authorization header and extracts the API key and agent ID. // Per MCP spec 7.1, the Authorization header should contain the API key directly // without any Bearer prefix or other scheme. @@ -42,14 +54,7 @@ var ( // - agentID: The extracted agent/session identifier // - error: ErrMissingAuthHeader if header is empty, nil otherwise func ParseAuthHeader(authHeader string) (apiKey string, agentID string, error error) { - // Sanitize header for logging (show only first 4 chars) - sanitized := "" - if len(authHeader) > 4 { - sanitized = authHeader[:4] + "..." - } else if len(authHeader) > 0 { - sanitized = "..." - } - log.Printf("Parsing auth header: sanitized=%s, length=%d", sanitized, len(authHeader)) + log.Printf("Parsing auth header: sanitized=%s, length=%d", sanitizeForLogging(authHeader), len(authHeader)) if authHeader == "" { log.Print("Auth header missing, returning error") diff --git a/internal/auth/header_test.go b/internal/auth/header_test.go index c95c8cbd8..583cf2205 100644 --- a/internal/auth/header_test.go +++ b/internal/auth/header_test.go @@ -4,6 +4,53 @@ import ( "testing" ) +func TestSanitizeForLogging(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "Empty string", + input: "", + want: "", + }, + { + name: "Single character", + input: "a", + want: "...", + }, + { + name: "Four characters", + input: "abcd", + want: "...", + }, + { + name: "Five characters", + input: "abcde", + want: "abcd...", + }, + { + name: "Long string", + input: "my-secret-api-key-12345", + want: "my-s...", + }, + { + name: "API key with Bearer prefix", + input: "Bearer my-token-123", + want: "Bear...", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := sanitizeForLogging(tt.input); got != tt.want { + t.Errorf("sanitizeForLogging() = %v, want %v", got, tt.want) + } + }) + } +} + func TestParseAuthHeader(t *testing.T) { tests := []struct { name string