Skip to content

fix: require S3_REGION in production + self-host all fonts (GDPR quick wins G-17, G-13) - #1387

Merged
kristofferremback merged 1 commit into
mainfrom
fix/gdpr-quick-wins
Jul 19, 2026
Merged

fix: require S3_REGION in production + self-host all fonts (GDPR quick wins G-17, G-13)#1387
kristofferremback merged 1 commit into
mainfrom
fix/gdpr-quick-wins

Conversation

@kristofferremback

@kristofferremback kristofferremback commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Problem

Two quick wins from the GDPR audit (docs/audits/gdpr-audit-2026-07.md, findings G-17 and G-13):

  • G-17: apps/backend/src/lib/env.ts defaulted S3_REGION to us-east-1 while infra/aws/ provisions only eu-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.
  • G-13: two third-party font CDNs disclosed visitor IPs. The app loaded OpenDyslexic from fonts.cdnfonts.com unconditionally 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 from fonts.googleapis.com. Every other font in the repo was already self-hosted.

Solution

S3 residency. loadConfig now throws S3_REGION is required in production, placed with the sibling production guards (CORS_ALLOWED_ORIGINS, stub-auth). The us-east-1 fallback remains for dev/test where MinIO ignores it; .env.example documents the production requirement.

Fonts. Both faces self-hosted following the existing public/fonts/ + @font-face in index.css pattern (Switzer/Commit Mono), files from Fontsource via jsDelivr full-latin (not scraped CSS — the broken-subset gotcha):

  • Frontend: 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:112js,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.
  • Backoffice: space-grotesk-{400,500,600,700}.woff2, preconnect/stylesheet links replaced with a preload of the 400 face.

No cdnfonts/googleapis/gstatic reference remains in either app (grep-verified).

Modified files

File Change
apps/backend/src/lib/env.ts Production guard: throw when S3_REGION unset (INV-11)
apps/backend/src/lib/env.test.ts New loadConfig S3 residency describe: prod throw + dev fallback
.env.example Note that S3_REGION is required in production
apps/frontend/index.html Remove fonts.cdnfonts.com stylesheet link; update font comment
apps/frontend/src/index.css Four OpenDyslexic @font-face blocks (400/700 × normal/italic)
apps/backoffice/index.html Remove Google Fonts preconnects + stylesheet; preload 400 face
apps/backoffice/src/index.css Four Space Grotesk @font-face blocks (400–700)

New files

File Purpose
apps/frontend/public/fonts/opendyslexic-*.woff2 (4) Self-hosted OpenDyslexic (~112–120 KB each, verified WOFF2)
apps/backoffice/public/fonts/space-grotesk-*.woff2 (4) Self-hosted Space Grotesk (~13 KB each, verified WOFF2)

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/.env pollution that pre-dates this PR)
  • bun run build in apps/frontend and apps/backoffice — both green; font paths in CSS match files on disk (listed side by side)
  • file on all 8 downloaded woff2 — genuine WOFF2, full-size faces (not the silent-fallback subsets from the Google-Fonts-scrape gotcha)
  • Pre-commit hooks: repo-wide lint + typecheck across all workspaces — clean
  • Visual check of dyslexic-font rendering in a live browser — not done; family name and selector are unchanged, only the source moved

🤖 PR by Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

…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>
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f483c7c8-5ae8-4491-88f2-f469724a8a92

📥 Commits

Reviewing files that changed from the base of the PR and between 3895bd0 and 5ff2640.

⛔ Files ignored due to path filters (9)
  • .env.example is excluded by !**/.env*
  • apps/backoffice/public/fonts/space-grotesk-400.woff2 is excluded by !**/*.woff2
  • apps/backoffice/public/fonts/space-grotesk-500.woff2 is excluded by !**/*.woff2
  • apps/backoffice/public/fonts/space-grotesk-600.woff2 is excluded by !**/*.woff2
  • apps/backoffice/public/fonts/space-grotesk-700.woff2 is excluded by !**/*.woff2
  • apps/frontend/public/fonts/opendyslexic-400-italic.woff2 is excluded by !**/*.woff2
  • apps/frontend/public/fonts/opendyslexic-400.woff2 is excluded by !**/*.woff2
  • apps/frontend/public/fonts/opendyslexic-700-italic.woff2 is excluded by !**/*.woff2
  • apps/frontend/public/fonts/opendyslexic-700.woff2 is excluded by !**/*.woff2
📒 Files selected for processing (6)
  • apps/backend/src/lib/env.test.ts
  • apps/backend/src/lib/env.ts
  • apps/backoffice/index.html
  • apps/backoffice/src/index.css
  • apps/frontend/index.html
  • apps/frontend/src/index.css

Comment @coderabbitai help to get the list of available commands.

@kristofferremback
kristofferremback merged commit b55c8d7 into main Jul 19, 2026
15 checks passed
@kristofferremback
kristofferremback deleted the fix/gdpr-quick-wins branch July 19, 2026 20:52
kristofferremback added a commit that referenced this pull request Jul 19, 2026
…#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>
kristofferremback added a commit that referenced this pull request Jul 19, 2026
)

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant