geocrop-platform./apps/nextgen/.harness/changelogs/2026-07-16-p0-security.md

2.8 KiB

2026-07-16 — P0 security (WT-A)

Closes the deployment-readiness P0s for auth, CORS, body size, hygiene, and client-side secret handling.

Files changed

New:

  • server/src/config/index.js — single source of truth for env-derived config. Crashes on missing required vars in production.
  • server/scripts/lint-no-backups.jsnpm run lint:hygiene fails if any *.bak / *.orig / *~ is staged.
  • server/scripts/refactor-jwt-secret.js — one-shot script that rewrote 56 files.
  • server/scripts/smoke-test.js — post-change smoke test (health, login, offline secret, me/credentials, 2MB body rejection).
  • server/.env.example — documents all env vars with required-in-prod set.
  • .harness/changelogs/2026-07-16-p0-security.md — this file.

Modified (56 server files):

  • All controllers (54) + server/src/index.js + server/src/services/wsHub.js no longer hardcode 'africa-alert-secret-key-2024'. They import const { jwtSecret: JWT_SECRET } = require('../config') (or './config' for index.js).
  • server/src/index.js: CORS restricted to ALLOWED_ORIGINS in prod (permissive in dev). JSON body limit dropped to 1mb. Added /api/health endpoint + 413 error handler for entity.too.large.
  • client/src/lib/offlineAuth.ts: OFFLINE_JWT_SECRET now sourced from localStorage (populated at login from the new offline_jwt_secret response field). Dev fallback only in import.meta.env.DEV; null in prod unless ALLOW_CLIENT_OFFLINE_MINT=true.
  • client/src/store/auth.ts: captures offline_jwt_secret from /api/auth/login response and caches it via cacheOfflineJwtSecret.
  • server/package.json: new scripts lint:hygiene and refactor:jwt-secret.
  • README.md: production security checklist section.

Deleted:

  • server/src/controllers/sync.controller.js.bak (6045 bytes).

Verification

Smoke test (node server/scripts/smoke-test.js):

  • GET /api/health → 200
  • POST /api/auth/login returns token + offline_jwt_secret
  • GET /api/auth/me/credentials (with token) → 200
  • ✓ 2MB JSON body → 413 (was 500 before the error handler)
  • 5/5 checks pass

Regression net: 14/14 Playwright E2E specs green (cd client && npx playwright test).

Hygiene: npm run lint:hygiene → "OK — no .bak / .orig / ~ files in server/src or client/src".

Select-String -Path 'server\src' -Pattern "'africa-alert-secret-key-2024'" → 0 matches. Select-String -Path 'client\src' -Pattern "OFFLINE_JWT_SECRET\s*=\s*'africa-alert" → 0 matches.

Known follow-ups (deferred to WT-B, WT-C)

  • WT-B (offline cache) is independent and should land before the next deploy.
  • WT-C (docker) will add HEALTHCHECK that hits /api/health (already present now).
  • The dev fallback string dev-only-insecure-secret-do-not-use-in-production is intentional; the prod crash on missing JWT_SECRET is in server/src/config/index.js.