Skip to content

Commit 716afe4

Browse files
committed
fix: redact database credentials in startup logs
1 parent 83ae4ca commit 716afe4

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

go/core/pkg/app/app.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"fmt"
2424
"net/http"
2525
"net/http/pprof"
26+
"net/url"
2627
"os"
2728
"path/filepath"
2829
"slices"
@@ -131,6 +132,24 @@ type Config struct {
131132
}
132133
}
133134

135+
// redactedConfig is a type alias for Config without MarshalLog to avoid recursion.
136+
type redactedConfig Config
137+
138+
// MarshalLog implements logr.Marshaler to redact sensitive fields when logging.
139+
func (c Config) MarshalLog() interface{} {
140+
rc := redactedConfig(c)
141+
rc.Database.Url = redactURL(rc.Database.Url)
142+
return rc
143+
}
144+
145+
func redactURL(rawURL string) string {
146+
u, err := url.Parse(rawURL)
147+
if err != nil {
148+
return "***"
149+
}
150+
return u.Redacted()
151+
}
152+
134153
func (cfg *Config) SetFlags(commandLine *flag.FlagSet) {
135154
commandLine.StringVar(&cfg.Metrics.Addr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
136155
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")

go/core/pkg/app/app_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,64 @@ func TestMapValueWithLoadFromEnvEqualsInValue(t *testing.T) {
371371
assert.Equal(t, map[string]string{"token": "abc=def", "team": "platform"}, target)
372372
}
373373

374+
func TestRedactURL(t *testing.T) {
375+
tests := []struct {
376+
name string
377+
url string
378+
want string
379+
}{
380+
{
381+
name: "postgres URL with credentials",
382+
url: "postgres://postgres:kagent@kagent-postgresql.kagent.svc.cluster.local:5432/postgres",
383+
want: "postgres://postgres:xxxxx@kagent-postgresql.kagent.svc.cluster.local:5432/postgres",
384+
},
385+
{
386+
name: "URL without credentials",
387+
url: "postgres://kagent-postgresql.kagent.svc.cluster.local:5432/postgres",
388+
want: "postgres://kagent-postgresql.kagent.svc.cluster.local:5432/postgres",
389+
},
390+
{
391+
name: "URL with username only",
392+
url: "postgres://postgres@localhost:5432/db",
393+
want: "postgres://postgres@localhost:5432/db",
394+
},
395+
{
396+
name: "empty string",
397+
url: "",
398+
want: "",
399+
},
400+
{
401+
name: "invalid URL",
402+
url: "://invalid",
403+
want: "***",
404+
},
405+
}
406+
407+
for _, tt := range tests {
408+
t.Run(tt.name, func(t *testing.T) {
409+
got := redactURL(tt.url)
410+
assert.Equal(t, tt.want, got)
411+
})
412+
}
413+
}
414+
415+
func TestConfigMarshalLog(t *testing.T) {
416+
cfg := Config{}
417+
cfg.Database.Url = "postgres://postgres:supersecret@localhost:5432/mydb"
418+
cfg.Database.VectorEnabled = true
419+
cfg.HttpServerAddr = ":8083"
420+
421+
result := cfg.MarshalLog()
422+
rc, ok := result.(redactedConfig)
423+
assert.True(t, ok, "MarshalLog should return redactedConfig")
424+
assert.Equal(t, "postgres://postgres:xxxxx@localhost:5432/mydb", rc.Database.Url)
425+
assert.Equal(t, true, rc.Database.VectorEnabled)
426+
assert.Equal(t, ":8083", rc.HttpServerAddr)
427+
428+
// Original config should not be modified
429+
assert.Equal(t, "postgres://postgres:supersecret@localhost:5432/mydb", cfg.Database.Url)
430+
}
431+
374432
func TestLoadFromEnvIntegration(t *testing.T) {
375433
envVars := map[string]string{
376434
"METRICS_BIND_ADDRESS": ":9090",

0 commit comments

Comments
 (0)