Skip to content

Commit c6b1917

Browse files
committed
Redact passwords from connection strings in error logs
Add redactConnectionString() to scrub credentials before logging, handling both MySQL DSN (user:pass@tcp) and PostgreSQL URL (postgres://user:pass@host) formats.
1 parent c7137bc commit c6b1917

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

internal/asherah/asherah.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func NewMetastore(opts *Options) appencryption.Metastore {
133133
}
134134
db, err := newConnection(dbType, opts.ConnectionString)
135135
if err != nil {
136-
log.ErrorLogf("PANIC: Failed to connect to %s database with connection string: %v", dbType, err.Error())
136+
log.ErrorLogf("PANIC: Failed to connect to %s database (connection: %s): %v", dbType, redactConnectionString(opts.ConnectionString), err.Error())
137137
panic(fmt.Errorf("failed to connect to %s database: %w", dbType, err))
138138
}
139139

internal/asherah/database.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ package asherah
22

33
import (
44
"database/sql"
5+
"regexp"
6+
"strings"
57

68
_ "github.com/go-sql-driver/mysql"
79
_ "github.com/lib/pq"
810
)
911

12+
var mysqlDSNPasswordRegexp = regexp.MustCompile(`^([^:]+):[^@]+@`)
13+
1014
const (
1115
ReplicaReadConsistencyQuery = "SET aurora_replica_read_consistency = ?"
1216
ReplicaReadConsistencyValueEventual = "eventual"
@@ -30,6 +34,22 @@ func newConnection(dbdriver string, connStr string) (*sql.DB, error) {
3034
return dbconnection, nil
3135
}
3236

37+
func redactConnectionString(connStr string) string {
38+
// URL-style: scheme://user:pass@host/db
39+
if idx := strings.Index(connStr, "://"); idx >= 0 {
40+
rest := connStr[idx+3:]
41+
if atIdx := strings.Index(rest, "@"); atIdx >= 0 {
42+
userInfo := rest[:atIdx]
43+
if colonIdx := strings.Index(userInfo, ":"); colonIdx >= 0 {
44+
return connStr[:idx+3] + userInfo[:colonIdx] + ":***@" + rest[atIdx+1:]
45+
}
46+
}
47+
return connStr
48+
}
49+
// MySQL DSN-style: user:pass@tcp(host)/db
50+
return mysqlDSNPasswordRegexp.ReplaceAllString(connStr, "${1}:***@")
51+
}
52+
3353
func setRdbmsReplicaReadConsistencyValue(value string) (err error) {
3454
if dbconnection != nil {
3555
switch value {

internal/asherah/database_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package asherah
2+
3+
import "testing"
4+
5+
func TestRedactConnectionStringMysqlWithPassword(t *testing.T) {
6+
result := redactConnectionString("user:secret@tcp(localhost:3306)/db")
7+
expected := "user:***@tcp(localhost:3306)/db"
8+
if result != expected {
9+
t.Errorf("Expected %q, got %q", expected, result)
10+
}
11+
}
12+
13+
func TestRedactConnectionStringMysqlWithoutPassword(t *testing.T) {
14+
result := redactConnectionString("user@tcp(localhost:3306)/db")
15+
expected := "user@tcp(localhost:3306)/db"
16+
if result != expected {
17+
t.Errorf("Expected %q, got %q", expected, result)
18+
}
19+
}
20+
21+
func TestRedactConnectionStringPostgresWithPassword(t *testing.T) {
22+
result := redactConnectionString("postgres://user:secret@localhost:5432/db")
23+
expected := "postgres://user:***@localhost:5432/db"
24+
if result != expected {
25+
t.Errorf("Expected %q, got %q", expected, result)
26+
}
27+
}
28+
29+
func TestRedactConnectionStringPostgresWithoutPassword(t *testing.T) {
30+
result := redactConnectionString("postgres://user@localhost:5432/db")
31+
expected := "postgres://user@localhost:5432/db"
32+
if result != expected {
33+
t.Errorf("Expected %q, got %q", expected, result)
34+
}
35+
}
36+
37+
func TestRedactConnectionStringEmpty(t *testing.T) {
38+
result := redactConnectionString("")
39+
if result != "" {
40+
t.Errorf("Expected empty string, got %q", result)
41+
}
42+
}

0 commit comments

Comments
 (0)