feat(server): BEE-1794 enable CORS for browser clients#6
Merged
Conversation
Drogon doesn't ship CORS middleware. The beepbox-server image deployed
to Cloud Run was rejecting every browser preflight (OPTIONS without
Access-Control-Allow-Origin) → BEE-1686 Commlink track encode step
broken end-to-end:
Access to fetch at '.../v1/encode' from origin 'http://localhost:3000'
has been blocked by CORS policy: Response to preflight request doesn't
pass access control check: No 'Access-Control-Allow-Origin' header is
present on the requested resource.
This commit adds a self-contained CORS module:
include/beepbox/CorsConfig.h
src/CorsConfig.cpp # Pure parsing + origin resolution (no Drogon)
src/CorsAdvice.cpp # Drogon preRoutingAdvice + postHandlingAdvice
Split exists so unit tests link only the pure logic file (no Drogon
runtime needed) — keeps the test suite fast.
Behaviour:
- Whitelist comes from BEEPBOX_CORS_ALLOWED_ORIGINS env var (CSV).
Empty / unset → CORS disabled, request pipeline behaves identically
to pre-1794 server-to-server-only mode.
- PreRoutingAdvice intercepts OPTIONS *before* the auth filter, so
the browser preflight (no Bearer) gets a 204 with the four
Access-Control-* headers without tripping the API key gate.
- PostHandlingAdvice stamps Access-Control-Allow-Origin + Vary: Origin
on every non-OPTIONS response when the request `Origin` matches the
whitelist. No-op for callers without an `Origin` header → server-to-
server flows unchanged.
- Exact-match origins only — no wildcards, no scheme coercion. RFC
6454 verbatim comparison (case-sensitive on host).
Server startup logs the active whitelist (or "CORS disabled") for
observability.
Infra:
infra/cloud-run.tf # Pipes the env var into Cloud Run
infra/variables.tf # New `cors_allowed_origins` variable
infra/terraform.tfvars.example # Documents dev defaults
Tests: 3 new test cases / 23 new assertions (parseAllowedOrigins · CSV
trimming + order preservation · whitelist resolution including verbatim
mismatch on scheme/port/case · enabled() flag). Full suite:
85 / 85 (was 82 → +3). beepbox-server build clean, smoke-tested
locally with `curl -X OPTIONS -H "Origin: http://localhost:3000"
http://localhost:8080/v1/encode` → 204 + all four headers; same with
`Origin: https://evil.com` → 204 with no CORS headers (browser blocks).
Closes BEE-1794. Unblocks BEE-1686.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
BEEPBOX_CORS_ALLOWED_ORIGINSenv var; empty = CORS off (server-to-server flows unchanged).Closes BEE-1794. Unblocks BEE-1686 (Commlink track encode step blocked on missing CORS preflight headers).
Test plan
🤖 Generated with Claude Code