fix(ingestion): redact password from BRAIN_PG_DSN log line
All checks were successful
CI / Lint / Test / Vet (push) Successful in 11s
CI / Mirror to GitHub (push) Successful in 4s

The previous "crude redaction" — pgDSN[:strings.IndexByte(pgDSN+"@", '@')] —
sliced up to the `@` character, which sits *after* the password in a
postgres URL, so the log line included the password in plaintext (caught
on first activation, 2026-05-18 startup log).

Use url.Parse + URL.Redacted() instead. Falls back to "postgres://***"
if parsing fails — we never log a raw DSN.
This commit is contained in:
Mathias
2026-05-19 13:04:12 +02:00
parent 7a13c75655
commit 4af1036423

View File

@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
"net/url"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@@ -24,6 +25,17 @@ import (
"github.com/mathiasbq/hyperguild/ingestion/internal/watcher" "github.com/mathiasbq/hyperguild/ingestion/internal/watcher"
) )
// redactDSN parses a Postgres URL and replaces its password with `***`
// for safe inclusion in logs. Falls back to a non-leaking placeholder
// if parsing fails — we never log a raw DSN.
func redactDSN(dsn string) string {
u, err := url.Parse(dsn)
if err != nil || u.User == nil {
return "postgres://***"
}
return u.Redacted()
}
// vectorAdapter bridges *vectorstore.PGStore (returns []vectorstore.Hit) // vectorAdapter bridges *vectorstore.PGStore (returns []vectorstore.Hit)
// to the search.VectorSearcher interface (which uses []search.VectorHit). // to the search.VectorSearcher interface (which uses []search.VectorHit).
// Kept here, not in either package, so neither has to import the other. // Kept here, not in either package, so neither has to import the other.
@@ -126,7 +138,7 @@ func main() {
mcpSrv = mcpSrv.WithHybridRetrieval(vectorAdapter{s: store}, embedder) mcpSrv = mcpSrv.WithHybridRetrieval(vectorAdapter{s: store}, embedder)
h.WithEmbedSync(store, embedder) h.WithEmbedSync(store, embedder)
logger.Info("brain hybrid retrieval enabled", logger.Info("brain hybrid retrieval enabled",
"pg", pgDSN[:strings.IndexByte(pgDSN+"@", '@')], // crude redaction "pg", redactDSN(pgDSN),
"embed_url", embedURL, "embed_model", embedModel) "embed_url", embedURL, "embed_model", embedModel)
case pgDSN == "" && embedURL == "": case pgDSN == "" && embedURL == "":
// disabled — fine // disabled — fine