Skip to content

fix(guided-setup): keep DATABASE_URL_APP empty, harden .env encoding & proxy trust#2616

Merged
ToddHebebrand merged 1 commit into
mainfrom
fix/guided-setup-db-url-env-roundtrip
Jul 18, 2026
Merged

fix(guided-setup): keep DATABASE_URL_APP empty, harden .env encoding & proxy trust#2616
ToddHebebrand merged 1 commit into
mainfrom
fix/guided-setup-db-url-env-roundtrip

Conversation

@ToddHebebrand

Copy link
Copy Markdown
Collaborator

Problem

The guided installer wrote DATABASE_URL_APP as a localhost value, but the bundled docker-compose.yml passes DATABASE_URL_APP straight through to the api container (${DATABASE_URL_APP:-}). So the unprivileged request pool dialed 127.0.0.1 inside the container and crashed at seed/startup with ECONNREFUSED. (DATABASE_URL is fine because compose rebuilds it as …@postgres in-container.)

Fix: leave DATABASE_URL_APP empty so the API derives the breeze_app URL from the container's @postgres DATABASE_URL. Multi-host/HA deployments still set it explicitly by hand.

Additional hardening (surfaced during review)

  • TRUST_PROXY_HEADERS: write true (was false), leaving TRUSTED_PROXY_CIDRS empty so compose re-defaults to the pinned Caddy peer (${BREEZE_CADDY_IP:-172.31.0.10}/32). false made the API attribute every request to Caddy's container IP — collapsing per-IP rate limiting, partner/admin IP allowlists, and audit IP attribution (SR2-16; locked by proxyTrustCompose.test.ts).
  • External-proxy same-host CIDR: now derives the docker bridge gateway (.1 of BREEZE_DOCKER_SUBNET, default 172.31.0.1) instead of 127.0.0.1, which matched nothing inside the container (packets are NAT'd to the bridge gateway). Uses parameter expansion, not BASH_REMATCH — that's unreliable on macOS bash 3.2.
  • .env value encoding: format_env_value single-quotes values without a single quote, else double-quotes and escapes \ " $ \``; strip_wrapping_quotesis the exact inverse (sentinel-protected backslash).get_env_valueonly strips inline#comments on **unquoted** values;set_env_valuepasses the value viaENVIRON, not awk -v(which mangled backslashes). Previously a', space + #, `, or $ in an admin display name or password aborted setup.
  • start_stack: checks compose pull / compose up -d exit codes; STACK_STARTED set only on success.
  • is_postgres_identifier validates POSTGRES_USER / POSTGRES_DB so both the host .env URL and the compose-built container URL stay well-formed.
  • Credential-backup chmod 600 now fails loudly; on_exit sweeps stranded atomic-write temp files (which can hold secrets).

Tests

Two new CI guards, wired into the existing Guard guided setup behavior step:

  • check-guided-setup-db-urls.shDATABASE_URL_APP is empty and TRUST_PROXY_HEADERS is never false.
  • check-guided-setup-env-roundtrip.sh — behavioral .env round-trip over 14 adversarial values (including O'Brien, pass #1, back\slash, a'b\c"d`e$f which exercises the double-quote escape branch). Verified non-vacuous: it fails against the pre-change encoder and against asymmetric mutations of the encode/decode pair, and is green on the fix.

All four guided-setup guards pass; bash -n and shellcheck clean.

🤖 Generated with Claude Code

…& proxy trust

The guided installer wrote DATABASE_URL_APP as a localhost value, but the
bundled docker-compose.yml passes DATABASE_URL_APP straight through to the api
container (`${DATABASE_URL_APP:-}`), so the unprivileged request pool dialed
127.0.0.1 inside the container and crashed at seed with ECONNREFUSED. Leave it
empty so the API derives the breeze_app URL from the container's @postgres
DATABASE_URL.

Additional hardening surfaced during review:
- TRUST_PROXY_HEADERS: write true (was false), leaving TRUSTED_PROXY_CIDRS empty
  so compose re-defaults to the pinned Caddy peer. false collapsed per-IP rate
  limiting, IP allowlists, and audit attribution (SR2-16).
- External-proxy same-host CIDR now derives the docker bridge gateway (.1 of
  BREEZE_DOCKER_SUBNET, default 172.31.0.1) instead of 127.0.0.1, which matched
  nothing inside the container. Uses parameter expansion, not BASH_REMATCH
  (unreliable on macOS bash 3.2).
- .env value encoding: format_env_value single-quotes values without a single
  quote, else double-quotes and escapes \ " $ `; strip_wrapping_quotes is the
  exact inverse (sentinel-protected backslash). get_env_value only strips inline
  comments on unquoted values; set_env_value passes the value via ENVIRON, not
  awk -v, which mangled backslashes. Previously ', space+#, \, and $ aborted setup.
- start_stack checks `compose pull` / `up -d` exit codes; STACK_STARTED only on
  success.
- is_postgres_identifier validates POSTGRES_USER/POSTGRES_DB so both the host and
  container URLs stay well-formed.
- Guard credential-backup chmod 600 loudly; on_exit sweeps stranded temp files.

Adds two CI guards (wired into the "Guard guided setup behavior" step):
check-guided-setup-db-urls.sh (DATABASE_URL_APP empty, TRUST_PROXY_HEADERS never
false) and check-guided-setup-env-roundtrip.sh (behavioral .env round-trip over
14 adversarial values, incl. one exercising the double-quote escape branch).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying breeze with  Cloudflare Pages  Cloudflare Pages

Latest commit: 84eddd6
Status: ✅  Deploy successful!
Preview URL: https://26996e11.breeze-9te.pages.dev
Branch Preview URL: https://fix-guided-setup-db-url-env.breeze-9te.pages.dev

View logs

@ToddHebebrand
ToddHebebrand merged commit 6c10e4a into main Jul 18, 2026
49 checks passed
@ToddHebebrand
ToddHebebrand deleted the fix/guided-setup-db-url-env-roundtrip branch July 18, 2026 20:33
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