Go · 2683 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package log
4
5 import (
6 "bytes"
7 "strings"
8 "testing"
9 )
10
11 func TestNew_RedactsSecretKeys(t *testing.T) {
12 t.Parallel()
13 var buf bytes.Buffer
14 logger := New(Options{Level: "debug", Format: "json", Writer: &buf})
15
16 logger.Info(
17 "login attempt",
18 "username", "alice",
19 "password", "hunter2",
20 "otp_secret", "JBSWY3DPEHPK3PXP",
21 "authorization", "Bearer eyJhbGc",
22 )
23
24 out := buf.String()
25 for _, leak := range []string{"hunter2", "JBSWY3DPEHPK3PXP", "Bearer eyJhbGc"} {
26 if strings.Contains(out, leak) {
27 t.Errorf("redaction missed %q\nlog: %s", leak, out)
28 }
29 }
30 if !strings.Contains(out, "alice") {
31 t.Errorf("non-secret value lost: %s", out)
32 }
33 }
34
35 func TestNew_RedactsSecretValuesByMarker(t *testing.T) {
36 t.Parallel()
37 var buf bytes.Buffer
38 logger := New(Options{Level: "info", Format: "json", Writer: &buf})
39
40 logger.Info("token used", "trace_note", "saw header: Bearer eyJfoo")
41 logger.Info("pat seen", "request_path", "/api/repos?token=shithub_pat_abc123")
42 logger.Info("totp uri", "url", "otpauth://totp/...")
43
44 out := buf.String()
45 for _, leak := range []string{"eyJfoo", "shithub_pat_abc123", "otpauth://"} {
46 if strings.Contains(out, leak) {
47 t.Errorf("value-marker redaction missed %q\nlog: %s", leak, out)
48 }
49 }
50 }
51
52 func TestNew_KeepsOrdinaryValues(t *testing.T) {
53 t.Parallel()
54 var buf bytes.Buffer
55 logger := New(Options{Level: "info", Format: "json", Writer: &buf})
56 logger.Info("repo created", "owner", "alice", "name", "my-project")
57 out := buf.String()
58 if !strings.Contains(out, "alice") || !strings.Contains(out, "my-project") {
59 t.Errorf("non-secret fields dropped: %s", out)
60 }
61 }
62
63 func TestNew_StripsURLCredentials(t *testing.T) {
64 t.Parallel()
65 var buf bytes.Buffer
66 logger := New(Options{Level: "info", Format: "json", Writer: &buf})
67
68 // Non-secret-keyed value containing user:pass@host — the per-value
69 // regex strips just the userinfo, keeping host + path readable.
70 logger.Info("db", "uri", "postgres://shithub:hunter2@127.0.0.1:5432/shithub?sslmode=disable")
71 // PAT-bearing URL routes through the value-marker scrub (shithub_pat_),
72 // which is more aggressive — the whole value collapses to ***.
73 logger.Info("git remote", "remote_uri", "https://alice:shithub_pat_abcdefghijklmnopqrstuvwxyz0123456789@host.example/owner/repo.git")
74
75 out := buf.String()
76 for _, leak := range []string{"hunter2", "shithub_pat_abc", "alice:shithub_pat_"} {
77 if strings.Contains(out, leak) {
78 t.Errorf("credential leaked: %q in %s", leak, out)
79 }
80 }
81 // Generic case keeps the host so logs stay useful.
82 if !strings.Contains(out, "127.0.0.1") {
83 t.Errorf("host stripped from generic URL: %s", out)
84 }
85 }
86