Implement S23 runtime health slice
This commit is contained in:
parent
c0ff59097c
commit
cf723141a4
@ -2,7 +2,7 @@
|
||||
|
||||
**Upstream version:** v0.51.118
|
||||
**Plugin version:** 0.5.0
|
||||
**Total dependencies:** 34 (25 public API · 0 forced internal · 9 frontend)
|
||||
**Total dependencies:** 39 (29 public API · 0 forced internal · 10 frontend)
|
||||
|
||||
> **Auto-generated by `scripts/ast-connection-map.py`. Do not hand-edit.**
|
||||
> To change a justification, edit the `# CONNECTION:` comment above the
|
||||
@ -25,12 +25,16 @@
|
||||
| `plugin.py:46` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/bte.js")` |
|
||||
| `plugin.py:48` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/umbrella_inline.css")` |
|
||||
| `plugin.py:49` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/umbrella_inline.js")` |
|
||||
| `plugin.py:51` | `api.inject_stylesheet` | `api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.c` |
|
||||
| `plugin.py:52` | `api.inject_script` | `api.inject_script(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.js")` |
|
||||
| `routes/adwright.py:68` | `api.logger` | `log = api.logger("svrnty.routes.adwright")` |
|
||||
| `routes/adwright.py:69` | `api.register_route` | `api.register_route(` |
|
||||
| `routes/adwright.py:71` | `api.register_route` | `api.register_route(` |
|
||||
| `routes/bte_proxy.py:90` | `api.logger` | `log = api.logger("svrnty.routes.bte_proxy")` |
|
||||
| `routes/bte_proxy.py:91` | `api.register_route` | `api.register_route("/api/bte/proxy", "GET", _handle_proxy)` |
|
||||
| `routes/bte_proxy.py:92` | `api.register_route` | `api.register_route("/api/bte/proxy", "POST", _handle_proxy)` |
|
||||
| `routes/cortex_os_runtime_health.py:26` | `api.logger` | `log = api.logger("svrnty.routes.cortex_os_runtime_health")` |
|
||||
| `routes/cortex_os_runtime_health.py:27` | `api.register_route` | `api.register_route(ROUTE_PATH, ROUTE_METHOD, _handle_runtime_health)` |
|
||||
| `routes/transcribe.py:37` | `api.logger` | `log = api.logger("svrnty.routes.transcribe")` |
|
||||
| `routes/transcribe.py:38` | `api.register_route` | `api.register_route("/api/transcribe", "POST", _handle_transcribe)` |
|
||||
| `routes/transcribe.py:39` | `api.register_audio_attachment_processor` | `api.register_audio_attachment_processor(_transcribe_audio_attachments)` |
|
||||
@ -63,4 +67,5 @@ _None. Plugin uses only the public API._ ✓
|
||||
| `static/adwright.js` | 606 | `/api/adwright/provision-creds` |
|
||||
| `static/umbrella.js` | 57 | `/api/umbrella` |
|
||||
| `static/app.js` | 165 | `/api/vault/status` |
|
||||
| `static/cortex-os/runtime-health/runtime_health.js` | 4 | `/api/cortex-os/runtime-health` |
|
||||
|
||||
|
||||
@ -47,6 +47,9 @@ def register(api):
|
||||
# Inline Umbrella graph for the Hermes Workspace right panel.
|
||||
api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/umbrella_inline.css")
|
||||
api.inject_script(f"/plugins/{STATIC_PREFIX}/umbrella_inline.js")
|
||||
# Cortex OS Runtime Health slice: read-only route status display.
|
||||
api.inject_stylesheet(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.css")
|
||||
api.inject_script(f"/plugins/{STATIC_PREFIX}/cortex-os/runtime-health/runtime_health.js")
|
||||
log.info("static + assets wired at /plugins/%s/", STATIC_PREFIX)
|
||||
|
||||
# Routes — each feature lives in its own module under routes/.
|
||||
@ -77,4 +80,5 @@ def _phase2_routes():
|
||||
"adwright", # P2.C — Adwright tool panel routes (PRD §5+§6) ✓
|
||||
"bte_proxy", # P2.D — BTE Command Center same-origin proxy (PRD §3) ✓
|
||||
"umbrella", # P2.E — cortex-os umbrella graph viz (UMBRELLA-VIZ-PRD) ✓
|
||||
"cortex_os_runtime_health", # S23.0-I4 — Cortex OS Runtime Health read-only slice ✓
|
||||
]
|
||||
|
||||
142
routes/cortex_os_runtime_health.py
Normal file
142
routes/cortex_os_runtime_health.py
Normal file
@ -0,0 +1,142 @@
|
||||
"""GET /api/cortex-os/runtime-health - Cortex OS Runtime Health slice.
|
||||
|
||||
Public API surface used: api.register_route, api.logger.
|
||||
No forced internal dependencies. This module does not import Hermes internals.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
ROUTE_PATH = "/api/cortex-os/runtime-health"
|
||||
ROUTE_METHOD = "GET"
|
||||
CONTRACT_ID = "runtime-health/v0.1"
|
||||
CHECKED_AT = "2026-05-29T00:00:00Z"
|
||||
|
||||
_FORBIDDEN_TEXT = re.compile(
|
||||
r"(https?://|/home/|workspaces/|\b\d{2,5}\b|token|secret|cookie|traceback|exception|\.env)",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
def register(api: Any) -> None:
|
||||
"""Wire the read-only Runtime Health route."""
|
||||
log = api.logger("svrnty.routes.cortex_os_runtime_health")
|
||||
api.register_route(ROUTE_PATH, ROUTE_METHOD, _handle_runtime_health)
|
||||
log.info("cortex os runtime health endpoint registered")
|
||||
|
||||
|
||||
def _handle_runtime_health(handler: Any, parsed: Any) -> bool:
|
||||
"""Handler signature matches the plugin loader contract."""
|
||||
if getattr(handler, "command", ROUTE_METHOD) != ROUTE_METHOD:
|
||||
_write_json(handler, 405, _error_envelope("method_not_allowed", "read only route"))
|
||||
return True
|
||||
if getattr(parsed, "query", ""):
|
||||
_write_json(handler, 400, _error_envelope("query_not_allowed", "query targets are not accepted"))
|
||||
return True
|
||||
|
||||
_write_json(handler, 200, {"ok": True, "result": runtime_health_payload(), "error": None})
|
||||
return True
|
||||
|
||||
|
||||
def runtime_health_payload(host_signals: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
"""Return the host-neutral Runtime Health envelope."""
|
||||
signals = _summarize_host_signals(host_signals or {})
|
||||
status = _derive_status(signals)
|
||||
return {
|
||||
"contract_id": CONTRACT_ID,
|
||||
"checked_at": CHECKED_AT,
|
||||
"status": status,
|
||||
"readiness": "runtime_not_started",
|
||||
"summary": _summary_for(status),
|
||||
"authority": {
|
||||
"read_only": True,
|
||||
"runtime_state_mutation": False,
|
||||
"tool_callable_authority": False,
|
||||
"mcp_exposure": False,
|
||||
"profile_exposure_change": False,
|
||||
"memory_domain_access": False,
|
||||
"delegated_memory_grant": False,
|
||||
"sharing": False,
|
||||
"installer_automation": False,
|
||||
"product_readiness_claim": False,
|
||||
},
|
||||
"signals": signals,
|
||||
"warnings": ["deterministic_host_surface_inputs_only"],
|
||||
"errors": [],
|
||||
"redactions": ["host_specific_values", "raw_paths", "raw_urls", "secrets", "raw_payloads"],
|
||||
"source_trace": {
|
||||
"host_adapter": "hermes",
|
||||
"host_surfaces": ["health", "agent_health", "dashboard_status"],
|
||||
"live_probe": False,
|
||||
"raw_payload_passthrough": False,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _summarize_host_signals(host_signals: dict[str, Any]) -> list[dict[str, str]]:
|
||||
names = ["health", "agent_health", "dashboard_status"]
|
||||
if not host_signals:
|
||||
return [
|
||||
{"name": name, "status": "unknown", "detail": "not_probed"}
|
||||
for name in names
|
||||
]
|
||||
return [
|
||||
{
|
||||
"name": name,
|
||||
"status": _clean_status(host_signals.get(name, "unknown")),
|
||||
"detail": _bounded_text(host_signals.get(f"{name}_detail", "declared_surface")),
|
||||
}
|
||||
for name in names
|
||||
]
|
||||
|
||||
|
||||
def _derive_status(signals: list[dict[str, str]]) -> str:
|
||||
statuses = {signal["status"] for signal in signals}
|
||||
if "unavailable" in statuses:
|
||||
return "unavailable"
|
||||
if "degraded" in statuses:
|
||||
return "degraded"
|
||||
if statuses == {"healthy"}:
|
||||
return "healthy"
|
||||
return "unknown"
|
||||
|
||||
|
||||
def _clean_status(value: Any) -> str:
|
||||
text = str(value).strip().lower()
|
||||
return text if text in {"healthy", "degraded", "unavailable", "unknown"} else "unknown"
|
||||
|
||||
|
||||
def _summary_for(status: str) -> str:
|
||||
if status == "healthy":
|
||||
return "Runtime Health signals are healthy."
|
||||
if status == "degraded":
|
||||
return "Runtime Health signals are degraded."
|
||||
if status == "unavailable":
|
||||
return "Runtime Health signals are unavailable."
|
||||
return "Runtime Health has not been live-probed in this slice."
|
||||
|
||||
|
||||
def _bounded_text(value: Any) -> str:
|
||||
text = str(value).strip().replace("\n", " ")
|
||||
if not text:
|
||||
return "redacted"
|
||||
if _FORBIDDEN_TEXT.search(text):
|
||||
return "redacted"
|
||||
return text[:80]
|
||||
|
||||
|
||||
def _error_envelope(code: str, message: str) -> dict[str, Any]:
|
||||
return {"ok": False, "result": None, "error": {"code": code, "message": message}}
|
||||
|
||||
|
||||
def _write_json(handler: Any, status_code: int, payload: dict[str, Any]) -> None:
|
||||
body = json.dumps(payload, sort_keys=True).encode("utf-8")
|
||||
handler.send_response(status_code)
|
||||
handler.send_header("Content-Type", "application/json; charset=utf-8")
|
||||
handler.send_header("Content-Length", str(len(body)))
|
||||
handler.send_header("Cache-Control", "no-store")
|
||||
handler.end_headers()
|
||||
handler.wfile.write(body)
|
||||
72
static/cortex-os/runtime-health/runtime_health.css
Normal file
72
static/cortex-os/runtime-health/runtime_health.css
Normal file
@ -0,0 +1,72 @@
|
||||
.cortex-os-runtime-health {
|
||||
border: 1px solid rgba(19, 82, 121, 0.22);
|
||||
border-radius: 8px;
|
||||
margin: 16px;
|
||||
max-width: 520px;
|
||||
padding: 14px 16px;
|
||||
background: #f7fbff;
|
||||
color: #18212b;
|
||||
font: 14px/1.45 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health__badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 22px;
|
||||
padding: 0 8px;
|
||||
border-radius: 999px;
|
||||
background: #dde8f0;
|
||||
color: #18212b;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health[data-state="healthy"] .cortex-os-runtime-health__badge {
|
||||
background: #d8f1df;
|
||||
color: #0d5b27;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health[data-state="degraded"] .cortex-os-runtime-health__badge,
|
||||
.cortex-os-runtime-health[data-state="unknown"] .cortex-os-runtime-health__badge,
|
||||
.cortex-os-runtime-health[data-state="loading"] .cortex-os-runtime-health__badge {
|
||||
background: #fff0c9;
|
||||
color: #6a4a00;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health[data-state="unavailable"] .cortex-os-runtime-health__badge,
|
||||
.cortex-os-runtime-health[data-state="error"] .cortex-os-runtime-health__badge,
|
||||
.cortex-os-runtime-health[data-state="redacted"] .cortex-os-runtime-health__badge {
|
||||
background: #ffe0dd;
|
||||
color: #7a1e17;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health__summary {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health__signals {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(120px, 1fr) minmax(92px, auto);
|
||||
gap: 6px 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health__signals dt,
|
||||
.cortex-os-runtime-health__signals dd {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health__signals dt {
|
||||
color: #44515f;
|
||||
}
|
||||
|
||||
.cortex-os-runtime-health__signals dd {
|
||||
font-weight: 700;
|
||||
}
|
||||
107
static/cortex-os/runtime-health/runtime_health.js
Normal file
107
static/cortex-os/runtime-health/runtime_health.js
Normal file
@ -0,0 +1,107 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var endpoint = "/api/cortex-os/runtime-health";
|
||||
var states = ["healthy", "degraded", "unavailable", "unknown", "loading", "error", "redacted"];
|
||||
|
||||
if (window.__cortexOsRuntimeHealthLoaded) {
|
||||
return;
|
||||
}
|
||||
window.__cortexOsRuntimeHealthLoaded = true;
|
||||
|
||||
function ensurePanel() {
|
||||
var panel = document.querySelector("[data-cortex-os-runtime-health]");
|
||||
if (panel) {
|
||||
return panel;
|
||||
}
|
||||
|
||||
panel = document.createElement("section");
|
||||
panel.className = "cortex-os-runtime-health";
|
||||
panel.setAttribute("data-cortex-os-runtime-health", "true");
|
||||
panel.setAttribute("data-state", "loading");
|
||||
|
||||
var title = document.createElement("h2");
|
||||
title.textContent = "Cortex OS Runtime Health";
|
||||
|
||||
var badge = document.createElement("span");
|
||||
badge.className = "cortex-os-runtime-health__badge";
|
||||
badge.setAttribute("data-role", "status");
|
||||
badge.textContent = "loading";
|
||||
|
||||
var summary = document.createElement("p");
|
||||
summary.className = "cortex-os-runtime-health__summary";
|
||||
summary.setAttribute("data-role", "summary");
|
||||
summary.textContent = "Checking Runtime Health.";
|
||||
|
||||
var list = document.createElement("dl");
|
||||
list.className = "cortex-os-runtime-health__signals";
|
||||
list.setAttribute("data-role", "signals");
|
||||
|
||||
panel.appendChild(title);
|
||||
panel.appendChild(badge);
|
||||
panel.appendChild(summary);
|
||||
panel.appendChild(list);
|
||||
|
||||
var target = document.querySelector("main") || document.body;
|
||||
target.appendChild(panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
function setState(panel, state, summary, signals) {
|
||||
var nextState = states.indexOf(state) >= 0 ? state : "unknown";
|
||||
panel.setAttribute("data-state", nextState);
|
||||
panel.querySelector("[data-role='status']").textContent = nextState;
|
||||
panel.querySelector("[data-role='summary']").textContent = summary || "redacted";
|
||||
renderSignals(panel.querySelector("[data-role='signals']"), signals || []);
|
||||
}
|
||||
|
||||
function renderSignals(list, signals) {
|
||||
list.textContent = "";
|
||||
signals.slice(0, 3).forEach(function (signal) {
|
||||
var name = document.createElement("dt");
|
||||
var value = document.createElement("dd");
|
||||
name.textContent = signal.name || "redacted";
|
||||
value.textContent = signal.status || "unknown";
|
||||
list.appendChild(name);
|
||||
list.appendChild(value);
|
||||
});
|
||||
}
|
||||
|
||||
function renderPayload(panel, payload) {
|
||||
if (!payload || payload.ok !== true || !payload.result) {
|
||||
setState(panel, "error", "Runtime Health is unavailable.", []);
|
||||
return;
|
||||
}
|
||||
setState(panel, payload.result.status, payload.result.summary, payload.result.signals);
|
||||
}
|
||||
|
||||
function loadRuntimeHealth() {
|
||||
var panel = ensurePanel();
|
||||
setState(panel, "loading", "Checking Runtime Health.", []);
|
||||
|
||||
fetch(endpoint, {
|
||||
method: "GET",
|
||||
headers: { Accept: "application/json" },
|
||||
credentials: "same-origin",
|
||||
cache: "no-store"
|
||||
})
|
||||
.then(function (response) {
|
||||
if (!response.ok) {
|
||||
throw new Error("runtime-health-unavailable");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(function (payload) {
|
||||
renderPayload(panel, payload);
|
||||
})
|
||||
.catch(function () {
|
||||
setState(panel, "error", "Runtime Health is unavailable.", []);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", loadRuntimeHealth, { once: true });
|
||||
} else {
|
||||
loadRuntimeHealth();
|
||||
}
|
||||
})();
|
||||
@ -62,12 +62,15 @@ def test_loader_register_wires_our_plugin(loader, monkeypatch):
|
||||
assert ("GET", "/api/vault/status") in loader._ROUTES
|
||||
assert ("GET", "/api/umbrella") in loader._ROUTES
|
||||
assert ("GET", "/api/umbrella/doc") in loader._ROUTES
|
||||
assert ("GET", "/api/cortex-os/runtime-health") in loader._ROUTES
|
||||
# Static + injected URLs
|
||||
assert "svrnty" in loader._STATIC
|
||||
assert "/plugins/svrnty/app.css" in loader._STYLESHEETS
|
||||
assert "/plugins/svrnty/app.js" in loader._SCRIPTS
|
||||
assert "/plugins/svrnty/umbrella_inline.css" in loader._STYLESHEETS
|
||||
assert "/plugins/svrnty/umbrella_inline.js" in loader._SCRIPTS
|
||||
assert "/plugins/svrnty/cortex-os/runtime-health/runtime_health.css" in loader._STYLESHEETS
|
||||
assert "/plugins/svrnty/cortex-os/runtime-health/runtime_health.js" in loader._SCRIPTS
|
||||
# Audio processor for voice-message transcription
|
||||
assert len(loader._AUDIO_PROCESSORS) == 1
|
||||
|
||||
|
||||
87
tests/unit/test_cortex_os_runtime_health_route.py
Normal file
87
tests/unit/test_cortex_os_runtime_health_route.py
Normal file
@ -0,0 +1,87 @@
|
||||
import io
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
|
||||
from routes import cortex_os_runtime_health as route
|
||||
|
||||
|
||||
class FakeHandler:
|
||||
def __init__(self, command="GET"):
|
||||
self.command = command
|
||||
self.status_code = None
|
||||
self.headers = []
|
||||
self.wfile = io.BytesIO()
|
||||
|
||||
def send_response(self, status_code):
|
||||
self.status_code = status_code
|
||||
|
||||
def send_header(self, name, value):
|
||||
self.headers.append((name, value))
|
||||
|
||||
def end_headers(self):
|
||||
return None
|
||||
|
||||
def payload(self):
|
||||
return json.loads(self.wfile.getvalue().decode("utf-8"))
|
||||
|
||||
|
||||
def test_register_wires_get_runtime_health_route():
|
||||
api = Mock()
|
||||
api.logger.return_value = Mock()
|
||||
|
||||
route.register(api)
|
||||
|
||||
api.register_route.assert_called_once_with(
|
||||
"/api/cortex-os/runtime-health",
|
||||
"GET",
|
||||
route._handle_runtime_health,
|
||||
)
|
||||
|
||||
|
||||
def test_get_returns_runtime_health_envelope():
|
||||
handler = FakeHandler()
|
||||
|
||||
assert route._handle_runtime_health(handler, SimpleNamespace(query="")) is True
|
||||
|
||||
payload = handler.payload()
|
||||
assert handler.status_code == 200
|
||||
assert payload["ok"] is True
|
||||
assert payload["result"]["contract_id"] == "runtime-health/v0.1"
|
||||
assert payload["result"]["status"] == "unknown"
|
||||
assert payload["result"]["source_trace"]["live_probe"] is False
|
||||
assert payload["result"]["authority"]["runtime_state_mutation"] is False
|
||||
|
||||
|
||||
def test_host_signal_mapping_is_closed_and_redacted():
|
||||
payload = route.runtime_health_payload(
|
||||
{
|
||||
"health": "healthy",
|
||||
"agent_health": "degraded",
|
||||
"dashboard_status": "unavailable",
|
||||
"health_detail": "http://localhost:8000/raw",
|
||||
"agent_health_detail": "/home/svrnty/private",
|
||||
"dashboard_status_detail": "token=abc123",
|
||||
}
|
||||
)
|
||||
|
||||
assert payload["status"] == "unavailable"
|
||||
assert {signal["detail"] for signal in payload["signals"]} == {"redacted"}
|
||||
assert payload["source_trace"]["host_surfaces"] == [
|
||||
"health",
|
||||
"agent_health",
|
||||
"dashboard_status",
|
||||
]
|
||||
|
||||
|
||||
def test_non_get_and_query_targets_are_rejected():
|
||||
post_handler = FakeHandler(command="POST")
|
||||
query_handler = FakeHandler()
|
||||
|
||||
route._handle_runtime_health(post_handler, SimpleNamespace(query=""))
|
||||
route._handle_runtime_health(query_handler, SimpleNamespace(query="target=raw"))
|
||||
|
||||
assert post_handler.status_code == 405
|
||||
assert post_handler.payload()["ok"] is False
|
||||
assert query_handler.status_code == 400
|
||||
assert query_handler.payload()["error"]["code"] == "query_not_allowed"
|
||||
45
tests/unit/test_cortex_os_runtime_health_static.py
Normal file
45
tests/unit/test_cortex_os_runtime_health_static.py
Normal file
@ -0,0 +1,45 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
JS = ROOT / "static" / "cortex-os" / "runtime-health" / "runtime_health.js"
|
||||
CSS = ROOT / "static" / "cortex-os" / "runtime-health" / "runtime_health.css"
|
||||
|
||||
|
||||
def test_runtime_health_assets_exist_and_render_all_states():
|
||||
js = JS.read_text(encoding="utf-8")
|
||||
css = CSS.read_text(encoding="utf-8")
|
||||
|
||||
assert "/api/cortex-os/runtime-health" in js
|
||||
for state in ["healthy", "degraded", "unavailable", "unknown", "loading", "error", "redacted"]:
|
||||
assert state in js
|
||||
assert state in css
|
||||
|
||||
|
||||
def test_runtime_health_display_has_no_hidden_write_surface():
|
||||
js = JS.read_text(encoding="utf-8")
|
||||
forbidden = [
|
||||
"localStorage",
|
||||
"sessionStorage",
|
||||
"document.cookie",
|
||||
"<form",
|
||||
".submit(",
|
||||
"POST",
|
||||
"PUT",
|
||||
"PATCH",
|
||||
"DELETE",
|
||||
"/api/gateway/status",
|
||||
"/api/tools",
|
||||
"/api/mcp",
|
||||
]
|
||||
|
||||
for snippet in forbidden:
|
||||
assert snippet not in js
|
||||
|
||||
|
||||
def test_runtime_health_css_is_scoped_to_panel():
|
||||
css = CSS.read_text(encoding="utf-8")
|
||||
|
||||
assert ".cortex-os-runtime-health" in css
|
||||
assert "body {" not in css
|
||||
assert "#app" not in css
|
||||
Loading…
Reference in New Issue
Block a user