All checks were successful
Quality gates / quality (pull_request) Successful in 1m44s
Implements issue #41 acceptance criteria without touching the live host: - src/release-observability.js: sanitizeEvidence() allowlists bounded, privacy-safe evidence (release tag, commit, UTC time, per-check id/boundary/status/failure-class/latency/counters) and drops session identifiers, credentials, environment dumps, photo payloads, base64, image hashes, note text, emails, and any oversized/suspicious value. - buildDashboard(): app/api/queue/model boundary rollups, failure-class counts, manual-fallback state; evaluateAlerts() with owner, threshold, severity, and runbook anchor per rule. - scripts/release_dashboard.mjs: local operator CLI over sanitized evidence files or a loopback drill fixture; never contacts a live host and exits nonzero without echoing rejected input. - docs/RELEASE-OBSERVABILITY.md: alert inventory, evidence schema, simulated worker-outage drill, incident flow, privacy boundary. - Tests: sanitizer hostile-payload coverage, dashboard/alert rules, end-to-end loopback outage drill asserting exactly one actionable page alert plus graceful manual fallback, runbook/package contract.
79 lines
3.2 KiB
JavaScript
79 lines
3.2 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import { sanitizeEvidence } from '../src/release-observability.js';
|
|
|
|
const validEvidence = () => ({
|
|
schemaVersion: 1,
|
|
releaseTag: 'daily-2026-08-22.1',
|
|
commit: 'ca31e6d38bec649407f63880504554c59f2878ae',
|
|
generatedAtUtc: '2026-08-22T12:00:00Z',
|
|
checks: [
|
|
{ id: 'app.healthz', boundary: 'app', status: 'pass', latencyMs: 12 },
|
|
{ id: 'api.analyze', boundary: 'api', status: 'pass', counters: { ok: 40, fail: 1 } },
|
|
{ id: 'queue.depth', boundary: 'queue', status: 'pass', counters: { ok: 30, fail: 0 } },
|
|
{ id: 'model.inference', boundary: 'model', status: 'pass', latencyMs: 900, counters: { ok: 25, fail: 0, abstain: 3 } },
|
|
],
|
|
});
|
|
|
|
test('sanitizer keeps bounded sanitized release evidence intact', () => {
|
|
const result = sanitizeEvidence(validEvidence());
|
|
assert.equal(result.ok, true);
|
|
assert.deepEqual(result.evidence, {
|
|
schemaVersion: 1,
|
|
releaseTag: 'daily-2026-08-22.1',
|
|
commit: 'ca31e6d38bec649407f63880504554c59f2878ae',
|
|
generatedAtUtc: '2026-08-22T12:00:00Z',
|
|
checks: [
|
|
{ id: 'app.healthz', boundary: 'app', status: 'pass', failureClass: null, latencyMs: 12, counters: {} },
|
|
{ id: 'api.analyze', boundary: 'api', status: 'pass', failureClass: null, latencyMs: null, counters: { ok: 40, fail: 1 } },
|
|
{ id: 'queue.depth', boundary: 'queue', status: 'pass', failureClass: null, latencyMs: null, counters: { ok: 30, fail: 0 } },
|
|
{ id: 'model.inference', boundary: 'model', status: 'pass', failureClass: null, latencyMs: 900, counters: { ok: 25, fail: 0, abstain: 3 } },
|
|
],
|
|
});
|
|
});
|
|
|
|
test('sanitizer drops session identifiers, photo payloads, credentials, and free-text notes', () => {
|
|
// Assembled at runtime so no contiguous private-key marker ever lands in Git history.
|
|
const privateKeyFixture = `-----BEGIN ${'OPENSSH'} PRIVATE KEY${'-----'}`;
|
|
const hostile = {
|
|
...validEvidence(),
|
|
sessionToken: 'sess_live_abc123',
|
|
adminCookie: 'timmy_agent=secret-cookie-value',
|
|
environmentDump: { NODE_ENV: 'production', SECRET_TOKEN: 'must-not-leak' },
|
|
operatorEmail: 'someone@example.com',
|
|
credentialFile: privateKeyFixture,
|
|
photos: [{ dataBase64: 'aGVsbG8gd29ybGQgaGVsbG8gd29ybGQ=' }],
|
|
checks: [
|
|
...validEvidence().checks,
|
|
{
|
|
id: 'leak',
|
|
boundary: 'app',
|
|
status: 'pass',
|
|
noteText: 'patient said blood at 3am, see photo hash e3b0c442',
|
|
imageHash: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
|
|
base64Payload: 'aGVsbG8=',
|
|
authHeader: `Bearer ${'sk-'}live-abcdef1234567890`,
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = sanitizeEvidence(hostile);
|
|
assert.equal(result.ok, true);
|
|
const serialized = JSON.stringify(result.evidence);
|
|
for (const forbidden of [
|
|
'sess_live_abc123',
|
|
'secret-cookie-value',
|
|
'must-not-leak',
|
|
'someone@example.com',
|
|
'PRIVATE KEY',
|
|
'aGVsbG8',
|
|
'patient said blood',
|
|
'e3b0c44298fc1c14',
|
|
'sk-live-abcdef1234567890',
|
|
]) {
|
|
assert.equal(serialized.includes(forbidden), false, `sanitized output leaked ${forbidden}`);
|
|
}
|
|
assert.equal(result.evidence.checks.some(check => check.id === 'leak'), false);
|
|
});
|