"""Executable and static quality gates for the isolated HUX-10 frontend.""" from __future__ import annotations import json from pathlib import Path from hux_node_gate import run_node_coverage ROOT = Path(__file__).resolve().parents[2] PRIVACY = ROOT / "dockerfiles" / "hermes-webui-hux" / "privacy" def test_hux_privacy_node_suite_and_per_source_coverage(): """Privacy adapters and transport remain above the repository gate.""" run_node_coverage( [ "dockerfiles/hermes-webui-hux/privacy/client.ts", "dockerfiles/hermes-webui-hux/privacy/model.ts", "dockerfiles/hermes-webui-hux/privacy/security.ts", ], [ "testing/tests/test_hermes_hux_ui_privacy.mjs", ], {"branches": 95, "functions": 95, "lines": 95}, strip_types=True, ) def test_hux_privacy_matches_contract_and_stays_inert(): """HUX-10 uses shared topic/notice rules without live integration.""" schema = json.loads( (ROOT / "services/hermes/contracts/hux/privacy.schema.json").read_text( encoding="utf-8" ) ) model = (PRIVACY / "model.ts").read_text(encoding="utf-8") security = (PRIVACY / "security.ts").read_text(encoding="utf-8") for topic in schema["$defs"]["topic"]["enum"]: assert f"{topic}:" in model for control in schema["$defs"]["notice"]["properties"]["controls"][ "items" ]["enum"]: assert f'"{control}"' in model assert "hux.privacy_notice.v1" in model and "hux.v1" in model assert "conversationId" in security and "sessionId" in security assert "dockerfiles/hermes-webui-hux/privacy" not in ( ROOT / "dockerfiles/Dockerfile.hermes-webui" ).read_text(encoding="utf-8") def test_hux_privacy_ui_is_accessible_minimized_and_explicit(): """The UI explains retention without repeating sensitive categories.""" component = (PRIVACY / "PrivacyCenter.tsx").read_text(encoding="utf-8") model = (PRIVACY / "model.ts").read_text(encoding="utf-8") client = (PRIVACY / "client.ts").read_text(encoding="utf-8") contracts = (PRIVACY / "contracts.ts").read_text(encoding="utf-8") styles = (PRIVACY / "styles.css").read_text(encoding="utf-8") assert "if (!enabled || !snapshot) return null" in component assert "What Hermes keeps" in component and "Effective retention" in component assert "No-store active" in component and "Use no-store here" in component assert "Sensitive-topic protection" in component assert "Previous sensitive details are not repeated" in component assert "Retention audit" in component and "auditIntervalDays" in component assert "Confirm forget" in component and "This cannot be undone" in component assert 'role="group"' in component and 'role="status"' in component assert 'aria-live="polite"' in component and 'role="alert"' in component assert "snapshot.notice.topic" not in component assert "dangerouslySetInnerHTML" not in component assert "GENERIC_NOTICE" in model and "Never carry the category" in model assert "seenNotices" in client and "withoutNotice" in client assert all( token not in client for token in ("localStorage", "sessionStorage", "indexedDB", "document.cookie") ) assert 'credentials: "same-origin"' in client and 'cache: "no-store"' in client assert "MUST omit inactive or previous topic" in contracts assert "Topic changes clear the prior notice" in contracts assert ".hux-privacy" in styles assert "body" not in styles and ":root" not in styles assert "focus-visible" in styles and "prefers-reduced-motion" in styles def test_hux_privacy_sources_are_bounded_and_endpoint_only(): """The slice defines API needs but changes no runtime or release wiring.""" sources = sorted(PRIVACY.glob("*")) assert {path.name for path in sources} == { "PrivacyCenter.tsx", "client.ts", "contracts.ts", "index.ts", "model.ts", "security.ts", "styles.css", "types.ts", } for path in sources: assert len(path.read_text(encoding="utf-8").splitlines()) < 500 contracts = (PRIVACY / "contracts.ts").read_text(encoding="utf-8") assert "GET /hux/v1/privacy/snapshot?session_id=&conversation_id=" in contracts assert "POST /hux/v1/privacy/controls" in contracts assert "expected_revision" in contracts and "A 409 rejects stale state" in contracts