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:
96
apps/api/tests/test_openapi.py
Normal file
96
apps/api/tests/test_openapi.py
Normal file
@@ -0,0 +1,96 @@
|
||||
"""Tests for OpenAPI schema generation and documentation."""
|
||||
|
||||
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 TestOpenAPISchema:
|
||||
@pytest.mark.asyncio
|
||||
async def test_openapi_endpoint_accessible(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_schema_has_info(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
schema = resp.json()
|
||||
assert schema["info"]["title"] == "ConsentOS API"
|
||||
assert "version" in schema["info"]
|
||||
assert "description" in schema["info"]
|
||||
assert "consent" in schema["info"]["description"].lower()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_schema_has_tags(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
schema = resp.json()
|
||||
tag_names = {t["name"] for t in schema.get("tags", [])}
|
||||
expected_tags = {
|
||||
"auth",
|
||||
"config",
|
||||
"consent",
|
||||
"sites",
|
||||
"cookies",
|
||||
"scanner",
|
||||
"compliance",
|
||||
"organisations",
|
||||
"users",
|
||||
}
|
||||
assert expected_tags.issubset(tag_names)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_all_tags_have_descriptions(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
schema = resp.json()
|
||||
for tag in schema.get("tags", []):
|
||||
assert "description" in tag, f"Tag '{tag['name']}' missing description"
|
||||
assert len(tag["description"]) > 10, f"Tag '{tag['name']}' has weak description"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_health_endpoint_in_schema(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
schema = resp.json()
|
||||
assert "/health" in schema["paths"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_key_endpoints_present(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
paths = resp.json()["paths"]
|
||||
assert "/api/v1/auth/login" in paths
|
||||
assert "/api/v1/consent/" in paths
|
||||
assert "/api/v1/sites/" in paths
|
||||
assert "/api/v1/config/geo" in paths
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_docs_endpoint_accessible(self, client):
|
||||
resp = await client.get("/docs")
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
class TestOpenAPIEndpoints:
|
||||
@pytest.mark.asyncio
|
||||
async def test_config_endpoints_documented(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
paths = resp.json()["paths"]
|
||||
config_paths = [p for p in paths if "/config/" in p]
|
||||
assert len(config_paths) >= 4 # public, resolved, geo-resolved, publish, geo
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_consent_endpoints_documented(self, client):
|
||||
resp = await client.get("/openapi.json")
|
||||
paths = resp.json()["paths"]
|
||||
consent_paths = [p for p in paths if "/consent" in p]
|
||||
assert len(consent_paths) >= 1
|
||||
Reference in New Issue
Block a user