mirror of
https://github.com/mgeeky/decode-spam-headers.git
synced 2026-02-22 05:23:31 +01:00
4.8 KiB
4.8 KiB
Phase 08: US6 — Security & Operational Readiness
This phase protects the analysis service from abuse with per-IP rate limiting and CAPTCHA challenge, exposes a health-check endpoint for monitoring, and wires all routers and middleware into the FastAPI application. The frontend displays a CAPTCHA modal when rate-limited. TDD Red-Green approach throughout.
Spec Kit Context
- Feature: 1-web-header-analyzer
- Specification: .specify/specs/1-web-header-analyzer/spec.md (NFR-11, NFR-12, NFR-15, NFR-16)
- Plan: .specify/specs/1-web-header-analyzer/plan.md
- Tasks: .specify/specs/1-web-header-analyzer/tasks.md
- API Contract: .specify/specs/1-web-header-analyzer/contracts/api.yaml (
GET /api/health,POST /api/captcha/verify) - User Story: US6 — Security & Operational Readiness
- Constitution: .specify/memory/constitution.md (TDD: P6)
Dependencies
- Requires Phase 05 completed (analysis endpoint for rate limiting to protect)
- Requires Phase 01 completed (config.py for rate limit thresholds)
Rate Limiting Design
- Mechanism: Per-IP sliding window counter (async-safe, in-memory)
- Threshold: Configurable via
config.pyenvironment variables - Response: HTTP 429 with
Retry-Afterheader and CAPTCHA challenge token - CAPTCHA: Server-generated visual noise (randomly distorted text rendered as image)
- Bypass: HMAC-signed token (5-minute expiry) returned on successful CAPTCHA solve
- Trade-off: Per-instance counters — acceptable for initial release; shared Redis store upgradeable later
Tasks
- T040 [US6] Write failing tests (TDD Red) in
backend/tests/api/test_rate_limiter.py(rate limiting triggers at threshold, 429 response with CAPTCHA challenge),backend/tests/api/test_captcha.py(challenge generation, verification, bypass token),backend/tests/api/test_health.py(health endpoint returns correct status), andfrontend/src/__tests__/CaptchaChallenge.test.tsx(render modal, display CAPTCHA image, submit answer, handle success/failure states, keyboard accessibility) - T041 [US6] Create
backend/app/middleware/rate_limiter.py— per-IP sliding window rate limiter (async-safe in-memory). Configurable limit viaconfig.py. Returns 429 with Retry-After header and CAPTCHA challenge token (NFR-11, NFR-12). Note: per-instance counters — acceptable for initial release; shared store upgradeable later. Verifytest_rate_limiter.pypasses (TDD Green) - T042 [US6] Create
backend/app/routers/captcha.py—POST /api/captcha/verifyendpoint. Server-generated visual noise CAPTCHA (randomly distorted text). Returns HMAC-signed bypass token (5-minute expiry) on success. Token exempts IP from rate limiting. Response schema inbackend/app/schemas/captcha.py. Verifytest_captcha.pypasses (TDD Green) - T043 [P] [US6] Create
frontend/src/components/CaptchaChallenge.tsx— modal on 429 response. Displays CAPTCHA image, on verification stores bypass token and retries original request. FontAwesome lock/unlock icons. Keyboard accessible (NFR-02). VerifyCaptchaChallenge.test.tsxpasses (TDD Green) - T044 [US6] Create
backend/app/schemas/health.pyandbackend/app/routers/health.py—GET /api/healthreturning status (up/degraded/down), version, uptime, scanner count (NFR-15). Verifytest_health.pypasses (TDD Green) - T045 [US6] Register all routers and middleware in
backend/app/main.py— CORS middleware (frontend origin), rate limiter, routers (analysis, tests, health, captcha). Verify stateless operation (NFR-16). Note: rate limiter per-instance state is accepted trade-off (see T041)
Completion
pytest backend/tests/api/test_rate_limiter.py backend/tests/api/test_captcha.py backend/tests/api/test_health.pyall pass- All vitest tests pass:
npx vitest run src/__tests__/CaptchaChallenge.test.tsx - Exceeding rate limit returns HTTP 429 with Retry-After header and CAPTCHA challenge
- Solving CAPTCHA returns HMAC-signed bypass token (5-minute expiry)
- Bypass token exempts IP from rate limiting on subsequent requests
GET /api/healthreturns{status, version, uptime, scannerCount}- All routers and CORS middleware are registered in
main.py - Application starts statelessly — no database, no session management. Verified
backend/app/main.pyregisters only CORS + rate limiter middleware and does not initialize any DB/session services. - CAPTCHA modal is keyboard accessible (Tab, Enter, Escape to close)
- Linting passes on both sides
- Run
/speckit.analyzeto verify consistency (attempted on 2026-02-18 in PowerShell during Auto Run iteration 00001; command not available in this environment,/speckit.analyzenot recognized: "The term '/speckit.analyze' is not recognized as a name of a cmdlet, function, script file, or executable program.")