Skip to content

fix(settings): treat bracketed IPv6 loopback DATABASE_URL/NATS_URL as local - #5217

Merged
pedrofrxncx merged 1 commit into
mainfrom
fix/external-url-ipv6-loopback-w2
Jul 24, 2026
Merged

fix(settings): treat bracketed IPv6 loopback DATABASE_URL/NATS_URL as local#5217
pedrofrxncx merged 1 commit into
mainfrom
fix/external-url-ipv6-loopback-w2

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Source: bug found while auditing apps/api/src/settings/resolve-config.ts fallback logic (this tick's focus area). Note: PR #5130 already covers the DUCKDB_THREADS validation gap in this file (against its pre-split apps/mesh path), so this PR targets a different, previously-unhandled gap in the same file.

Payoff: externalUrlOrNull decides whether apps/api/src/services/ensure-services.ts skips starting the embedded local Postgres/NATS (skipPostgres/skipNats). It compares URL#hostname against the bare loopback forms "localhost", "127.0.0.1", "::1" — but for a bracketed IPv6 URL like postgres://[::1]:5432/postgres, URL#hostname returns "[::1]" (brackets included), so the comparison never matches. A DATABASE_URL/NATS_URL written with an IPv6 loopback (a legitimate way to say "local") is misclassified as external, causing the app to skip booting the embedded services it actually needs and instead try to reach a service that was never started.

Failure scenario: set DATABASE_URL=postgres://[::1]:5432/postgres (or NATS_URL=nats://[::1]:4222) — resolveConfig reports externalDatabaseUrl/externalNatsUrl as non-null, ensure-services.ts sets skipPostgres/skipNats to true, and the embedded local Postgres/NATS never starts even though the URL points at localhost.

Fix: strip the brackets from parsed.hostname before comparing, so [::1] normalizes to ::1 and matches the existing loopback check. Added a regression test covering bracketed-IPv6 DATABASE_URL and NATS_URL (both now correctly resolve to null/local) plus a genuinely-remote-host case to confirm external detection still works.

Verify: cd apps/api && bun test src/settings/resolve-config.test.ts (53 pass, 0 fail).

Checks run locally: bun run fmt, bunx tsc --noEmit (apps/api workspace, clean), and the targeted test file above. Full CI validates the rest.


Summary by cubic

Fixes local URL detection for bracketed IPv6 loopback so [::1] in DATABASE_URL or NATS_URL is treated as local. This prevents skipping the embedded Postgres/NATS when using IPv6 loopback.

  • Bug Fixes
    • Strip brackets from URL.hostname before checking for loopback (localhost, 127.0.0.1, ::1).
    • Added tests for [::1] in DATABASE_URL and NATS_URL, plus a remote host case.

Written for commit ac11803. Summary will update on new commits.

Review in cubic

@pedrofrxncx
pedrofrxncx enabled auto-merge (squash) July 24, 2026 18:19
@pedrofrxncx
pedrofrxncx merged commit 4c46441 into main Jul 24, 2026
14 checks passed
@pedrofrxncx
pedrofrxncx deleted the fix/external-url-ipv6-loopback-w2 branch July 24, 2026 18:26
pedrofrxncx added a commit that referenced this pull request Jul 24, 2026
#5220)

The `deco services up/down` externalUrlOrNull had its own copy of the
external-host check, missing the bracketed-IPv6 fix landed in #5217 for
resolve-config.ts's copy. A bracketed IPv6 loopback DATABASE_URL/NATS_URL
(e.g. "postgres://[::1]:5432/postgres") kept the brackets in
`URL#hostname`, failed the bare "::1" comparison, and was wrongly treated
as external — skipping local Postgres/NATS provisioning.

Export the already-fixed, already-tested resolve-config.ts helper and
import it in services.ts instead of keeping a second copy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant