import httpx import pytest from src import main REQUIRED_HEADERS = { "x-content-type-options": "nosniff", "referrer-policy": "no-referrer", "x-frame-options": "DENY", } def assert_browser_security_boundary(response: httpx.Response) -> None: for name, value in REQUIRED_HEADERS.items(): assert response.headers[name] == value assert "camera=()" in response.headers["permissions-policy"] policy = response.headers["content-security-policy"] assert "default-src 'self'" in policy assert "script-src 'self'" in policy assert "object-src 'none'" in policy assert "frame-ancestors 'none'" in policy script_policy = next(part for part in policy.split(";") if "script-src" in part) assert "'unsafe-inline'" not in script_policy assert "'unsafe-eval'" not in script_policy @pytest.mark.anyio async def test_security_boundary_covers_pages_health_static_and_api_errors(monkeypatch): monkeypatch.setenv("STACKCHAIN_DASHBOARD_ACCESS_TOKEN", "access-token-with-at-least-thirty-two-characters") monkeypatch.setenv("STACKCHAIN_DASHBOARD_SESSION_SECRET", "session-secret-with-at-least-thirty-two-characters") monkeypatch.setenv("STACKCHAIN_DASHBOARD_AUTH_MODE", "operator") monkeypatch.setenv("STACKCHAIN_DASHBOARD_PUBLIC_ORIGIN", "https://test") transport = httpx.ASGITransport(app=main.app) async with httpx.AsyncClient(transport=transport, base_url="https://test") as client: responses = [ await client.get("/healthz"), await client.get("/login"), await client.get("/static/dashboard.js"), await client.get("/api/v1/context"), ] assert [response.status_code for response in responses] == [200, 200, 200, 401] for response in responses: assert_browser_security_boundary(response) assert response.headers["strict-transport-security"] == "max-age=31536000" @pytest.mark.anyio async def test_security_boundary_covers_fail_closed_authentication_response(monkeypatch): monkeypatch.delenv("STACKCHAIN_DASHBOARD_ACCESS_TOKEN", raising=False) monkeypatch.delenv("STACKCHAIN_DASHBOARD_SESSION_SECRET", raising=False) monkeypatch.delenv("STACKCHAIN_DASHBOARD_AUTH_MODE", raising=False) transport = httpx.ASGITransport(app=main.app) async with httpx.AsyncClient(transport=transport, base_url="https://test") as client: response = await client.get("/login") assert response.status_code == 503 assert_browser_security_boundary(response) @pytest.mark.anyio async def test_insecure_local_mode_does_not_emit_hsts(): transport = httpx.ASGITransport(app=main.app, client=("127.0.0.1", 123)) async with httpx.AsyncClient(transport=transport, base_url="http://localhost") as client: response = await client.get("/healthz") assert response.status_code == 200 assert "strict-transport-security" not in response.headers