arborist-viz/arborist_viz/tests/test_smoke.py
russell@unturf.com 0cd96ab1d7
Initial commit: arborist VIZ — Merkle command center
Pyramid web app for inspecting arborist Merkle trees over sharded SQLite:
document roots, inclusion proofs, an interactive 3D Merkle lattice
(six.js / WebGL with graceful fallback), audit-chain linkage, and a live
SSE event stream.

Generated artifacts (env/, vendored static/six/ bundles, demo databases)
are gitignored and rebuilt via the Makefile (venv, six, init-db, serve).
2026-05-28 09:22:59 -04:00

237 lines
7.6 KiB
Python

"""End-to-end smoke tests against a real arborist demo shard."""
from __future__ import annotations
# ---------- meta + home ------------------------------------------------
def test_version_endpoint(app):
res = app.get("/version")
assert res.status_code == 200
assert res.json["service"] == "arborist-viz"
assert "git_commit" in res.json
def test_home_renders(app):
res = app.get("/")
assert res.status_code == 200
assert b"arborist VIZ" in res.body
assert b"Merkle Command Center" in res.body
assert b"hash-drop" in res.body # hash-drop bar always present
def test_robots(app):
res = app.get("/robots.txt")
assert res.status_code == 200
# ---------- dashboards ------------------------------------------------
def test_dashboards_list(app):
res = app.get("/api/dashboards")
assert res.status_code == 200
ids = {d["id"] for d in res.json["dashboards"]}
assert {"default", "graveyard", "proof"} <= ids
def test_canned_dashboards_have_source_roots(app):
for dashboard_id in ("default", "graveyard", "proof"):
res = app.get(f"/api/dashboards/{dashboard_id}")
assert res.status_code == 200
cfg = res.json
assert cfg["id"] == dashboard_id
for w in cfg["widgets"]:
assert "source_roots" in w
assert "query" in w
def test_proof_dashboard_includes_lattice_widget(app):
res = app.get("/api/dashboards/proof")
types = {w["type"] for w in res.json["widgets"]}
assert "merkle-lattice-3d" in types
assert "merkle-proof" in types
def test_create_and_delete_dashboard(app):
body = {"id": "test-fresh", "title": "Test", "widgets": []}
res = app.post_json("/api/dashboards", body)
assert res.status_code == 200
assert res.json["created"]["id"] == "test-fresh"
res2 = app.get("/api/dashboards/test-fresh")
assert res2.status_code == 200
res3 = app.delete("/api/dashboards/test-fresh")
assert res3.status_code == 200
# ---------- roots / leaves / lattice ----------------------------------
def test_root_endpoint(app, demo_facts):
res = app.get(f"/api/root/{demo_facts['root']}")
assert res.status_code == 200
assert res.json["root_hash"] == demo_facts["root"]
assert res.json["leaf_count"] >= 1
assert res.json["source_roots"] == [demo_facts["root"]]
def test_root_not_found(app):
res = app.get("/api/root/" + "0" * 64, expect_errors=True)
assert res.status_code == 404
def test_leaves_reveal_in_dev(app, demo_facts):
"""development.ini sets privacy.reveal_private_leaves=true so the
operator can inspect their own corpus. production.ini keeps the
default-deny posture per §14 — see test_production_ini_is_deny."""
res = app.get(f"/api/root/{demo_facts['root']}/leaves")
assert res.status_code == 200
assert res.json["private_revealed"] is True
# At least one leaf must carry content under reveal mode.
assert any(leaf["content"] for leaf in res.json["leaves"])
def test_production_ini_is_deny():
"""production.ini must remain fail-closed for §14."""
import re
with open("production.ini") as f:
text = f.read()
m = re.search(r"privacy\.reveal_private_leaves\s*=\s*(\S+)", text)
assert m, "production.ini must set privacy.reveal_private_leaves"
assert m.group(1).lower() == "false", "production.ini must keep private leaves deny by default"
def test_lattice_returns_layers(app, demo_facts):
res = app.get(f"/api/lattice/{demo_facts['root']}")
assert res.status_code == 200
assert res.json["layer_count"] >= 1
assert res.json["leaf_count"] >= 1
# Root layer always has exactly one node.
assert len(res.json["layers"][-1]) == 1
assert res.json["layers"][-1][0] == demo_facts["root"]
# ---------- proof ------------------------------------------------------
def test_proof_passes_against_arborist_merkle(app, demo_facts):
res = app.get(f"/api/proof/{demo_facts['root']}/{demo_facts['leaf_index']}")
assert res.status_code == 200
assert res.json["passed"] is True
assert res.json["computed_root"] == demo_facts["root"]
assert res.json["leaf_hash"] == demo_facts["leaf_hash"]
def test_proof_leaf_out_of_range(app, demo_facts):
res = app.get(f"/api/proof/{demo_facts['root']}/9999", expect_errors=True)
assert res.status_code == 400
def test_proof_rejects_non_integer(app, demo_facts):
res = app.get(f"/api/proof/{demo_facts['root']}/notanint", expect_errors=True)
assert res.status_code == 400
# ---------- audit ------------------------------------------------------
def test_audit_event(app, demo_facts):
res = app.get(f"/api/audit/{demo_facts['event_hash']}")
assert res.status_code == 200
assert res.json["event_hash"] == demo_facts["event_hash"]
assert res.json["subject_root"] == demo_facts["root"]
def test_audit_chain(app, demo_facts):
res = app.get(f"/api/audit/chain/{demo_facts['event_hash']}")
assert res.status_code == 200
assert res.json["head_event_hash"] == demo_facts["event_hash"]
def test_audit_recent(app):
res = app.get("/api/audit/recent?limit=10")
assert res.status_code == 200
assert res.json["count"] >= 1
# ---------- hash resolver ---------------------------------------------
def test_resolve_document_root(app, demo_facts):
res = app.get(f"/api/resolve/{demo_facts['root']}")
assert res.status_code == 200
assert res.json["kind"] == "document_root"
assert res.json["url"] == f"/proof/{demo_facts['root']}"
def test_resolve_leaf_hash(app, demo_facts):
res = app.get(f"/api/resolve/{demo_facts['leaf_hash']}")
assert res.status_code == 200
assert res.json["kind"] == "leaf_hash"
assert res.json["document_root"] == demo_facts["root"]
assert res.json["leaf_index"] == demo_facts["leaf_index"]
def test_resolve_audit_event(app, demo_facts):
res = app.get(f"/api/resolve/{demo_facts['event_hash']}")
assert res.status_code == 200
assert res.json["kind"] == "audit_event"
def test_resolve_unknown(app):
res = app.get("/api/resolve/" + "0" * 64)
assert res.json["kind"] == "unknown"
def test_resolve_not_hex(app, demo_facts):
res = app.get("/api/resolve/not_hex_at_all_g!", expect_errors=True)
assert res.status_code == 400
# ---------- proof page render -----------------------------------------
def test_proof_page_renders(app, demo_facts):
res = app.get(f"/proof/{demo_facts['root']}")
assert res.status_code == 200
assert demo_facts["root"].encode() in res.body
assert b"lattice-canvas" in res.body
assert b"mountProofPage" in res.body
def test_audit_page_renders(app, demo_facts):
res = app.get(f"/audit/{demo_facts['event_hash']}")
assert res.status_code == 200
assert demo_facts["event_hash"].encode() in res.body
# ---------- #000062 gate ----------------------------------------------
def test_trace_gate_returns_501(app):
res = app.get("/api/trace/t1", expect_errors=True)
assert res.status_code == 501
def test_circuit_gate_returns_501(app):
res = app.get("/api/circuit/c1", expect_errors=True)
assert res.status_code == 501
# ---------- diff -------------------------------------------------------
def test_root_diff(app, demo_facts):
# demo shard has two docs; diff them.
res_roots = app.get("/api/roots")
assert res_roots.status_code == 200
roots = [r["document_root"] for r in res_roots.json["roots"]]
assert len(roots) >= 2
res = app.get(f"/api/diff/{roots[0]}/{roots[1]}")
assert res.status_code == 200
assert res.json["root_a"] == roots[0]
assert res.json["root_b"] == roots[1]
assert res.json["source_roots"] == [roots[0], roots[1]]