import os import unittest from pathlib import Path from httpx import ASGITransport, AsyncClient MASTER_KEY = "master-secret-for-ui-tests" os.environ["IGNIS_API_KEY"] = MASTER_KEY import main # noqa: E402 class UiSecurityTests(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): self.client = AsyncClient( transport=ASGITransport(app=main.app), base_url="http://testserver", ) async def asyncTearDown(self): await self.client.aclose() async def test_root_sets_security_headers(self): response = await self.client.get("/") self.assertEqual(response.status_code, 200) self.assertEqual(response.headers["cache-control"], "no-store") self.assertEqual(response.headers["pragma"], "no-cache") self.assertEqual(response.headers["referrer-policy"], "no-referrer") self.assertEqual(response.headers["x-content-type-options"], "nosniff") self.assertEqual(response.headers["x-frame-options"], "DENY") self.assertIn("default-src 'self'", response.headers["content-security-policy"]) self.assertIn( "script-src 'self' 'unsafe-eval'", response.headers["content-security-policy"], ) self.assertIn( "style-src 'self' 'unsafe-inline'", response.headers["content-security-policy"], ) async def test_static_ui_uses_only_local_assets_and_session_storage(self): index_html = Path("static/index.html").read_text(encoding="utf-8") app_js = Path("static/app.js").read_text(encoding="utf-8") self.assertIn("/static/vendor/tailwindcdn.js", index_html) self.assertIn("/static/ui.css", index_html) self.assertIn("/static/vendor/vue.global.prod.js", index_html) self.assertIn("/static/app.js", index_html) self.assertNotIn("https://unpkg.com", index_html) self.assertNotIn("https://cdn.tailwindcss.com", index_html) self.assertNotIn("https://fonts.googleapis.com", index_html) self.assertNotIn("localStorage", index_html) self.assertNotIn("localStorage", app_js) self.assertIn("sessionStorage", app_js) self.assertIn("/system/info", app_js) self.assertIn("serverInfo", app_js) self.assertIn("Комнаты, сцены и свет", index_html) self.assertIn("Устройства и группы", index_html) self.assertIn("Собрать комнату из найденных ламп", index_html) self.assertIn("Повторяющееся расписание", index_html) self.assertIn("Гостевые и админ-ключи", index_html) self.assertIn("О сервере", index_html) self.assertIn("Запущен", index_html) self.assertNotIn("ОБЗОР", index_html) self.assertNotIn("tab === 'overview'", app_js)