feat(bell): add alert acknowledgement vertical slice
Harness governance / validate (pull_request) Has been cancelled
Harness governance / validate (pull_request) Has been cancelled
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""Static contract checks for the T-020 Bell alert vertical slice."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
OPENAPI = ROOT / "docs" / "contracts" / "bell-alert-console-v1.openapi.json"
|
||||
WEB = ROOT / "Bell" / "web" / "assets"
|
||||
|
||||
|
||||
class BellAlertContractTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
cls.contract = json.loads(OPENAPI.read_text(encoding="utf-8"))
|
||||
cls.html = (WEB / "index.html").read_text(encoding="utf-8")
|
||||
cls.css = (WEB / "style.css").read_text(encoding="utf-8")
|
||||
cls.js = (WEB / "app.js").read_text(encoding="utf-8")
|
||||
|
||||
def test_loopback_routes_and_bounds_are_frozen(self) -> None:
|
||||
self.assertEqual("3.1.0", self.contract["openapi"])
|
||||
self.assertTrue(self.contract["servers"][0]["url"].startswith("http://127.0.0.1:"))
|
||||
paths = self.contract["paths"]
|
||||
self.assertEqual(
|
||||
{"/alerts", "/alerts/{alert_id}", "/alerts/{alert_id}:ack", "/alerts/{alert_id}:close"},
|
||||
set(paths),
|
||||
)
|
||||
limit = paths["/alerts"]["get"]["parameters"][1]["schema"]
|
||||
self.assertEqual({"type": "integer", "minimum": 1, "maximum": 100, "default": 16}, limit)
|
||||
key = self.contract["components"]["parameters"]["IdempotencyKey"]["schema"]
|
||||
self.assertEqual((8, 128), (key["minLength"], key["maxLength"]))
|
||||
|
||||
def test_alert_is_separate_from_event_and_missing_capabilities_are_explicit(self) -> None:
|
||||
detail = self.contract["components"]["schemas"]["AlertDetail"]
|
||||
encoded = json.dumps(detail, ensure_ascii=False)
|
||||
self.assertIn("events", encoded)
|
||||
self.assertIn("transitions", encoded)
|
||||
self.assertIn("evidence_status", encoded)
|
||||
self.assertIn("delivery_status", encoded)
|
||||
self.assertIn("证据切片尚未启用", self.html)
|
||||
self.assertIn("升级与通知尚未启用", self.html)
|
||||
self.assertNotRegex(self.html + self.js, r"短信已发送|语音已接通|倒计时[::]\s*\d")
|
||||
|
||||
def test_console_is_dependency_free_and_does_not_embed_secrets(self) -> None:
|
||||
combined = self.html + self.css + self.js
|
||||
self.assertNotRegex(combined, r"https?://|cdn\.|localStorage|sessionStorage")
|
||||
self.assertNotRegex(combined, r"postgres(?:ql)?://|rtsp://|BELL_DB_DSN")
|
||||
self.assertIn('type="password"', self.html)
|
||||
self.assertIn('Cache-Control", "no-store"', (ROOT / "Bell" / "web" / "web.go").read_text(encoding="utf-8"))
|
||||
|
||||
def test_accessibility_and_small_screen_contract(self) -> None:
|
||||
for marker in (
|
||||
'aria-live="polite"',
|
||||
'aria-live="assertive"',
|
||||
'aria-busy="false"',
|
||||
'aria-pressed="true"',
|
||||
'href="#alerts"',
|
||||
):
|
||||
self.assertIn(marker, self.html)
|
||||
self.assertIn("@media(max-width:480px)", self.css.replace(" ", ""))
|
||||
self.assertIn("prefers-reduced-motion:reduce", self.css.replace(" ", ""))
|
||||
self.assertIn("[hidden]{display:none!important}", self.css.replace(" ", ""))
|
||||
self.assertRegex(self.css, r"min-height:44px")
|
||||
self.assertIn("textContent", self.js)
|
||||
self.assertNotIn("innerHTML", self.js)
|
||||
|
||||
def test_console_has_loading_empty_retry_conflict_and_keyboard_paths(self) -> None:
|
||||
for marker in ("skeleton", "没有预警", "加载失败,重试", "already_acknowledged", "keydown"):
|
||||
self.assertIn(marker, self.js)
|
||||
self.assertRegex(self.js, re.escape('limit:"16"'))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -64,6 +64,8 @@ class PostgresContractTests(unittest.TestCase):
|
||||
"015_privileges_audit_relay.sql",
|
||||
"016_event_ingress.sql",
|
||||
"017_privileges_event_ingress.sql",
|
||||
"018_bell_alerts.sql",
|
||||
"019_privileges_bell_alerts.sql",
|
||||
],
|
||||
names,
|
||||
)
|
||||
@@ -170,6 +172,24 @@ class PostgresContractTests(unittest.TestCase):
|
||||
)
|
||||
self.assertNotIn("endpoint_ref", privileges.split("revoke all on table sense.devices")[1])
|
||||
|
||||
def test_alert_history_is_append_only_and_runtime_is_least_privilege(self) -> None:
|
||||
migration = normalized(migration_text("018_bell_alerts.sql"))
|
||||
privileges = normalized(migration_text("019_privileges_bell_alerts.sql"))
|
||||
for marker in (
|
||||
"create table if not exists bell.rule_versions",
|
||||
"create table if not exists bell.event_rule_sweeps",
|
||||
"create table if not exists bell.rule_evaluations",
|
||||
"create table if not exists bell.alerts",
|
||||
"create table if not exists bell.alert_events",
|
||||
"create table if not exists bell.alert_transitions",
|
||||
"create table if not exists bell.alert_command_receipts",
|
||||
"insert into bell.schema_migrations(version) values (6)",
|
||||
):
|
||||
self.assertIn(marker, migration)
|
||||
self.assertIn("before update or delete", migration)
|
||||
self.assertIn("grant select, insert on table", privileges)
|
||||
self.assertNotRegex(privileges, r"grant\s+(?:update|delete|truncate|all)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user