Require explicit FORGE_API_KEY at API startup#23
Conversation
There was a problem hiding this comment.
Pull request overview
This PR tightens security for the FastAPI service by removing the insecure default API key behavior and requiring operators to explicitly configure FORGE_API_KEY (with an opt-in dev-mode fallback) before the API is considered ready.
Changes:
- Change API key initialization to
Noneand enforce startup-time validation ofFORGE_API_KEY(or explicitFORGE_DEV_MODE) instartup_event. - Add an auth readiness guard to return
503until the API key is configured. - Add unit tests and update docs to reflect the new required environment variable behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
api.py |
Enforces explicit API key configuration at startup; blocks auth until configured. |
tests/unit/test_api_startup_security.py |
Adds tests covering startup validation and readiness behavior. |
README.md |
Documents required FORGE_API_KEY / optional FORGE_DEV_MODE configuration. |
DEPLOYMENT.md |
Adds deployment guidance for required API environment variables. |
| async def get_api_key(api_key: str = Security(api_key_header)): | ||
| """Validate API key.""" | ||
| if not API_KEY: | ||
| raise HTTPException( | ||
| status_code=503, | ||
| detail="API key is not configured. Service is not ready." | ||
| ) |
There was a problem hiding this comment.
APIKeyHeader(..., auto_error=False) can yield None when the header is missing, but get_api_key currently types api_key as str and doesn’t explicitly handle the None case. Update the signature to accept Optional[str] (or APIKey | None) and return a clear 403/401 for missing credentials before comparing to API_KEY.
|
|
||
|
|
There was a problem hiding this comment.
Other unit tests in tests/unit/ are consistently marked with @pytest.mark.unit (e.g., tests/unit/test_utils.py). Consider marking this module/tests as unit as well (e.g., module-level pytestmark = pytest.mark.unit) so marker-based test selection remains consistent.
| pytestmark = pytest.mark.unit |
| ### API Security Configuration (Required for `api.py`) | ||
|
|
||
| When running the FastAPI service (`python api.py`), you **must** set `FORGE_API_KEY` explicitly. | ||
|
|
||
| ```bash | ||
| export FORGE_API_KEY="replace-with-a-strong-random-key" | ||
| python api.py | ||
| ``` |
There was a problem hiding this comment.
This section documents how to configure the server-side API key, but it doesn’t say how clients must present it (header name / request format). Please mention that requests must include the X-API-Key header set to the same value as FORGE_API_KEY (and how dev mode affects that), otherwise users won’t know how to authenticate.
| ### API Environment Variables (Required) | ||
|
|
||
| If you deploy or run the FastAPI service (`api.py`), configure the API key before startup: | ||
|
|
||
| ```bash | ||
| export FORGE_API_KEY="replace-with-a-strong-random-key" | ||
| python api.py | ||
| ``` |
There was a problem hiding this comment.
Like the README change, this deployment section explains setting FORGE_API_KEY but doesn’t mention how clients authenticate. Add a note that callers must send X-API-Key: <FORGE_API_KEY> with API requests so operators can validate deployments end-to-end.
Motivation
FORGE_DEV_MODEis intentionally set.Description
API_KEYis initialized toNoneand populated during startup validation instartup_eventinapi.py.FORGE_API_KEY, setsAPI_KEYwhen present, and raises a clearRuntimeErrorwhen the variable is missing or empty; whenFORGE_DEV_MODEis explicitly enabled a non-productionDEV_API_KEYis used with a printed warning.get_api_keythat returns503whileAPI_KEYis not configured to prevent accepting requests before startup succeeds.README.mdandDEPLOYMENT.mdwith requiredFORGE_API_KEYsetup instructions and a clear note about the explicitFORGE_DEV_MODEopt-in for local development; added new unit tests attests/unit/test_api_startup_security.pycovering the new behaviors.Testing
pytest -q -o addopts='' tests/unit/test_api_startup_security.py, which passed (4 passed).pytestconfiguration failed due to coverage-relatedpytest.iniaddopts, so the targeted command above was used to run the new tests in isolation.Codex Task