fix(ui): correct and harden config.json generation - #6870
Conversation
gen-config.sh read STRIPE_PUBLISHABLE_KEY while every other value in the file reads a SHELLHUB_* var. Deployments only ever pass the prefixed name, so the :- fallback rendered stripePublishableKey empty and Stripe Elements failed to mount at checkout. The new bats guard asserts every value in the script reads a SHELLHUB_-prefixed variable, so the whole bug class fails CI rather than just this one key. Fixes: #6865
gen-config.sh interpolated environment values straight into the JSON, so a
value carrying a quote, a backslash or a control character produced a
config.json the console could not parse at all.
The unquoted boolean fields were the sharper edge. A value such as
'false, "edition": "cloud"' appends a second "edition" key that wins at parse
time, so a community deployment could be silently promoted to cloud despite
the SHELLHUB_EDITION guard rejecting exactly that. They are now validated as
true/false rather than escaped, since neither is valid JSON otherwise.
The $!{N;ba} form in json_string is deliberate: the more familiar :a;N;$!ba
slurp makes both GNU and busybox sed print and exit on single-line input,
skipping every substitution after it and quietly emitting unescaped output.
|
Claude finished @otavio's task in 10m 53s —— View job Code Review CompleteReviewed 3 files across code quality, security, testing, language patterns, and architecture — no new issues found. The code looks good as-is. I verified the parts flagged in the PR body as easy to get wrong, and they hold up:
Non-blocking noteThe To request another review round, comment |
The runner ships GNU sed and tr, but gen-config.sh escapes JSON inside the alpine production image, where the octal tr ranges and the newline match in the pattern space are busybox's to interpret. A green suite on the runner said nothing about the shell that actually renders config.json in a deployment. Run the same suite a second time inside the image the Dockerfile names, so an alpine bump is covered by the same guard rather than silently widening the gap.
What
Two independent fixes to
ui/scripts/gen-config.sh, which renders the/config.jsonthe console fetches at boot. Stripe checkout works again, and the generated document is now always valid JSON.Requires https://github.com/shellhub-io/cloud/pull/2481. That PR passes the renamed variable through to the
uiservice. Merging this one alone leaves cloud deployments and local dev serving an empty key, because the compose overlay still exports the old name.Why
gen-config.shread the Stripe publishable key fromSTRIPE_PUBLISHABLE_KEY— the only unprefixed variable in the file. Theshellhub-uisecret only setsSHELLHUB_STRIPE_PUBLISHABLE_KEY, so the container never received the name the script looked for, the:-fallback renderedstripePublishableKey: "", andBillingPayment.tsxpassedstripe={null}into<Elements>. Stripe Elements never mounted and customers could not enter card details.Closes #6865
Changes
stripe key (1572693): renamed the read to
SHELLHUB_STRIPE_PUBLISHABLE_KEY, matching every other value in the file.prefix guard (1572693):
tests/ui/gen-config.batsasserts that every value in the script reads aSHELLHUB_-prefixed variable. This is the point of the test file — it fails the whole bug class rather than this one key.EDITIONandOUTPUTare exempt because the script assigns them itself.CI (1572693): a
gen-configjob inscript-tests.yml, mirroring the existingis-latest-tagjob (pinned SHAs, paths-filter, draft guard).Unrelated pre-existing bug, second commit
4f399a701is not part of #6865. It was found while reviewing the first commit and is kept separate so it can be reviewed, or dropped, on its own.Values were interpolated straight into the JSON, so a quote, backslash or control character produced a
config.jsonthe console could not parse at all. The unquoted boolean fields were the sharper edge:A second
"edition"key wins at parse time, silently promoting a community deployment to cloud despite theSHELLHUB_EDITIONguard rejecting exactly that value. Not a vulnerability — it needs control of the container's environment, and anyone with that can setSHELLHUB_EDITIONdirectly — but it defeats a check the script goes out of its way to perform.String fields are now escaped; boolean fields are validated rather than escaped, since no escaping makes a non-boolean valid in an unquoted position.
Behavioural change worth a look:
SHELLHUB_ANNOUNCEMENTSorSHELLHUB_WEB_ENDPOINTSset to anything buttrue/falsenow aborts startup instead of rendering garbage. Every declared value in the repo is alreadytrue/false, and this matches how the script already treats an invalidSHELLHUB_EDITION, but an operator with a hand-rolled.env.overridecould hit it.Testing
Two things are easy to get wrong here and worth a reviewer's attention:
json_stringuses$!{N;ba}, not the more familiar:a;N;$!ba. The familiar form makes both GNU and busyboxsedprint-and-exit on single-line input, skipping every substitution after it and emitting unescaped output — i.e. it silently fails on the common case. Verified inalpine:3.24.1, the production base image, under busyboxsh/sed/tr.",\t,\rand\nrules are not re-escaped.Beyond the bats suite, the escaping was fuzzed over 200 random values drawn from quotes, backslashes, tabs, newlines and control characters, checking every output parses: zero invalid documents.