ci / lint-test-leaks (pull_request) Canceled after 0s
- self-contained HTML (no external assets/JS), everything html-escaped - daemon health from daemon_runs (last status + last run per daemon) - proposal queue counts by state; human-gate counters (mail drafts awaiting approval, content draft/approved) - audit tail: actor/action/result only — no detail payloads, no addresses, no subjects, no content bodies (tests assert the negatives) - DaemonRun bookkeeping like every other daemon tests: 3 new (sections render, leak-negatives, XSS escape) — 44 total
70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
"""monitor tests — page renders, no sensitive data, escapes input."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from cayceops.components.monitor import monitor
|
|
from cayceops.models import ContentItem, DaemonRun, MailMessage, Proposal
|
|
|
|
|
|
def _seed(sess):
|
|
sess.add(DaemonRun(daemon="scanner", status="ok", detail={"proposed": 3}))
|
|
sess.add(Proposal(kind="affiliate", title="Title with <script>alert(1)</script>"))
|
|
sess.add(
|
|
MailMessage(
|
|
direction="in",
|
|
from_addr="secret-person@private.example.org",
|
|
subject="private subject",
|
|
classification="approval",
|
|
draft_status="drafted",
|
|
)
|
|
)
|
|
sess.add(ContentItem(theme="atm-fees", channel="nostr", caption="caption", status="draft"))
|
|
sess.flush()
|
|
|
|
|
|
def test_build_renders_all_sections(cfg, sess, tmp_path):
|
|
_seed(sess)
|
|
out = tmp_path / "status.html"
|
|
monitor._build(cfg(CAYCE_OPS_MONITOR_OUTPUT=str(out)), sess)
|
|
page = out.read_text()
|
|
|
|
assert "daemon health" in page
|
|
assert "proposal queue" in page
|
|
assert "recent audit activity" in page
|
|
assert "scanner" in page
|
|
assert "proposed: <strong>1</strong>" in page
|
|
assert "mail drafts awaiting approval: <strong>1</strong>" in page
|
|
|
|
|
|
def test_build_leaks_no_sensitive_data(cfg, sess, tmp_path):
|
|
_seed(sess)
|
|
out = tmp_path / "status.html"
|
|
monitor._build(cfg(CAYCE_OPS_MONITOR_OUTPUT=str(out)), sess)
|
|
page = out.read_text()
|
|
|
|
assert "secret-person@private.example.org" not in page # no addresses
|
|
assert "private subject" not in page # no subjects
|
|
assert "caption" not in page # no content bodies
|
|
assert "Title with" not in page # proposal titles not rendered
|
|
|
|
|
|
def test_build_escapes_injected_content(cfg, sess, tmp_path):
|
|
from datetime import UTC, datetime
|
|
|
|
from cayceops.models import AuditEntry
|
|
|
|
sess.add(
|
|
AuditEntry(
|
|
ts=datetime.now(UTC),
|
|
actor="<script>x</script>",
|
|
action="probe",
|
|
detail={},
|
|
)
|
|
)
|
|
sess.flush()
|
|
out = tmp_path / "status.html"
|
|
monitor._build(cfg(CAYCE_OPS_MONITOR_OUTPUT=str(out)), sess)
|
|
page = out.read_text()
|
|
assert "<script>x</script>" not in page
|
|
assert "<script>x</script>" in page
|