128 lines
4.2 KiB
Python
128 lines
4.2 KiB
Python
#!/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())
|