fix(storage): redact credentials in driver errors + advisory lock (FED-M1-10) #479
Reference in New Issue
Block a user
Delete Branch "feat/federation-m1-security-review"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
FED-M1-10 — Independent security review of the federation tier code (migration script + tier detector). Two review rounds surfaced 7 distinct findings; all addressed in this PR.
Security findings (all fixed)
1. Credential leak via driver error messages (HIGH)
postgresandioredispackages embed full DSN strings (user:password@host) in connection errors. Those messages were being captured raw in:migrate-tier.tsper-table catch block (re-thrown to caller)tier-detection.tsprobePostgresMeasured / probePgvectorMeasured / probeValkeyMeasured (surfaced inTierHealthReport.services[].error.message— emitted as JSON bymosaic gateway doctor --json)cli.tsstorage status reachability check + migrate-tier outer catchThe doctor JSON path was the most exposed surface: any monitoring pipeline ingesting it would have collected production credentials.
Fix: New internal helper
packages/storage/src/redact-error.ts:Covers postgres / postgresql / redis / rediss. Case-insensitive. Idempotent. NOT exported from package public surface. 10 unit tests covering all schemes, multi-URL strings, no-creds variants, and case sensitivity.
2. No advisory lock on
migrate-tier(LOW-MEDIUM)Two concurrent invocations against the same target both passed
checkTargetPreconditions(non-atomic) and proceeded, racing on row counts and defeating the non-empty guard.Fix:
PostgresMigrationTargetnow exposestryAcquireAdvisoryLock()andreleaseAdvisoryLock()using session-scopedpg_try_advisory_lock(hashtext('mosaic-migrate-tier')).runMigrateTieracquires the lock before preflight, releases infinally. PG releases automatically on session end. Dry-run skips lock acquisition. Non-blocking — fails fast with a clear message if held.3. SKIP_TABLES rationale (advisory)
Comment expanded to document:
sessions,verifications,admin_tokensare skipped (TTL'd / one-time / env-bound)accounts(OAuth tokens) andprovider_credentials(AI provider keys) are NOT skipped — they are durable user-bound credentials, not deployment-bound. Operators migrating to a shared/multi-tenant federated tier should review whether to wipe these manually post-migration.Process notes
Verification
Quality gates: typecheck PASS · lint PASS · format:check PASS
Test plan
mosaic storage migrate-tieragainst a closed PG port; confirm error has no DSNRefs #460
Independent two-round security review surfaced credential leak vectors and a concurrency footgun in the federation tier code. All findings addressed: Credential redaction (HIGH): - New packages/storage/src/redact-error.ts strips user:password from postgres://, postgresql://, redis://, rediss:// URLs (case-insensitive, global). Internal — not exported from package index. - Applied to: migrate-tier inner catch, tier-detection postgres+pgvector+ valkey probe error fields, cli.ts storage status + migrate-tier outer catch. The TierHealthReport JSON emitted by `mosaic gateway doctor --json` no longer leaks DSNs to monitoring pipelines. - 10 unit tests covering both schemes, multi-URL, no-creds, case variants. Advisory lock for migrate-tier (LOW-MEDIUM): - PostgresMigrationTarget gains tryAcquireAdvisoryLock / releaseAdvisoryLock using session-scoped pg_try_advisory_lock with key hashtext('mosaic-migrate-tier'). Non-blocking — fails fast with a clear message if another invocation is in progress. Released in finally; PG releases automatically on session end. Dry-run skips lock acquisition. SKIP_TABLES rationale (advisory): - Comment expanded to document why sessions/verifications/admin_tokens are skipped AND why accounts/provider_credentials are intentionally migrated (durable user-bound credentials). Operators migrating to a shared/multi-tenant federated tier should review whether to wipe these manually post-migration. Tests: 95 storage tests pass + 1 integration test skipped (FEDERATED_INTEGRATION). Refs #460