Skip to content

Commit aae6e9e

Browse files
Merge pull request #14 from CoreyLeath-code/fix/require-production-api-key
Require API key for production serving
2 parents c9a335c + 3ee4a37 commit aae6e9e

3 files changed

Lines changed: 28 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ API_KEY='replace-me' \
162162
uvicorn app.main:app --host 0.0.0.0 --port 8000
163163
```
164164

165+
In production, `API_KEY` is mandatory. When it is unset, recommendation and feedback requests return HTTP 503 so a deployment cannot silently expose unauthenticated endpoints. Development intentionally permits an unset key for local smoke tests.
166+
165167
```bash
166168
curl -X POST http://localhost:8000/recommendations/ \
167169
-H 'Content-Type: application/json' \

‎app/api/routes.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ class FeedbackRequest(BaseModel):
8989

9090

9191
def _authorize(api_key: str | None) -> None:
92+
"""Enforce configured authentication for production recommendation traffic."""
93+
94+
if settings.environment.lower() == "production" and not settings.api_key:
95+
raise HTTPException(status_code=503, detail="Production API key is not configured")
9296
if not api_key_is_valid(api_key, settings.api_key):
9397
raise HTTPException(status_code=401, detail="Invalid API key")
9498

‎tests/test_serving_controls.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import pytest
2+
from fastapi import HTTPException
3+
4+
from app.api.routes import _authorize
5+
from app.core.config import settings
16
from app.core.security import api_key_is_valid
27
from app.core.serving import RateLimiter, RecommendationCache
38

@@ -22,3 +27,20 @@ def test_api_key_validation() -> None:
2227
assert api_key_is_valid(None, None) is True
2328
assert api_key_is_valid("correct", "correct") is True
2429
assert api_key_is_valid("wrong", "correct") is False
30+
31+
32+
def test_production_without_api_key_fails_closed(monkeypatch) -> None:
33+
monkeypatch.setattr(settings, "environment", "production")
34+
monkeypatch.setattr(settings, "api_key", None)
35+
36+
with pytest.raises(HTTPException) as error:
37+
_authorize(None)
38+
39+
assert error.value.status_code == 503
40+
41+
42+
def test_development_without_api_key_remains_open(monkeypatch) -> None:
43+
monkeypatch.setattr(settings, "environment", "development")
44+
monkeypatch.setattr(settings, "api_key", None)
45+
46+
_authorize(None)

0 commit comments

Comments
 (0)