Files
2026-07-13 13:12:33 +08:00

68 lines
2.4 KiB
Python

"""Pin the Control UI Content-Security-Policy.
The chat surface previews artifacts (notably generated images) by fetching the
authenticated bytes and rendering an object URL (``blob:``) in an ``<img>``.
If ``img-src`` omits ``blob:`` the browser blocks every generated-image
preview while the file still downloads fine — a "the UI lied" failure. These
tests keep ``blob:`` in the policy and keep the header scoped to the Control UI
path prefix.
"""
from __future__ import annotations
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.routing import Route
from starlette.testclient import TestClient
from opensquilla.gateway.middleware import SecurityHeadersMiddleware
def _client(path_prefix: str = "/control") -> TestClient:
async def ok(_request): # type: ignore[no-untyped-def]
return PlainTextResponse("ok")
app = Starlette(
routes=[
Route("/control/ping", ok),
Route("/other", ok),
]
)
app.add_middleware(SecurityHeadersMiddleware, path_prefix=path_prefix)
return TestClient(app)
def test_csp_allows_blob_images_for_artifact_previews() -> None:
response = _client().get("/control/ping")
assert response.status_code == 200
csp = response.headers.get("content-security-policy", "")
assert "img-src 'self' data: blob:;" in csp, csp
assert "font-src 'self' data:;" in csp, csp
def test_csp_still_constrains_default_and_connect_sources() -> None:
csp = _client().get("/control/ping").headers.get("content-security-policy", "")
# blob: is added only to img-src; the rest of the policy stays locked down.
assert "default-src 'self';" in csp, csp
assert "connect-src 'self' ws: wss:;" in csp, csp
assert "blob:" not in csp.split("img-src", 1)[0], csp
def test_csp_allows_only_same_origin_blob_and_https_media() -> None:
csp = _client().get("/control/ping").headers.get("content-security-policy", "")
directives = [directive.strip() for directive in csp.split(";") if directive.strip()]
assert [
directive for directive in directives if directive.startswith("media-src ")
] == ["media-src 'self' blob: https:"], csp
def test_security_headers_scoped_to_control_prefix() -> None:
response = _client().get("/other")
assert response.status_code == 200
assert "content-security-policy" not in response.headers
assert "x-frame-options" not in response.headers