Add security regression tests for all hardening fixes
- New: test_security_headers.py — verify all headers present, HSTS conditional on HTTPS - New: test_passkey_error_handling.py — generic vs user-facing error messages - New: test_poi_validation.py — field length and coordinate range constraints - Extend test_rate_limiter.py — client IP depth selection, in-memory fallback enforcement - Extend test_models.py — sqm range validation - Extend test_task_service.py — IDOR 404, ownership 200, traceback suppression in production
This commit is contained in:
parent
727dd537ef
commit
492921424e
6 changed files with 365 additions and 0 deletions
56
tests/unit/test_security_headers.py
Normal file
56
tests/unit/test_security_headers.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""Unit tests for api/security_headers.py."""
|
||||
from starlette.testclient import TestClient
|
||||
from starlette.applications import Starlette
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse
|
||||
from starlette.routing import Route
|
||||
|
||||
from api.security_headers import SecurityHeadersMiddleware
|
||||
|
||||
|
||||
async def _ok_endpoint(request: Request) -> JSONResponse:
|
||||
return JSONResponse({"ok": True})
|
||||
|
||||
|
||||
def _build_app() -> Starlette:
|
||||
app = Starlette(routes=[Route("/test", _ok_endpoint)])
|
||||
app.add_middleware(SecurityHeadersMiddleware)
|
||||
return app
|
||||
|
||||
|
||||
class TestSecurityHeaders:
|
||||
"""Tests for SecurityHeadersMiddleware."""
|
||||
|
||||
def test_x_content_type_options(self) -> None:
|
||||
client = TestClient(_build_app())
|
||||
resp = client.get("/test")
|
||||
assert resp.headers["X-Content-Type-Options"] == "nosniff"
|
||||
|
||||
def test_x_frame_options(self) -> None:
|
||||
client = TestClient(_build_app())
|
||||
resp = client.get("/test")
|
||||
assert resp.headers["X-Frame-Options"] == "DENY"
|
||||
|
||||
def test_referrer_policy(self) -> None:
|
||||
client = TestClient(_build_app())
|
||||
resp = client.get("/test")
|
||||
assert resp.headers["Referrer-Policy"] == "strict-origin-when-cross-origin"
|
||||
|
||||
def test_content_security_policy(self) -> None:
|
||||
client = TestClient(_build_app())
|
||||
resp = client.get("/test")
|
||||
assert "Content-Security-Policy" in resp.headers
|
||||
csp = resp.headers["Content-Security-Policy"]
|
||||
assert "default-src 'self'" in csp
|
||||
assert "frame-ancestors 'none'" in csp
|
||||
|
||||
def test_hsts_set_for_https(self) -> None:
|
||||
client = TestClient(_build_app())
|
||||
resp = client.get("/test", headers={"x-forwarded-proto": "https"})
|
||||
assert "Strict-Transport-Security" in resp.headers
|
||||
assert "max-age=" in resp.headers["Strict-Transport-Security"]
|
||||
|
||||
def test_hsts_not_set_for_http(self) -> None:
|
||||
client = TestClient(_build_app())
|
||||
resp = client.get("/test")
|
||||
assert "Strict-Transport-Security" not in resp.headers
|
||||
Loading…
Add table
Add a link
Reference in a new issue