fix: require S3_REGION in production + self-host all fonts (GDPR quick wins G-17, G-13) - #1387
Conversation
…k wins) Two quick wins from the GDPR audit (docs/audits/gdpr-audit-2026-07.md): - G-17: loadConfig now throws when S3_REGION is unset in production — the us-east-1 dev fallback could silently re-home attachments outside the workspace's region (INV-11). - G-13: OpenDyslexic self-hosted from public/fonts (was fonts.cdnfonts.com, fetched unconditionally for every app visitor); backoffice Space Grotesk self-hosted (was fonts.googleapis.com). No third-party font CDN remains; OpenDyslexic now also only downloads when the accessibility font is active. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 52 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (9)
📒 Files selected for processing (6)
Comment |
…#1387) (#1433) The S3_REGION-required-in-production guard (b55c8d7, G-17) throws before the four github-app production tests reach their expected assertions — they construct production env without S3_REGION, so main's Tests job has been red since the merge. Each block now sets S3_REGION; the dedicated 'requires S3_REGION in production' test still deletes it and pins the guard itself. 25/25 pass (run without the stray local apps/backend/.env, per the documented gotcha). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
) Semantic merge collision on main: #1387 added the production S3_REGION guard while the GitHub multi-install work added four production-mode loadConfig tests that don't set it — green independently, red together (guard throws before the GitHub checks those tests assert). Fixture-only fix; both guards keep their coverage. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Problem
Two quick wins from the GDPR audit (docs/audits/gdpr-audit-2026-07.md, findings G-17 and G-13):
apps/backend/src/lib/env.tsdefaultedS3_REGIONtous-east-1whileinfra/aws/provisions onlyeu-north-1— a missing env var in production would silently re-home attachments and avatars to a US region. Violates INV-11 (no silent fallback defaults) with a data-residency consequence.fonts.cdnfonts.comunconditionally for every visitor (the pattern targeted by the German Google-Fonts rulings), even though the accessibility font is opt-in; the backoffice loaded Space Grotesk fromfonts.googleapis.com. Every other font in the repo was already self-hosted.Solution
S3 residency.
loadConfignow throwsS3_REGION is required in production, placed with the sibling production guards (CORS_ALLOWED_ORIGINS, stub-auth). Theus-east-1fallback remains for dev/test where MinIO ignores it;.env.exampledocuments the production requirement.Fonts. Both faces self-hosted following the existing
public/fonts/+@font-faceinindex.csspattern (Switzer/Commit Mono), files from Fontsource via jsDelivr full-latin (not scraped CSS — the broken-subset gotcha):opendyslexic-{400,700}{,-italic}.woff2, family name"OpenDyslexic"unchanged so[data-font-family="dyslexic"](index.css:832) and the settings preview keep working. Because the family is only applied under that attribute and the SW precache glob excludes woff2 (vite.config.ts:112—js,css,html,ico,png,svg), browsers fetch the files only when the accessibility font is actually selected — the old CDN CSS was fetched by everyone.space-grotesk-{400,500,600,700}.woff2, preconnect/stylesheet links replaced with a preload of the 400 face.No
cdnfonts/googleapis/gstaticreference remains in either app (grep-verified).Modified files
apps/backend/src/lib/env.tsS3_REGIONunset (INV-11)apps/backend/src/lib/env.test.tsloadConfig S3 residencydescribe: prod throw + dev fallback.env.exampleS3_REGIONis required in productionapps/frontend/index.htmlfonts.cdnfonts.comstylesheet link; update font commentapps/frontend/src/index.css@font-faceblocks (400/700 × normal/italic)apps/backoffice/index.htmlapps/backoffice/src/index.css@font-faceblocks (400–700)New files
apps/frontend/public/fonts/opendyslexic-*.woff2(4)apps/backoffice/public/fonts/space-grotesk-*.woff2(4)Out of scope (deliberate)
The other audit G-items (erasure, transparency, OpenRouter pinning, Langfuse masking) — these are the P0/P1 builds, not quick wins. Giphy's client-side CDN fetches (also G-13-adjacent) need a media proxy, not a config change.
Test plan
bun test --env-file=/dev/null src/lib/env.test.ts— 20 pass (2 new; the clean env-file sidesteps the known stray-apps/backend/.envpollution that pre-dates this PR)bun run buildinapps/frontendandapps/backoffice— both green; font paths in CSS match files on disk (listed side by side)fileon all 8 downloaded woff2 — genuine WOFF2, full-size faces (not the silent-fallback subsets from the Google-Fonts-scrape gotcha)🤖 PR by Claude Code
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.