"""Unit tests for security headers middleware.""" from starlette.testclient import TestClient from app.config import Settings from app.main import create_app def test_security_headers_middleware_adds_csp_header() -> None: """Security headers middleware adds Content-Security-Policy header to responses.""" settings = Settings( database_path="/tmp/test.db", fail2ban_socket="/tmp/fake_fail2ban.sock", fail2ban_config_dir="/tmp/fail2ban", session_secret="test-secret-key-do-not-use-in-production", session_duration_minutes=60, timezone="UTC", log_level="debug", ) app = create_app(settings=settings) client = TestClient(app) response = client.get("/api/health") assert "Content-Security-Policy" in response.headers assert response.headers["Content-Security-Policy"] == "default-src 'self'" def test_security_headers_middleware_adds_x_frame_options() -> None: """Security headers middleware adds X-Frame-Options header to responses.""" settings = Settings( database_path="/tmp/test.db", fail2ban_socket="/tmp/fake_fail2ban.sock", fail2ban_config_dir="/tmp/fail2ban", session_secret="test-secret-key-do-not-use-in-production", session_duration_minutes=60, timezone="UTC", log_level="debug", ) app = create_app(settings=settings) client = TestClient(app) response = client.get("/api/health") assert "X-Frame-Options" in response.headers assert response.headers["X-Frame-Options"] == "DENY" def test_security_headers_middleware_adds_x_content_type_options() -> None: """Security headers middleware adds X-Content-Type-Options header to responses.""" settings = Settings( database_path="/tmp/test.db", fail2ban_socket="/tmp/fake_fail2ban.sock", fail2ban_config_dir="/tmp/fail2ban", session_secret="test-secret-key-do-not-use-in-production", session_duration_minutes=60, timezone="UTC", log_level="debug", ) app = create_app(settings=settings) client = TestClient(app) response = client.get("/api/health") assert "X-Content-Type-Options" in response.headers assert response.headers["X-Content-Type-Options"] == "nosniff" def test_security_headers_middleware_adds_x_xss_protection() -> None: """Security headers middleware adds X-XSS-Protection header to responses.""" settings = Settings( database_path="/tmp/test.db", fail2ban_socket="/tmp/fake_fail2ban.sock", fail2ban_config_dir="/tmp/fail2ban", session_secret="test-secret-key-do-not-use-in-production", session_duration_minutes=60, timezone="UTC", log_level="debug", ) app = create_app(settings=settings) client = TestClient(app) response = client.get("/api/health") assert "X-XSS-Protection" in response.headers assert response.headers["X-XSS-Protection"] == "1; mode=block" def test_security_headers_on_all_response_types() -> None: """Security headers are added to all response types (success and error).""" settings = Settings( database_path="/tmp/test.db", fail2ban_socket="/tmp/fake_fail2ban.sock", fail2ban_config_dir="/tmp/fail2ban", session_secret="test-secret-key-do-not-use-in-production", session_duration_minutes=60, timezone="UTC", log_level="debug", ) app = create_app(settings=settings) client = TestClient(app) # Test on successful response response = client.get("/api/health") assert response.status_code == 200 assert "Content-Security-Policy" in response.headers assert "X-Frame-Options" in response.headers assert "X-Content-Type-Options" in response.headers assert "X-XSS-Protection" in response.headers