- Fix loyalty & monitoring router bugs (_get_router → named routers) - Implement team invitation email with send_template + seed templates (en/fr/de) - Add SecurityHeadersMiddleware (nosniff, HSTS, referrer-policy, permissions-policy) - Build email audit admin page: service, schemas, API, page route, menu, i18n, HTML, JS - Clean stale TODO in platform-menu-config.js - Add 67 tests (unit + integration) covering all new functionality Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
2.1 KiB
Python
56 lines
2.1 KiB
Python
# tests/unit/middleware/test_security_headers.py
|
|
"""Unit tests for SecurityHeadersMiddleware."""
|
|
|
|
import pytest
|
|
|
|
from middleware.security_headers import SecurityHeadersMiddleware
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestSecurityHeadersMiddleware:
|
|
"""Tests for security headers on responses."""
|
|
|
|
def test_nosniff_header(self, client):
|
|
"""X-Content-Type-Options: nosniff is present."""
|
|
response = client.get("/health")
|
|
assert response.headers.get("X-Content-Type-Options") == "nosniff"
|
|
|
|
def test_frame_options_header(self, client):
|
|
"""X-Frame-Options: SAMEORIGIN is present."""
|
|
response = client.get("/health")
|
|
assert response.headers.get("X-Frame-Options") == "SAMEORIGIN"
|
|
|
|
def test_referrer_policy_header(self, client):
|
|
"""Referrer-Policy is set correctly."""
|
|
response = client.get("/health")
|
|
assert (
|
|
response.headers.get("Referrer-Policy")
|
|
== "strict-origin-when-cross-origin"
|
|
)
|
|
|
|
def test_permissions_policy_header(self, client):
|
|
"""Permissions-Policy restricts camera/mic/geo."""
|
|
response = client.get("/health")
|
|
assert (
|
|
response.headers.get("Permissions-Policy")
|
|
== "camera=(), microphone=(), geolocation=()"
|
|
)
|
|
|
|
def test_no_hsts_on_http(self, client):
|
|
"""HSTS header is NOT set for plain HTTP requests."""
|
|
response = client.get("/health")
|
|
# TestClient uses http by default
|
|
assert "Strict-Transport-Security" not in response.headers
|
|
|
|
def test_headers_on_api_routes(self, client):
|
|
"""Security headers are present on API routes too."""
|
|
response = client.get("/api/v1/health")
|
|
assert response.headers.get("X-Content-Type-Options") == "nosniff"
|
|
assert response.headers.get("X-Frame-Options") == "SAMEORIGIN"
|
|
|
|
def test_headers_on_404(self, client):
|
|
"""Security headers are present even on 404 responses."""
|
|
response = client.get("/nonexistent-path-that-returns-404")
|
|
assert response.headers.get("X-Content-Type-Options") == "nosniff"
|
|
assert response.headers.get("Referrer-Policy") == "strict-origin-when-cross-origin"
|