Appearance
Code review โ deploy-time prod web config injection (GAC-48) โ
- Branch:
ci/gac-48-web-env-injectโmaster - Date: 2026-07-14
- Scope: 1 commit, 2 files (+85) โ new
scripts/inject-web-env.mjs,deploy.ymlweb-job wiring - Reviewer: code-reviewer agent over
git diff master...HEAD, synthesized.
Deterministic gate โ
| Check | Result |
|---|---|
nx lint web | โ |
nx test web | โ |
coverage gate (nx test web --configuration=coverage) | โ |
nx build web | โ (run twice โ clean tree, and with injected values) |
nx affected -t lint test build --base=master | โ no projects affected (CI/scripts-only diff) |
| Go gates | n/a โ apps/api untouched |
What's in the batch โ
The code half of GAC-48 (tier C โ web build-time values). environment.prod.ts deliberately ships empty supabaseUrl / supabaseAnonKey / apiUrl; nothing filled them at deploy time, so the web job produced an unconfigured bundle. Now:
scripts/inject-web-env.mjsโ readsDISPATCH_SUPABASE_URL,DISPATCH_SUPABASE_ANON_KEY,DISPATCH_API_URL; validates (https-only URLs, JWT orsb_publishable_โฆkey shape); strips trailing slashes (consumers doapiUrl + pathjoins); rewrites the three literals inenvironment.prod.tsidempotently with an exactly-one-match guard; exits 1 loudly if anything is missing or malformed so a half-configured deploy cannot ship.deploy.ymlโ web job runs the script betweenbun installandbunx nx build web, fed from GitHub Actions repository variables (not secrets โ all three values are publishable and ship in the browser bundle by design); header comment documents them.
End-to-end verification โ
Missing vars โ exit 1 listing all three ยท http:// URL โ rejected ยท truncated anon key โ rejected ยท valid values โ exactly 3 lines changed, trailing slash stripped ยท re-run with different values โ clean overwrite (idempotent) ยท nx build web (production, fileReplacements confirmed active via defaultConfiguration) โ injected values present in dist/apps/web/browser/chunk-*.js ยท env file restored afterwards.
Findings โ
๐ด Blocking โ none. โ
๐ก Should-fix โ none. โ
๐ข Nit (resolved in-branch) โ
ANON_KEYregex looser than its comment claimed โ accepted any alnum string, so a truncated copy-paste key would pass. FIXED โ now requires three dot-separated base64url segments (JWT) orsb_publishable_+ โฅ8 chars; truncated-key rejection re-verified.
Checked and clean โ
$-in-replacement / quote-injection into the TS literal (both excluded by validation char classes, validation runs before splice); fail-loud ordering (validation precedes any file write; no continue-on-error on the step); GH Actions script-injection surface (values passed via env:, never interpolated into run:); job ordering unchanged (web needs supabase only).
Note: the VS Code Actions extension warns "Context access might be invalid" on the three vars.* references โ expected until the repository variables are created (GAC-48 ops half).
Verdict โ
Green. Deterministic gate passed, no blocking or should-fix findings, the one nit fixed and re-verified. Remaining GAC-48 work is operational (create the six Actions secrets + three repository variables, set Fly secrets, run deploy.yml, tag phase-1).