Add API anti-abuse hardening: disable docs in prod, origin validator, exception handler
- Disable OpenAPI docs/redoc/openapi.json when APP_ENV=production - Strip uvicorn Server header with --no-server-header in Dockerfile and docker-compose.yml - Add OriginValidatorMiddleware to reject state-changing requests from disallowed origins - Add global exception handler to prevent stack trace leakage on unhandled errors - Add tests for all new security features (OpenAPI, origin validation, exception handler, server header)
This commit is contained in:
parent
162d9a886d
commit
1ace45353a
8 changed files with 252 additions and 4 deletions
42
tests/unit/test_openapi_disabled.py
Normal file
42
tests/unit/test_openapi_disabled.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
"""Unit tests for OpenAPI docs disabled in production."""
|
||||
from unittest import mock
|
||||
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
|
||||
class TestOpenAPIDisabledInProduction:
|
||||
"""Verify docs/redoc/openapi are disabled when APP_ENV=production."""
|
||||
|
||||
def test_docs_disabled_in_production(self) -> None:
|
||||
prod_env = {
|
||||
"APP_ENV": "production",
|
||||
"OIDC_CLIENT_ID": "test-client-id",
|
||||
"JWT_SECRET": "test-secret-not-default",
|
||||
}
|
||||
with mock.patch.dict("os.environ", prod_env):
|
||||
# Re-import to pick up the new env
|
||||
import importlib
|
||||
import api.config
|
||||
importlib.reload(api.config)
|
||||
import api.app
|
||||
importlib.reload(api.app)
|
||||
app = api.app.app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
assert client.get("/docs").status_code == 404
|
||||
assert client.get("/redoc").status_code == 404
|
||||
assert client.get("/openapi.json").status_code == 404
|
||||
|
||||
def test_docs_enabled_in_dev(self) -> None:
|
||||
with mock.patch.dict("os.environ", {"APP_ENV": "dev"}):
|
||||
import importlib
|
||||
import api.config
|
||||
importlib.reload(api.config)
|
||||
import api.app
|
||||
importlib.reload(api.app)
|
||||
app = api.app.app
|
||||
|
||||
client = TestClient(app, raise_server_exceptions=False)
|
||||
# /docs should return 200 (Swagger UI) in non-production
|
||||
assert client.get("/docs").status_code == 200
|
||||
assert client.get("/openapi.json").status_code == 200
|
||||
Loading…
Add table
Add a link
Reference in a new issue