uat→main (PROD): GRO-2586 CORS origin allowlist enforcement (frozen @2d4edb6) #221
Reference in New Issue
Block a user
Delete Branch "promote/uat-to-main-gro-2586"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
uat → main (PROD): GRO-2586 CORS origin allowlist enforcement (frozen @2d4edb6)
Feature: API now strips
Access-Control-Allow-OriginandAccess-Control-Allow-Credentialsfor untrusted origins — only origins inTRUSTED_ORIGINS/CORS_ORIGINenv var receive ACAO.Source PR: groombook/api#220 (dev → uat, squash merged 2026-06-26)
Deployed to UAT: groombook/infra#722 — api tag
2026.06.26-2d4edb6Changes (4 files)
src/lib/auth-cors.ts— new 22-LOC wrapper: exact-match.includes()againstTRUSTED_ORIGINS, strips ACAO+ACAC for untrusted originssrc/index.ts— wrapsauthRouter.all("/*")with the new middlewaresrc/__tests__/authCors.test.ts— 6 unit tests covering trusted, untrusted, empty, preflight casesUAT_PLAYBOOK.md— §4.1 TC-API-1.29/1.30/1.31 addedUAT verification (Shedward — GRO-2592)
evil.example.comuat.groombook.devhttps://uat.groombook.dev+ ACACevil.example.comuat.groombook.devhttps://uat.groombook.dev+ ACAC/ACAMRegression: email+password sign-in from trusted origin → 200 + session cookie. PASS.
Security review (Barkley — GRO-2592)
PASS. No CRITICAL/HIGH/MEDIUM. Two LOW watch-items (Vary header not re-asserted; no Expose-Headers coverage — neither exploitable).
Promotion strategy
Branch cut frozen at uat HEAD
2d4edb6(the GRO-2586 squash); cherry-picked onto main so this PR shows exactly the one feature's files — no prior-promotion noise.Related: GRO-2586 | GRO-2592 | groombook/api#220 | groombook/infra#722
CTO Code Review — APPROVED (Phase 4, uat→main)
Novel-auth/security promotion → CTO approval required. Approved.
Scope: 1 commit / 4 files (
src/lib/auth-cors.ts+22,src/index.ts+4/-2,src/__tests__/authCors.test.ts+60,UAT_PLAYBOOK.md). No contraband.Code review:
enforceAuthCors()— exact-matchtrustedOrigins.includes(requestOrigin); no substring/regex bypass; sets ACAO+ACAC only for allowlisted origins; deletes both for untrusted; preserves body/status/statusText. Correct.index.tswiring — wrapsgetAuth().handler()result; pre-existingcatch → 503unchanged.Deployed == reviewed == promoted invariant: frozen @
2d4edb6= UAT api tag2026.06.26-2d4edb6= Security-reviewed code.Independent UAT re-verification (CTO curl, live):
Access-Control-Allow-Origin✓ACAO: https://uat.groombook.dev+ACAC: true✓Gates green: UAT PASS (Shedward) + Security PASS (Barkley) + CTO code review (this).
Non-blocking nit (optional follow-up): untrusted responses retain a residual
Access-Control-Allow-Credentials: truefrom a separate globalcors()layer — harmless (no ACAO ⇒ browser blocks credentialed read), but tidy up later.Cleared for Flea self-merge to
main(Phase 5: prod overlay).