Review of aa2ca0a found and fixed:
- re-ingest duplicated ALL edges (upsert conflicted on valid_from=now(),
never fired) — migration 007 dedupes + partial unique index on current
edges; upsert now targets it. Regression-tested.
- export was a stub that overwrote seeds/*.yaml with 11-byte "version: 1"
files — implemented real deterministic export (ontology/inventory/policy,
cognition-layer excluded); round-trip is byte-stable (tested)
- DB password leaked in startup logs (slog JSON bypasses String()) —
Config now implements slog.LogValuer; regression-tested
- docker-compose had literal '***' as DB password — env-interpolated
- uuid.New() (v4) → uuid.NewV7() per ADR-0005
- no ontology validation on ingest — internal/ontology TypeTree: abstract
instantiation rejected, relationship endpoints hierarchy-validated,
cardinality enforced in-transaction, lifecycle states checked, default
state applied (Phase 1 gate items, R3-1)
- getOrCreateEntityID swallowed non-ErrNoRows errors
- migration runner now holds a session advisory lock on one connection
- Makefile: hardcoded /opt/homebrew/bin/go → go; test-db target
Tests: 4 unit suites + 7 integration tests (env-guarded, throwaway DB per
run): migrate idempotent, seed idempotent + no dup edges, abstract/edge/
cardinality rejection, blast_radius cycle termination, export round-trip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
1.1 KiB
Go
43 lines
1.1 KiB
Go
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)
|
|
}
|
|
}
|