#!/usr/bin/env python3 """Static integrity checks for the embedded administration interface. The test intentionally uses only the Python standard library. It verifies the actual HTML assembly and JavaScript files embedded by src/admin/router.rs; it is not a replacement for Rust/browser integration tests. """ from __future__ import annotations from collections import Counter from pathlib import Path import re ROOT = Path(__file__).resolve().parents[1] WEB = ROOT / "src/admin/web" ROUTER = (ROOT / "src/admin/router.rs").read_text(encoding="utf-8") def assembled_html() -> str: html = (WEB / "index.html").read_text(encoding="utf-8") metrics = (WEB / "partials/overview-metrics.html").read_text(encoding="utf-8") charts = (WEB / "partials/overview-charts.html").read_text(encoding="utf-8") metrics_main, metrics_web = metrics.split("", 1) charts_main, charts_web = charts.split("", 1) return ( html.replace("", metrics_main) .replace("", metrics_web) .replace("", charts_main) .replace("", charts_web) ) def embedded_app_sources() -> list[Path]: start = ROUTER.index("fn admin_app_javascript()") end = ROUTER.index("fn admin_vhosts_javascript()", start) app_block = ROUTER[start:end] paths = [WEB / rel for rel in re.findall(r'include_str!\("web/([^"\n]+\.js)"\)', app_block)] vstart = end vend = ROUTER.index("pub fn router", vstart) vhost_block = ROUTER[vstart:vend] vhost_paths = [WEB / rel for rel in re.findall(r'include_str!\("web/([^"\n]+\.js)"\)', vhost_block)] result: list[Path] = [] for path in [*paths, *vhost_paths]: if path not in result: result.append(path) return result def attribute_values(html: str, name: str) -> set[str]: return set(re.findall(rf'\b{re.escape(name)}=["\']([^"\']+)', html)) html = assembled_html() ids = re.findall(r'\bid=["\']([^"\']+)', html) duplicates = sorted(name for name, count in Counter(ids).items() if count > 1) assert not duplicates, f"duplicate panel DOM ids: {duplicates}" id_set = set(ids) sources = embedded_app_sources() assert sources, "no embedded administration JavaScript sources found" missing_files = [str(path.relative_to(ROOT)) for path in sources if not path.is_file()] assert not missing_files, f"missing embedded JS sources: {missing_files}" literal_refs: dict[str, set[str]] = {} patterns = [ re.compile(r'\$\(["\']([^"\']+)["\']\)'), re.compile(r'document\.getElementById\(["\']([^"\']+)["\']\)'), ] for path in sources: source = path.read_text(encoding="utf-8") for pattern in patterns: for dom_id in pattern.findall(source): literal_refs.setdefault(dom_id, set()).add(str(path.relative_to(ROOT))) missing_refs = {dom_id: sorted(paths) for dom_id, paths in literal_refs.items() if dom_id not in id_set} assert not missing_refs, f"embedded panel JS references missing DOM ids: {missing_refs}" assert "ui-interface-icons" in id_set, "Appearance must expose the SVG icon toggle" assert any(path.name == "icons.js" for path in sources), "semantic icon module must be embedded in app.js" assert 'data-i18n="overviewExtraRecentSamples"' not in html, "Overview metric tiles must not show the redundant Recent samples footer" overview_extra = (WEB / "app/overview-extra-metrics.js").read_text(encoding="utf-8") assert 't("overviewExtraRecentSamples")' not in overview_extra, "Overview metric details must not fall back to the generic Recent samples label" # Every visible primary navigation target must have a panel section. filelogs is # intentionally opened from the Logs menu rather than the main navigation. panel_targets = attribute_values(html, "data-panel") panel_sections = {value.removeprefix("panel-") for value in id_set if value.startswith("panel-")} assert panel_targets <= panel_sections, f"navigation targets without panels: {sorted(panel_targets - panel_sections)}" assert panel_sections - panel_targets <= {"filelogs"}, f"unexpected orphan panels: {sorted(panel_sections - panel_targets)}" # Tab/page contracts used by the generic tab handlers in the embedded JS. for prefix in ("settings", "policy-settings", "cache-settings", "logging-settings", "traffic"): tabs = attribute_values(html, f"data-{prefix}-tab") pages = attribute_values(html, f"data-{prefix}-page") assert tabs == pages, f"{prefix} tab/page mismatch: tabs={sorted(tabs - pages)}, pages={sorted(pages - tabs)}" print( f"Panel interface contract: OK ({len(ids)} unique DOM ids, " f"{len(literal_refs)} literal JS references, {len(sources)} embedded JS files)" )