package config import ( "bytes" "log/slog" "strings" "testing" ) func secretConfig() Config { c := Default() c.DatabaseURL = "postgres://oikos:supersecretpw@localhost:5432/oikos" c.MCPBearerToken = "supersecrettoken" return c } func TestStringRedactsSecrets(t *testing.T) { s := secretConfig().String() for _, leak := range []string{"supersecretpw", "supersecrettoken"} { if strings.Contains(s, leak) { t.Errorf("String() leaks %q: %s", leak, s) } } } // TestSlogJSONRedactsSecrets guards the bug where slog's JSON handler // serialized Config struct fields directly, bypassing String() and leaking // the DB password into logs. func TestSlogJSONRedactsSecrets(t *testing.T) { var buf bytes.Buffer logger := slog.New(slog.NewJSONHandler(&buf, nil)) logger.Info("starting", "config", secretConfig()) out := buf.String() for _, leak := range []string{"supersecretpw", "supersecrettoken"} { if strings.Contains(out, leak) { t.Errorf("slog JSON output leaks %q: %s", leak, out) } } if !strings.Contains(out, "***") { t.Errorf("expected redaction marker in log output: %s", out) } }