package tgapi import ( "errors" "fmt" "net/url" "strings" "testing" ) func TestRedactRequestLogRemovesSensitiveValues(t *testing.T) { const input = `{"secret_token":"webhook-secret","provider_token":"payment-token","nested":{"data":"passport-data","callback_data":"callback-secret"},"chat_id":42}` got := redactRequestLog([]byte(input)) for _, secret := range []string{"webhook-secret", "payment-token", "passport-data", "callback-secret"} { if strings.Contains(got, secret) { t.Errorf("redacted request contains %q: %s", secret, got) } } if !strings.Contains(got, `"chat_id":42`) { t.Errorf("redacted request lost non-sensitive field: %s", got) } } func TestRedactRequestLogOmitsInvalidJSON(t *testing.T) { const secret = "not-json-secret" got := redactRequestLog([]byte(secret)) if strings.Contains(got, secret) { t.Fatalf("invalid JSON was logged verbatim: %s", got) } } func TestResponseLogSummaryNeverContainsBody(t *testing.T) { const token = "managed-bot-token" got := responseLogSummary("getManagedBotToken", len(token)) if strings.Contains(got, token) { t.Fatalf("response summary contains response body: %s", got) } if !strings.Contains(got, "body=omitted") { t.Fatalf("response summary does not explain omission: %s", got) } } func TestRedactHTTPErrorRemovesTokenAndPreservesCause(t *testing.T) { const token = "123456:secret-token" cause := errors.New("transport failed") original := &url.Error{ Op: "Post", URL: "https://api.telegram.org/bot" + token + "/sendMessage", Err: fmt.Errorf("request for %s failed: %w", token, cause), } got := redactHTTPError(original, token) if strings.Contains(got.Error(), token) { t.Fatalf("redacted HTTP error contains bot token: %v", got) } if !errors.Is(got, cause) { t.Fatalf("redacted HTTP error lost its cause: %v", got) } var gotURLError *url.Error if !errors.As(got, &gotURLError) { t.Fatalf("redacted HTTP error lost url.Error type: %T", got) } if strings.Contains(gotURLError.Error(), token) { t.Fatalf("redacted url.Error contains bot token: %v", gotURLError) } }