diff --git a/static/cortex-os/runtime-health/runtime_health.css b/static/cortex-os/runtime-health/runtime_health.css index 9bd83de..4370190 100644 --- a/static/cortex-os/runtime-health/runtime_health.css +++ b/static/cortex-os/runtime-health/runtime_health.css @@ -74,3 +74,36 @@ main.main:not(.svrnty-showing-cortex-os) .cortex-os-runtime-health { .cortex-os-runtime-health__signals dd { font-weight: 700; } + +.cortex-os-runtime-health__details { + border-top: 1px solid rgba(19, 82, 121, 0.14); + display: grid; + gap: 10px; + margin-top: 12px; + padding-top: 12px; +} + +.cortex-os-runtime-health__detail-group h3 { + margin: 0 0 4px; + font-size: 12px; + font-weight: 700; + text-transform: uppercase; +} + +.cortex-os-runtime-health__detail-list { + display: grid; + grid-template-columns: minmax(116px, 0.8fr) minmax(0, 1.2fr); + gap: 4px 10px; + margin: 0; +} + +.cortex-os-runtime-health__detail-list dt, +.cortex-os-runtime-health__detail-list dd { + margin: 0; + min-width: 0; + overflow-wrap: anywhere; +} + +.cortex-os-runtime-health__detail-list dt { + color: #44515f; +} diff --git a/static/cortex-os/runtime-health/runtime_health.js b/static/cortex-os/runtime-health/runtime_health.js index 7e16b18..1431616 100644 --- a/static/cortex-os/runtime-health/runtime_health.js +++ b/static/cortex-os/runtime-health/runtime_health.js @@ -38,10 +38,15 @@ list.className = "cortex-os-runtime-health__signals"; list.setAttribute("data-role", "signals"); + var details = document.createElement("section"); + details.className = "cortex-os-runtime-health__details"; + details.setAttribute("data-role", "details"); + panel.appendChild(title); panel.appendChild(badge); panel.appendChild(summary); panel.appendChild(list); + panel.appendChild(details); var target = document.querySelector("main.main"); if (!target) { @@ -51,13 +56,14 @@ return panel; } - function setState(panel, state, headline, detail, signals) { + function setState(panel, state, headline, detail, signals, payloadDetails) { var nextState = states.indexOf(state) >= 0 ? state : "unknown"; panel.setAttribute("data-state", nextState); panel.querySelector("[data-role='headline']").textContent = headline || "Runtime Health"; panel.querySelector("[data-role='status']").textContent = nextState; panel.querySelector("[data-role='summary']").textContent = detail || "redacted"; renderSignals(panel.querySelector("[data-role='signals']"), signals || []); + renderDetails(panel.querySelector("[data-role='details']"), payloadDetails || {}); } function renderSignals(list, signals) { @@ -75,6 +81,69 @@ }); } + function renderKeyValues(container, title, rows) { + var group = document.createElement("section"); + group.className = "cortex-os-runtime-health__detail-group"; + + var heading = document.createElement("h3"); + heading.textContent = title; + group.appendChild(heading); + + var list = document.createElement("dl"); + list.className = "cortex-os-runtime-health__detail-list"; + rows.forEach(function (row) { + var key = document.createElement("dt"); + var value = document.createElement("dd"); + key.textContent = row.key || "redacted"; + value.textContent = row.value || "redacted"; + list.appendChild(key); + list.appendChild(value); + }); + group.appendChild(list); + container.appendChild(group); + } + + function renderDetails(container, detail) { + container.textContent = ""; + var signals = detail.signals || []; + var warnings = detail.warnings || []; + var redactions = detail.redactions || []; + var sourceTrace = detail.source_trace || []; + var authority = detail.authority || {}; + var allAuthorityDenied = Object.keys(authority).every(function (key) { + return authority[key] === false; + }); + + renderKeyValues(container, "Signals", signals.slice(0, 3).map(function (signal) { + return { + key: signal.signal_id || "redacted", + value: (signal.state || "unknown") + " | " + (signal.redacted ? "redacted" : "visible") + " | " + (signal.summary || "redacted") + }; + })); + renderKeyValues(container, "Warnings", warnings.slice(0, 3).map(function (warning) { + return { + key: warning.code || "redacted", + value: warning.message || "redacted" + }; + })); + renderKeyValues(container, "Redactions", redactions.slice(0, 4).map(function (redaction) { + return { + key: redaction.reason_code || "redacted", + value: redaction.label || "redacted" + }; + })); + renderKeyValues(container, "Source Trace", sourceTrace.slice(0, 3).map(function (source) { + return { + key: source.source_kind || "redacted", + value: source.label || "redacted" + }; + })); + renderKeyValues(container, "Authority", [{ + key: "all denied", + value: allAuthorityDenied ? "true" : "review required" + }]); + } + function renderPayload(panel, payload) { if (!payload || payload.ok !== true || !payload.result) { setState(panel, "error", "Runtime Health is unavailable.", "Runtime Health is unavailable.", []); @@ -87,6 +156,13 @@ displaySummary.headline, displaySummary.detail, payload.result.signals, + { + signals: payload.result.signals, + warnings: payload.result.warnings, + redactions: payload.result.redactions, + source_trace: payload.result.source_trace, + authority: payload.result.authority + } ); } diff --git a/tests/unit/test_cortex_os_runtime_health_static.py b/tests/unit/test_cortex_os_runtime_health_static.py index c2caf13..dcbb9e1 100644 --- a/tests/unit/test_cortex_os_runtime_health_static.py +++ b/tests/unit/test_cortex_os_runtime_health_static.py @@ -33,6 +33,10 @@ def test_runtime_health_display_has_no_hidden_write_surface(): "window.open", "eval(", "new Function", + "JSON.stringify", + "Object.keys(payload", + "Object.entries(payload", + "clipboard", "innerHTML", "insertAdjacentHTML", "outerHTML", @@ -85,6 +89,10 @@ def test_runtime_health_display_consumes_canonical_envelope_only(): "signal.signal_id", "signal.state", "signal.summary", + "payload.result.warnings", + "payload.result.redactions", + "payload.result.source_trace", + "payload.result.authority", ]: assert snippet in js for forbidden in [ @@ -101,3 +109,30 @@ def test_runtime_health_display_consumes_canonical_envelope_only(): "authority.delegated_memory_grant", ]: assert forbidden not in js + + +def test_runtime_health_detail_surface_is_bounded_and_text_only(): + js = JS.read_text(encoding="utf-8") + css = CSS.read_text(encoding="utf-8") + + for snippet in [ + 'details.setAttribute("data-role", "details")', + "renderDetails(", + "renderKeyValues(", + "signals.slice(0, 3)", + "warnings.slice(0, 3)", + "redactions.slice(0, 4)", + "sourceTrace.slice(0, 3)", + "allAuthorityDenied", + ".every(function (key)", + "textContent", + ]: + assert snippet in js + for snippet in [ + ".cortex-os-runtime-health__details", + ".cortex-os-runtime-health__detail-group", + ".cortex-os-runtime-health__detail-list", + ]: + assert snippet in css + for forbidden in ["body {", "main {", "#app", ".panel"]: + assert forbidden not in css