also looking at this
fix: validate site domain before it reaches nginx server_name
#129Hardening for values that flow from the dashboard into generated server config.
domain → nginx server_name
A site's domain is member-editable and was written into the generated server_name with quote-escaping only, while its sibling aliases — same destination — was validated with isValidHostname. This closes that asymmetry:
- validate
domainonPATCH /api/sitesbefore any write, so a rejected value can't leavecloud.config.tshalf-edited - reject non-hostname tokens inside
buildNginxVhostas defense in depth, so no other path can introduce one - refuse an empty
server_nameinstead of emittingserver_name ;(invalid nginx)
The generator's check is deliberately laxer than the API's: compute-deploy falls back to domain: site.domain || siteName, so an internal site legitimately arrives as a single label (main, docs). A test pins that so the stricter API rule can't leak into the generator and break those deploys.
escapeSingle now escapes \r / \n
These values land in single-quoted TS literals in the shared, box-wide cloud.config.ts. A raw newline terminates the literal and leaves the file syntactically broken for every tenant that loads it. Escaping also keeps line-oriented sinks downstream (heredoc delimiters in the deploy script) safe from multi-line values.
Dashboard password no longer logged
The generated Basic-auth password was written to the 0600 credentials file and logged in full on every successful deploy — and deploy output outlives the deploy in CI logs, scrollback and the journal. Now logs the path. The failure path still prints it (persisting failed, so it's the only copy) but says so and tells you to rotate.
Tests
Adds test/drivers/nginx-vhost-injection.test.ts (9 tests): injection payloads rejected in both domain and aliases, whitespace/newline/;/{/} rejected, empty server_name rejected, single-label fallback still accepted, and escaping of newlines/CR/quotes/backslashes.
Baseline on main is 249 pass / 15 fail; this branch is 258 pass / 15 fail — the same 15 pre-existing module-resolution failures (@stacksjs/ts-xml, bunfig aren't installed in the checkout), no regressions.
5 changed files on the files tab, with 0 review threads.