from __future__ import annotations import hashlib import json import aiohttp import pytest from jarvis.operator_server import OperatorServer @pytest.mark.asyncio async def test_operator_server_routes_and_control_log(tmp_path): calls: list[tuple[str, dict]] = [] async def status_provider(): return {"status": "ok"} async def control_handler(action: str, payload: dict): calls.append((action, payload)) return {"ok": True, "action": action} server = OperatorServer( host="127.0.0.1", port=0, status_provider=status_provider, diagnostics_provider=lambda: ["warn-1"], control_handler=control_handler, control_schema_provider=lambda: {"actions": {"set_mode": {"required": ["mode"]}}}, metrics_provider=lambda: "jarvis_uptime_seconds 1\n", events_provider=lambda: [{"event_type": "x", "payload": {"a": 1}}], conversation_trace_provider=lambda limit=20: [{"turn_id": 1, "intent": "action"}][:limit], inbound_callback=lambda payload, headers, path, source: 7, inbound_enabled=False, inbound_token="", operator_auth_token="", ) await server.start() try: assert server._site is not None sockets = getattr(server._site, "_server").sockets port = int(sockets[0].getsockname()[1]) base = f"http://127.0.0.1:{port}" async with aiohttp.ClientSession(cookie_jar=aiohttp.CookieJar(unsafe=True)) as session: dashboard_resp = await session.get(f"{base}/") dashboard = await dashboard_resp.text() assert dashboard_resp.headers["X-Content-Type-Options"] == "nosniff" assert dashboard_resp.headers["X-Frame-Options"] == "DENY" assert dashboard_resp.headers["Referrer-Policy"] == "no-referrer" csp = dashboard_resp.headers["Content-Security-Policy"] assert "unsafe-inline" not in csp assert "style-src 'self' 'nonce-" in csp assert "script-src 'self' 'nonce-" in csp assert "'unsafe-hashes'" in csp assert '