atlas-iac/testing/tests/test_hermes_hux_ui_privacy.py
jenkins b66c762f5d hermes(webui): add HUX card UI models with contract-locked suites
Standalone per-card browser model/security/view modules for HUX-01..10
plus node+pytest suites that read the hux.v1 contract schemas directly.
Reconciled drift found on integration: the activity model now accepts
all 32 hux.event.v1 kinds (delegation.*, memory.suppressed,
memory.retrieval_removed, budget.exhausted, side_effect.*), the
autonomy model carries the external_side_effect capability, and the
foundation boundary test now asserts the shipped static HUX surface
exists on disk and that images never bake activated HUX_FLAGS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
2026-08-24 04:12:03 -03:00

120 lines
5.0 KiB
Python

"""Executable and static quality gates for the isolated HUX-10 frontend."""
from __future__ import annotations
import json
import subprocess
from pathlib import Path
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."""
result = subprocess.run(
[
"node",
"--test",
"--experimental-strip-types",
"--experimental-test-coverage",
"--test-coverage-lines=95",
"--test-coverage-functions=95",
"--test-coverage-branches=95",
"--test-coverage-include=dockerfiles/hermes-webui-hux/privacy/client.ts",
"--test-coverage-include=dockerfiles/hermes-webui-hux/privacy/model.ts",
"--test-coverage-include=dockerfiles/hermes-webui-hux/privacy/security.ts",
"testing/tests/test_hermes_hux_ui_privacy.mjs",
],
cwd=ROOT,
check=False,
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0, result.stdout + result.stderr
for row in ("client.ts", "model.ts", "security.ts"):
report = next(line for line in result.stdout.splitlines() if row in line)
percentages = [float(part) for part in report.split("|")[1:4]]
assert min(percentages) >= 95.0, report
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