feat: initial public release
ConsentOS — a privacy-first cookie consent management platform. Self-hosted, source-available alternative to OneTrust, Cookiebot, and CookieYes. Full standards coverage (IAB TCF v2.2, GPP v1, Google Consent Mode v2, GPC, Shopify Customer Privacy API), multi-tenant architecture with role-based access, configuration cascade (system → org → group → site → region), dark-pattern detection in the scanner, and a tamper-evident consent record audit trail. This is the initial public release. Prior development history is retained internally. See README.md for the feature list, architecture overview, and quick-start instructions. Licensed under the Elastic Licence 2.0 — self-host freely; do not resell as a managed service.
This commit is contained in:
65
apps/api/tests/test_middleware_security.py
Normal file
65
apps/api/tests/test_middleware_security.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""Tests for the security headers middleware."""
|
||||
|
||||
import pytest
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
|
||||
from src.main import create_app
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app():
|
||||
return create_app()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def client(app):
|
||||
transport = ASGITransport(app=app)
|
||||
async with AsyncClient(transport=transport, base_url="http://test") as ac:
|
||||
yield ac
|
||||
|
||||
|
||||
class TestSecurityHeaders:
|
||||
@pytest.mark.asyncio
|
||||
async def test_x_content_type_options(self, client):
|
||||
resp = await client.get("/health")
|
||||
assert resp.headers["x-content-type-options"] == "nosniff"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_x_frame_options(self, client):
|
||||
resp = await client.get("/health")
|
||||
assert resp.headers["x-frame-options"] == "DENY"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_x_xss_protection(self, client):
|
||||
resp = await client.get("/health")
|
||||
assert resp.headers["x-xss-protection"] == "0"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_referrer_policy(self, client):
|
||||
resp = await client.get("/health")
|
||||
assert resp.headers["referrer-policy"] == "strict-origin-when-cross-origin"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_content_security_policy(self, client):
|
||||
resp = await client.get("/health")
|
||||
assert resp.headers["content-security-policy"] == "default-src 'none'"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_hsts_on_http(self, client):
|
||||
resp = await client.get("/health")
|
||||
assert "strict-transport-security" not in resp.headers
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hsts_on_https(self, app):
|
||||
transport = ASGITransport(app=app)
|
||||
async with AsyncClient(transport=transport, base_url="https://test") as client:
|
||||
resp = await client.get("/health")
|
||||
assert "strict-transport-security" in resp.headers
|
||||
assert "max-age=63072000" in resp.headers["strict-transport-security"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_headers_present_on_non_existent_route(self, client):
|
||||
# Even 404s on unknown routes should have security headers
|
||||
resp = await client.get("/this-does-not-exist")
|
||||
assert resp.headers["x-content-type-options"] == "nosniff"
|
||||
assert resp.headers["x-frame-options"] == "DENY"
|
||||
Reference in New Issue
Block a user