#!/usr/bin/env node // Local operator surface for release observability (issue #41). // Consumes only sanitized evidence files or a loopback drill fixture. // Never contacts a live host, never accepts credentials, never prints secrets. import { readFile } from 'node:fs/promises'; import { sanitizeEvidence, buildDashboard, evaluateAlerts } from '../src/release-observability.js'; function argValue(args, flag) { const index = args.indexOf(flag); if (index === -1) return null; return args[index + 1] || null; } // Terminal safety: strip C0/C1 control characters — newline and carriage // return included — from any dynamically produced text before it reaches // stdout/stderr. Hostile file paths or fixture payloads can therefore never // forge additional terminal lines (e.g. a fake "PAGE worker.outage"): the // only line boundaries in CLI output are the ones this program authors. function controlSafe(text) { return String(text) .replace(/[\u0000-\u001F\u007F-\u009F]/g, ''); } async function loadEvidence(source) { if (source.drillOrigin) { const response = await fetch(`${source.drillOrigin.replace(/\/$/, '')}/api/drill/checks`, { signal: AbortSignal.timeout(5_000) }); if (!response.ok) throw new Error(`drill fixture returned ${response.status}`); const body = await response.json(); return { schemaVersion: 1, releaseTag: controlSafe('daily-2026-08-22.1'), commit: 'ca31e6d38bec649407f63880504554c59f2878ae', generatedAtUtc: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'), checks: Array.isArray(body.checks) ? body.checks : [], }; } const raw = JSON.parse(await readFile(source.evidencePath, 'utf8')); return raw; } function renderDashboard(dashboard, alerts) { const lines = []; lines.push('RELEASE OBSERVABILITY DASHBOARD'); lines.push(`release ${dashboard.identity.releaseTag} · commit ${dashboard.identity.commit.slice(0, 12)} · evidence ${dashboard.identity.generatedAtUtc}`); lines.push(''); for (const boundary of ['app', 'api', 'queue', 'model']) { const stats = dashboard.boundaries[boundary]; const latency = stats.latencyMs == null ? '' : ` · max latency ${stats.latencyMs}ms`; const counterBits = Object.keys(stats.counters).sort() .map(key => `${key}=${stats.counters[key]}`) .join(' '); const counterText = counterBits ? ` · ${counterBits}` : ''; lines.push(`${boundary.padEnd(6)}${stats.pass}/${stats.checks} pass · fail ${stats.fail} · degraded ${stats.degraded}${latency}${counterText}`); } lines.push(''); const failureEntries = Object.entries(dashboard.failureClasses); if (failureEntries.length === 0) { lines.push('failure classes: none'); } else { for (const [failureClass, count] of failureEntries.sort((a, b) => b[1] - a[1])) { lines.push(`failure class ${failureClass}: ${count}`); } } lines.push(''); lines.push(`alerts (${alerts.length})`); for (const alert of alerts) { lines.push(`[${alert.severity.toUpperCase()}] ${alert.id} — owner ${alert.owner}, observed ${alert.count} >= threshold ${alert.threshold}`); lines.push(` ${alert.message}`); lines.push(` runbook: ${alert.runbook}`); } if (alerts.length === 0) lines.push('no alert conditions met'); return lines.join('\n'); } async function main() { const args = process.argv.slice(2); if (args.includes('--self-check')) { console.log('release-observability module self-check: exports OK'); return 0; } const drillOrigin = argValue(args, '--drill-origin'); const evidencePath = argValue(args, '--evidence'); if (Boolean(drillOrigin) === Boolean(evidencePath)) { console.error('usage: node scripts/release_dashboard.mjs (--evidence | --drill-origin )'); return 2; } // Gate every network path before any fetch can happen: a drill may only // ever address a validated bare loopback origin. let validatedOrigin = null; if (drillOrigin) { try { validatedOrigin = validateLoopbackOrigin(drillOrigin); } catch (error) { console.error(controlSafe(error.message)); return 2; } } let rawEvidence; try { rawEvidence = await loadEvidence({ drillOrigin: validatedOrigin, evidencePath }); } catch { // Fixed wording on purpose: interpolating filesystem error messages would // echo attacker-controlled path bytes (even sanitized) into the terminal. console.error('release_dashboard: cannot read sanitized evidence (unreadable file or invalid JSON). No contents are echoed.'); return 2; } // Drill mode owns its whole flow: the baseline gate must speak with one // voice ("not a genuine drill baseline") whether the fixture served // unsanitizable evidence or merely unhealthy checks, and nothing may be // rendered or flipped until the baseline proves genuinely healthy. if (drillOrigin) return runDrill({ drillOrigin: validatedOrigin }); const validated = sanitizeEvidence(rawEvidence); if (!validated.ok) { console.error('release_dashboard: evidence failed sanitization (schema mismatch, forbidden fields, or unbounded values). Nothing was rendered.'); return 2; } const dashboard = buildDashboard(validated.evidence); const alerts = evaluateAlerts(dashboard); console.log(renderDashboard(dashboard, alerts)); console.log(''); console.log(manualFallbackLine(dashboard.manualFallback)); return alerts.some(alert => alert.severity === 'page') ? 1 : 0; } // Truthful operator wording: the manual-fallback line is a safety statement, // so each deterministic state says exactly what is known. Availability is // only ever claimed from explicit passes; an unknown app boundary reads as // unknown and demands hand verification — never as quiet health. const FALLBACK_PHRASES = { 'none-required': 'all checks explicitly passing; no degradation observed; fallback not required', 'local-journal': 'degraded elsewhere; local journal remains usable', 'app-down': 'app boundary is down; local journal cannot be served', 'app-state-unknown': 'app state unknown; verify the local journal by hand before relying on it', }; function manualFallbackLine(fallback, { shout = false } = {}) { const label = fallback.available === null ? (shout ? 'UNKNOWN' : 'unknown') : fallback.available ? (shout ? 'AVAILABLE' : 'available') : (shout ? 'UNAVAILABLE' : 'unavailable'); return `manual fallback: ${label} — ${FALLBACK_PHRASES[fallback.reason] ?? fallback.reason}`; } // A drill may only ever talk to a throwaway fixture on 127.0.0.1. The origin // must be a bare http URL whose host is exactly the loopback address: no // credentials, no DNS names, no alternative IP encodings, no IPv6, no path, // query, or fragment, and no scheme other than http. const LOOPBACK_ORIGIN_PATTERN = /^http:\/\/127\.0\.0\.1:[0-9]{1,5}$/; function validateLoopbackOrigin(rawOrigin) { if (typeof rawOrigin !== 'string') { throw new Error('drill origin rejected: expected an http://127.0.0.1: URL'); } // Grammar gate runs on the RAW string first: the WHATWG URL parser // canonicalizes hostile host encodings (hex octets, decimal IP integers, // percent-encoded dots) into a clean-looking 127.0.0.1, so a normalized // string can never be trusted on its own. if (!LOOPBACK_ORIGIN_PATTERN.test(rawOrigin)) { throw new Error('drill origin rejected: only a bare http://127.0.0.1: loopback origin is permitted'); } let parsed; try { parsed = new URL(rawOrigin); } catch { throw new Error('drill origin rejected: not a valid URL'); } // Round-trip defense in depth: the parsed form must be byte-identical to // what was supplied, proving no hidden credentials, path, query, fragment, // or alternative host encoding was smuggled past the grammar. if (parsed.toString().replace(/\/$/, '') !== rawOrigin) { throw new Error('drill origin rejected: URL did not round-trip as a bare loopback origin'); } if (parsed.protocol !== 'http:' || parsed.hostname !== '127.0.0.1') { throw new Error('drill origin rejected: host must be exactly http://127.0.0.1'); } const port = Number(parsed.port); if (!Number.isInteger(port) || port < 1 || port > 65535) { throw new Error('drill origin rejected: port must be between 1 and 65535'); } return rawOrigin; } async function runDrill({ drillOrigin }) { let origin; try { origin = validateLoopbackOrigin(drillOrigin); } catch (error) { console.error(controlSafe(error.message)); return 2; } // Genuine baseline: read the fixture's own current state BEFORE anything is // announced or flipped. A drill may only start from proven health — every // required boundary check must explicitly pass and zero alerts may fire. // Unknown, degraded, malformed, missing-boundary, or warning baselines are // refused here, so stdout stays empty whenever no drill actually ran. const preRaw = await loadEvidence({ drillOrigin }); const preValidated = sanitizeEvidence(preRaw); if (!preValidated.ok) { console.error('release_dashboard: fixture evidence is unsanitizable: not a genuine drill baseline (schema mismatch, forbidden fields, or unbounded values). Nothing will be rendered or flipped.'); return 2; } const preDashboard = buildDashboard(preValidated.evidence); const preAlerts = evaluateAlerts(preDashboard); const allExplicitlyPassing = Object.values(preDashboard.boundaries).every( boundary => boundary.checks > 0 && boundary.pass === boundary.checks, ); if (!allExplicitlyPassing || preAlerts.length > 0) { console.error('release_dashboard: fixture is not healthy before the drill: not a genuine drill baseline (every required boundary check must explicitly pass with zero alerts). Refusing to flip an already-down or uncertain worker.'); return 2; } console.log(''); console.log('WORKER OUTAGE DRILL (simulated fixture on loopback; no live host is contacted)'); console.log('pre-drill baseline: every required boundary check explicitly passing; alerts: none'); console.log('pre-drill: healthy (0 page alerts)'); try { const response = await fetch(`${origin}/drill/outage`, { method: 'POST', signal: AbortSignal.timeout(5_000) }); if (!response.ok) throw new Error(`fixture returned ${response.status}`); } catch { // Fixed wording on purpose: fetch failures can embed attacker-chosen URL // text; echoing it (even sanitized) has no operational value. console.error('release_dashboard: drill switch failed. The fixture switch was not verifiably flipped.'); return 2; } const postRaw = await loadEvidence({ drillOrigin }); const postValidated = sanitizeEvidence(postRaw); if (!postValidated.ok) { console.error('release_dashboard: post-outage evidence failed sanitization.'); return 2; } const postDashboard = buildDashboard(postValidated.evidence); const postAlerts = evaluateAlerts(postDashboard); const pageAlerts = postAlerts.filter(alert => alert.severity === 'page'); if (pageAlerts.length === 0) { console.log('no outage observed after flip: the fixture never transitioned from healthy to outage.'); console.log('DRILL FAIL'); return 1; } console.log(`post-outage: exactly 1 alert expected, found ${pageAlerts.length}`); for (const alert of pageAlerts) { console.log(` ${alert.severity.toUpperCase()} ${alert.message.replace(/^PAGE /, '')}`); console.log(` owner ${alert.owner} · threshold ${alert.threshold} · runbook ${alert.runbook}`); } console.log(manualFallbackLine(postDashboard.manualFallback, { shout: true })); const pass = pageAlerts.length === 1 && pageAlerts[0].id === 'worker.outage' && postDashboard.manualFallback.available === true; console.log(pass ? 'DRILL PASS' : 'DRILL FAIL'); return pass ? 0 : 1; } process.exitCode = await main();