"""Canonical icon, PWA, and fail-closed Hermes WebUI identity contracts.""" from __future__ import annotations import hashlib import json import os from pathlib import Path import shutil import struct import subprocess import sys ROOT = Path(__file__).resolve().parents[2] DOCKERFILES = ROOT / "dockerfiles" FIXTURE = ROOT / "testing/fixtures/hermes-webui-0.52.181" AGENT_FIXTURE = ROOT / "testing/fixtures/hermes-agent" ATLAS_PATCHER = DOCKERFILES / "hermes-webui-atlas-patch.py" BRAND_PATCHER = DOCKERFILES / "hermes-webui-brand-patch.py" ASSETS = DOCKERFILES / "hermes-webui-assets" MANIFEST = DOCKERFILES / "hermes-webui-manifest.json" BRAND_CSS = DOCKERFILES / "hermes-webui-brand.css" EXPECTED_HASHES = { "hermes-agent.ico": "aefe65e6574e6f46d3382588f46c508e1b3f3b3c9ce3dec6d335403a5374add9", "hermes-agent-192.png": "0e4102cc715372058dd6ab55e9cde2567e46fee5ab6557b564cdd212ccd2616f", "hermes-agent-512.png": "6661e5ca0ecc690af213b9f85f961541e6d3d0e36946ede9d3c2c97dfbd3c23d", } def _patched_fixture(tmp_path: Path) -> Path: target = tmp_path / "hermes-webui" agent_target = tmp_path / "hermes-agent" shutil.copytree(FIXTURE, target) shutil.copytree(AGENT_FIXTURE, agent_target) env = os.environ.copy() env["HERMES_WEBUI_PATCH_ROOT"] = str(target) env["HERMES_AGENT_PATCH_ROOT"] = str(agent_target) for patcher in (ATLAS_PATCHER, BRAND_PATCHER): subprocess.run( [sys.executable, str(patcher)], cwd=ROOT, env=env, check=True, capture_output=True, text=True, ) return target def _png_size(path: Path) -> tuple[int, int]: payload = path.read_bytes() assert payload.startswith(b"\x89PNG\r\n\x1a\n") assert payload[12:16] == b"IHDR" return struct.unpack(">II", payload[16:24]) def test_canonical_icon_provenance_format_and_pwa_derivatives() -> None: """The supplied persona is tracked exactly and only resized for PWA use.""" for name, expected in EXPECTED_HASHES.items(): payload = (ASSETS / name).read_bytes() assert hashlib.sha256(payload).hexdigest() == expected ico = (ASSETS / "hermes-agent.ico").read_bytes() reserved, image_type, count = struct.unpack_from(" None: """The app has both mandatory icon sizes and no remote or secret-bearing data.""" manifest = json.loads(MANIFEST.read_text(encoding="utf-8")) assert manifest["id"] == "./" assert manifest["name"] == "Hermes Chat" assert manifest["short_name"] == "Hermes" assert manifest["start_url"].startswith("./") assert manifest["scope"] == "./" assert manifest["display"] == "standalone" assert manifest["background_color"] == "#070A12" assert manifest["theme_color"] == "#0D1420" icons = manifest["icons"] assert {(icon["sizes"], icon["type"]) for icon in icons} == { ("192x192", "image/png"), ("512x512", "image/png"), } assert {icon["src"] for icon in icons} == { "static/hermes-agent-192.png", "static/hermes-agent-512.png", } assert all(icon["purpose"] == "any" for icon in icons) serialized = json.dumps(manifest).lower() assert "http:" not in serialized and "https:" not in serialized assert "secret" not in serialized and "token" not in serialized def test_production_patchers_apply_title_icons_theme_and_cache_contract( tmp_path: Path, ) -> None: """Exercise the shipped patchers against pinned upstream source fragments.""" target = _patched_fixture(tmp_path) index = (target / "static/index.html").read_text(encoding="utf-8") worker = (target / "static/sw.js").read_text(encoding="utf-8") assert index.count("Hermes Chat") == 1 assert index.count('id="hermesBrandStyles"') == 1 assert 'href="static/hermes-agent.ico"' in index assert 'sizes="192x192" href="static/hermes-agent-192.png"' in index assert 'sizes="512x512" href="static/hermes-agent-512.png"' in index assert '' in index assert 'Hermes Chat' in index assert '' in index assert "favicon.svg" not in index assert "favicon-32.png" not in index assert worker.count("'./static/hermes-brand.css' + VQ") == 1 for name in EXPECTED_HASHES: assert worker.count(f"'./static/{name}'") == 1 assert "favicon.svg" not in worker assert "favicon-32.png" not in worker def test_brand_patch_rejects_upstream_drift_before_partial_success( tmp_path: Path, ) -> None: """A changed pinned title/favicon context cannot silently ship partial branding.""" target = _patched_fixture(tmp_path) index = target / "static/index.html" index.write_text( index.read_text(encoding="utf-8").replace( "Hermes Chat", "Upstream changed", 1 ), encoding="utf-8", ) env = os.environ.copy() env["HERMES_WEBUI_PATCH_ROOT"] = str(target) result = subprocess.run( [sys.executable, str(BRAND_PATCHER)], cwd=ROOT, env=env, check=False, capture_output=True, text=True, ) assert result.returncode != 0 assert "brand patch context changed" in result.stderr def test_brand_css_is_accessible_dark_and_reduced_motion_aware() -> None: """Identity colors retain system controls and disable cosmetic motion.""" css = BRAND_CSS.read_text(encoding="utf-8") dark = css.split(":root.dark {", 1)[1] assert "color-scheme: dark" in dark assert "--bg: #070a12" in dark assert "--text: #e8f1f4" in dark assert "--accent: #48cfcc" in dark assert "--voice-accent: 72, 207, 204" in css assert "--voice-accent-secondary: 76, 164, 205" in css assert "@media (prefers-reduced-motion: reduce)" in css reduced = css.split("@media (prefers-reduced-motion: reduce)", 1)[1] assert "transition: none !important" in reduced assert "animation:" not in css def test_dockerfile_copies_and_verifies_every_tracked_brand_asset() -> None: """The immutable image, not a runtime coordinator path, owns PWA assets.""" dockerfile = (DOCKERFILES / "Dockerfile.hermes-webui").read_text(encoding="utf-8") assert "/opt/hermes/web/public/favicon.ico" not in dockerfile assert "COPY dockerfiles/hermes-webui-brand-patch.py" in dockerfile assert "python /tmp/hermes-webui-brand-patch.py" in dockerfile assert "COPY dockerfiles/hermes-webui-manifest.json" in dockerfile assert "COPY dockerfiles/hermes-webui-brand.css" in dockerfile for name, digest in EXPECTED_HASHES.items(): assert f"COPY dockerfiles/hermes-webui-assets/{name}" in dockerfile assert digest in dockerfile