cached gateway routing
This commit is contained in:
@@ -35,6 +35,41 @@ type envConfig struct {
|
||||
|
||||
const defaultConsumerBufferSize = 1024
|
||||
|
||||
func sanitizeNATSURL(rawURL string) string {
|
||||
if rawURL == "" {
|
||||
return rawURL
|
||||
}
|
||||
|
||||
parts := strings.Split(rawURL, ",")
|
||||
sanitized := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
trimmed := strings.TrimSpace(part)
|
||||
if trimmed == "" {
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(trimmed, "://") {
|
||||
sanitized = append(sanitized, trimmed)
|
||||
continue
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(trimmed)
|
||||
if err != nil {
|
||||
sanitized = append(sanitized, trimmed)
|
||||
continue
|
||||
}
|
||||
if parsed.User == nil {
|
||||
sanitized = append(sanitized, trimmed)
|
||||
continue
|
||||
}
|
||||
sanitized = append(sanitized, parsed.Redacted())
|
||||
}
|
||||
|
||||
if len(sanitized) == 0 {
|
||||
return strings.TrimSpace(rawURL)
|
||||
}
|
||||
return strings.Join(sanitized, ",")
|
||||
}
|
||||
|
||||
// loadEnv gathers and validates connection details from environment variables
|
||||
// listed in the Settings struct. Invalid or missing values surface as a typed
|
||||
// InvalidArgument error so callers can decide how to handle them.
|
||||
@@ -109,6 +144,7 @@ func NewNatsBroker(logger mlogger.Logger, settings *nc.Settings) (*NatsBroker, e
|
||||
}
|
||||
natsURL = u.String()
|
||||
}
|
||||
sanitizedNATSURL := sanitizeNATSURL(natsURL)
|
||||
|
||||
opts := []nats.Option{
|
||||
nats.Name(settings.NATSName),
|
||||
@@ -120,7 +156,7 @@ func NewNatsBroker(logger mlogger.Logger, settings *nc.Settings) (*NatsBroker, e
|
||||
zap.String("broker", settings.NATSName),
|
||||
}
|
||||
if conn != nil {
|
||||
fields = append(fields, zap.String("connected_url", conn.ConnectedUrl()))
|
||||
fields = append(fields, zap.String("connected_url", sanitizeNATSURL(conn.ConnectedUrl())))
|
||||
}
|
||||
if err != nil {
|
||||
fields = append(fields, zap.Error(err))
|
||||
@@ -132,7 +168,7 @@ func NewNatsBroker(logger mlogger.Logger, settings *nc.Settings) (*NatsBroker, e
|
||||
zap.String("broker", settings.NATSName),
|
||||
}
|
||||
if conn != nil {
|
||||
fields = append(fields, zap.String("connected_url", conn.ConnectedUrl()))
|
||||
fields = append(fields, zap.String("connected_url", sanitizeNATSURL(conn.ConnectedUrl())))
|
||||
}
|
||||
l.Info("Reconnected to NATS", fields...)
|
||||
}),
|
||||
@@ -142,7 +178,7 @@ func NewNatsBroker(logger mlogger.Logger, settings *nc.Settings) (*NatsBroker, e
|
||||
}
|
||||
if conn != nil {
|
||||
if url := conn.ConnectedUrl(); url != "" {
|
||||
fields = append(fields, zap.String("connected_url", url))
|
||||
fields = append(fields, zap.String("connected_url", sanitizeNATSURL(url)))
|
||||
}
|
||||
if err := conn.LastError(); err != nil {
|
||||
fields = append(fields, zap.Error(err))
|
||||
@@ -172,7 +208,7 @@ func NewNatsBroker(logger mlogger.Logger, settings *nc.Settings) (*NatsBroker, e
|
||||
}
|
||||
|
||||
if res.nc, err = nats.Connect(natsURL, opts...); err != nil {
|
||||
l.Error("Failed to connect to NATS", zap.String("url", natsURL), zap.Error(err))
|
||||
l.Error("Failed to connect to NATS", zap.String("url", sanitizedNATSURL), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
if res.js, err = res.nc.JetStream(); err != nil {
|
||||
@@ -180,7 +216,7 @@ func NewNatsBroker(logger mlogger.Logger, settings *nc.Settings) (*NatsBroker, e
|
||||
}
|
||||
|
||||
logger.Info("Connected to NATS", zap.String("broker", settings.NATSName),
|
||||
zap.String("url", natsURL))
|
||||
zap.String("url", sanitizedNATSURL))
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
||||
58
api/pkg/messaging/internal/natsb/broker_test.go
Normal file
58
api/pkg/messaging/internal/natsb/broker_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package natsb
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSanitizeNATSURL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("redacts single URL credentials", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
raw := "nats://alice:supersecret@localhost:4222"
|
||||
sanitized := sanitizeNATSURL(raw)
|
||||
|
||||
if strings.Contains(sanitized, "supersecret") {
|
||||
t.Fatalf("expected password to be redacted, got %q", sanitized)
|
||||
}
|
||||
if !strings.Contains(sanitized, "alice:xxxxx@") {
|
||||
t.Fatalf("expected redacted URL to keep username, got %q", sanitized)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("keeps URL without credentials unchanged", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
raw := "nats://localhost:4222"
|
||||
sanitized := sanitizeNATSURL(raw)
|
||||
if sanitized != raw {
|
||||
t.Fatalf("expected URL without credentials to remain unchanged, got %q", sanitized)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("redacts each URL in server list", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
raw := " nats://alice:one@localhost:4222, nats://bob:two@localhost:4223 "
|
||||
sanitized := sanitizeNATSURL(raw)
|
||||
|
||||
if strings.Contains(sanitized, "one") || strings.Contains(sanitized, "two") {
|
||||
t.Fatalf("expected passwords to be redacted, got %q", sanitized)
|
||||
}
|
||||
if !strings.Contains(sanitized, "alice:xxxxx@") || !strings.Contains(sanitized, "bob:xxxxx@") {
|
||||
t.Fatalf("expected both URLs to be redacted, got %q", sanitized)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns invalid URL as-is", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
raw := "not a url"
|
||||
sanitized := sanitizeNATSURL(raw)
|
||||
if sanitized != raw {
|
||||
t.Fatalf("expected invalid URL to remain unchanged, got %q", sanitized)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user