id: SEC-001 title: Turnstile CAPTCHA for Public Workspace Bootstrap status: done priority: P0 effort: M depends_on: - PORT-004 tags: - security - public-exposure - workspace summary: > Require Cloudflare Turnstile verification before creating a workspace from the public welcome page on lombard.uncloud.tech. acceptance_criteria: - Welcome/bootstrap flow at / and /workspaces/bootstrap requires valid Turnstile verification before creating a workspace. - Workspace creation fails closed when the Turnstile token is missing, invalid, expired, or verification cannot be completed. - Existing users with a valid workspace cookie visiting / are redirected to their workspace without solving CAPTCHA again. - UI shows a clear user-facing retry path when CAPTCHA verification fails. - Server-side verification uses TURNSTILE_SECRET_KEY and does not trust client-side success alone. - Browser test covers protected bootstrap flow using Cloudflare Turnstile test keys in local/dev mode. technical_notes: - Use Cloudflare Turnstile only on the welcome/bootstrap flow, not on normal workspace navigation. - Keep verification in a focused server-side seam such as app/services/turnstile.py. - Use Cloudflare's published Turnstile test keys for deterministic local/browser coverage. - This story exists because the app is now publicly reachable at https://lombard.uncloud.tech. completed_notes: - Added server-side Turnstile verification seam in app/services/turnstile.py. - Changed workspace bootstrap to POST-only and redirected failures to /?captcha_error=1. - Added welcome-page Turnstile widget markup and retry UX. - Preserved a safe compatibility redirect for legacy GET /workspaces/bootstrap -> /. - Added browser and route tests covering protected bootstrap flow and invalid fake workspace paths.