fix(guided-setup): keep DATABASE_URL_APP empty, harden .env encoding & proxy trust#2616
Merged
Merged
Conversation
…& 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>
Deploying breeze with
|
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The guided installer wrote
DATABASE_URL_APPas alocalhostvalue, but the bundleddocker-compose.ymlpassesDATABASE_URL_APPstraight through to the api container (${DATABASE_URL_APP:-}). So the unprivileged request pool dialed127.0.0.1inside the container and crashed at seed/startup withECONNREFUSED. (DATABASE_URLis fine because compose rebuilds it as…@postgresin-container.)Fix: leave
DATABASE_URL_APPempty so the API derives thebreeze_appURL from the container's@postgresDATABASE_URL. Multi-host/HA deployments still set it explicitly by hand.Additional hardening (surfaced during review)
TRUST_PROXY_HEADERS: writetrue(wasfalse), leavingTRUSTED_PROXY_CIDRSempty so compose re-defaults to the pinned Caddy peer (${BREEZE_CADDY_IP:-172.31.0.10}/32).falsemade 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 byproxyTrustCompose.test.ts)..1ofBREEZE_DOCKER_SUBNET, default172.31.0.1) instead of127.0.0.1, which matched nothing inside the container (packets are NAT'd to the bridge gateway). Uses parameter expansion, notBASH_REMATCH— that's unreliable on macOS bash 3.2..envvalue encoding:format_env_valuesingle-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, notawk -v(which mangled backslashes). Previously a',space + #,`, or$in an admin display name or password aborted setup.start_stack: checkscompose pull/compose up -dexit codes;STACK_STARTEDset only on success.is_postgres_identifiervalidatesPOSTGRES_USER/POSTGRES_DBso both the host.envURL and the compose-built container URL stay well-formed.chmod 600now fails loudly;on_exitsweeps 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.sh—DATABASE_URL_APPis empty andTRUST_PROXY_HEADERSis neverfalse.check-guided-setup-env-roundtrip.sh— behavioral.envround-trip over 14 adversarial values (includingO'Brien,pass #1,back\slash,a'b\c"d`e$fwhich 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 -nandshellcheckclean.🤖 Generated with Claude Code