#!/usr/bin/env python3 """Exercise branded PWA responses from a running upstream WebUI server.""" from __future__ import annotations import json import sys from collections.abc import Callable from typing import Any from urllib.parse import urljoin from urllib.request import Request, urlopen PNG_MAGIC = b"\x89PNG\r\n\x1a\n" PERSONA_LINKS = ( "static/hermes-agent.ico", "static/hermes-agent-192.png", "static/hermes-agent-512.png", ) def _get( url: str, opener: Callable[..., Any], ) -> tuple[bytes, str]: request = Request(url, headers={"Accept-Encoding": "identity"}) with opener(request, timeout=5) as response: status = int(getattr(response, "status", 0)) if status != 200: raise RuntimeError(f"GET {url} returned HTTP {status}") body = response.read() final_url = response.geturl() return body, final_url def _icon_sources(value: object) -> list[str]: sources: list[str] = [] if isinstance(value, dict): icons = value.get("icons") if isinstance(icons, list): for icon in icons: if not isinstance(icon, dict) or not isinstance(icon.get("src"), str): raise RuntimeError("manifest contains an invalid icon entry") if icon.get("type") != "image/png": raise RuntimeError("manifest contains a non-PNG icon") sources.append(icon["src"]) for child in value.values(): if child is not icons: sources.extend(_icon_sources(child)) elif isinstance(value, list): for child in value: sources.extend(_icon_sources(child)) return sources def smoke( base_url: str, *, opener: Callable[..., Any] = urlopen, ) -> dict[str, object]: base_url = base_url.rstrip("/") + "/" manifest_body, manifest_url = _get(urljoin(base_url, "manifest.json"), opener) try: manifest = json.loads(manifest_body) except (UnicodeDecodeError, json.JSONDecodeError) as exc: raise RuntimeError("served /manifest.json is not valid branded JSON") from exc if manifest.get("name") != "Hermes Chat" or manifest.get("short_name") != "Hermes": raise RuntimeError("served /manifest.json is not branded for Hermes Chat") expected = { "static/hermes-agent-192.png", "static/hermes-agent-512.png", } top_level = manifest.get("icons") if not isinstance(top_level, list) or { icon.get("src") for icon in top_level if isinstance(icon, dict) } != expected: raise RuntimeError("served /manifest.json has the wrong Hermes icons") icon_sources = _icon_sources(manifest) if not icon_sources: raise RuntimeError("served /manifest.json has no icon URLs") for source in icon_sources: icon_body, _icon_url = _get(urljoin(manifest_url, source), opener) if not icon_body.startswith(PNG_MAGIC): raise RuntimeError(f"manifest icon is not PNG: {source}") root_body, _root_url = _get(base_url, opener) try: root_html = root_body.decode("utf-8") except UnicodeDecodeError as exc: raise RuntimeError("served / is not UTF-8 HTML") from exc for source in PERSONA_LINKS: if source not in root_html: raise RuntimeError(f"served / omitted Hermes persona link: {source}") if "static/hermes-brand.css" not in root_html: raise RuntimeError("served / omitted static/hermes-brand.css") direct_icon, _direct_url = _get( urljoin(base_url, "static/hermes-agent-192.png"), opener ) if not direct_icon.startswith(PNG_MAGIC): raise RuntimeError("served /static/hermes-agent-192.png is not PNG") return { "manifest": manifest_url, "icon_requests": len(icon_sources), "root": base_url, "direct_icon": "static/hermes-agent-192.png", } def main() -> int: if len(sys.argv) != 2: raise SystemExit("usage: hermes-webui-smoke.py BASE_URL") result = smoke(sys.argv[1]) print( "Hermes WebUI smoke passed: " f"manifest={result['manifest']} " f"icon_requests={result['icon_requests']} " "root=branded direct_icon=png" ) return 0 if __name__ == "__main__": raise SystemExit(main())