morphit/apps/ops-cli/scripts/canary-timestamp-parity-smoke.ts

92 lines
3.8 KiB
TypeScript

#!/usr/bin/env tsx
/**
* Smoke: the canary timestamp parser is implemented twice, and the two copies
* must never disagree (cp442).
*
* • `scripts/canary/verify.ts` — the operator-facing verifier CLI
* • `apps/ops-cli/src/canaryTime.ts` — used by `morphit-ops` health
*
* They can't share a module: the root workspace is CommonJS and ops-cli is ESM,
* so a named import across that boundary fails at runtime. So they're kept in
* lockstep here instead.
*
* Why this matters: the canary's freshness IS the security signal. If health
* reads a stamp as local time while the verifier reads it as UTC, an operator's
* dead-man's switch quietly acquires an hours-wide blind spot. If one accepts a
* typo'd month as a real date, a canary that should read `unparsable` reads
* `fresh` instead.
*/
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { parseCanaryTimestamp } from '../src/canaryTime.ts';
const __dirname = dirname(fileURLToPath(import.meta.url));
const REPO = join(__dirname, '..', '..', '..');
const verifySrc = readFileSync(join(REPO, 'scripts', 'canary', 'verify.ts'), 'utf8');
const opsSrc = readFileSync(join(__dirname, '..', 'src', 'canaryTime.ts'), 'utf8');
let pass = 0;
let fail = 0;
function check(name: string, ok: boolean): void {
if (ok) {
pass++;
console.log(` \u2713 ${name}`);
} else {
fail++;
console.error(` \u2717 ${name}`);
}
}
/** Pull a regex literal's source out of a TS file by a nearby anchor. */
function humanRegexOf(src: string): string | null {
const m = /\/\^\(\\d\{1,2\}\)[^\n]*?\/(?=[.;\s])/.exec(src);
return m ? m[0] : null;
}
function isoRegexOf(src: string): string | null {
const m = /\/\^\\d\{4\}-\\d\{2\}-\\d\{2\}T[^\n]*?\/(?=\.test)/.exec(src);
return m ? m[0] : null;
}
// ─── the two implementations are textually identical where it counts ──
const hVerify = humanRegexOf(verifySrc);
const hOps = humanRegexOf(opsSrc);
check('both files define the human-stamp regex', hVerify !== null && hOps !== null);
check('the human-stamp regex is IDENTICAL in both', hVerify === hOps);
const iVerify = isoRegexOf(verifySrc);
const iOps = isoRegexOf(opsSrc);
check('both files define the strict ISO guard', iVerify !== null && iOps !== null);
check('the strict ISO guard is IDENTICAL in both', iVerify === iOps);
check('neither falls back to a bare Date.parse of arbitrary text', !/return Date\.parse\(s\);\s*\n\}/.test(verifySrc) && !/return Date\.parse\(s\);\s*\n\}/.test(opsSrc));
check('both list all twelve months', (opsSrc.match(/'(january|december)'/g) ?? []).length === 2 && /december/.test(verifySrc));
// ─── behaviour (run against the ops-cli copy) ────────────────────────
const cases: [string, string | 'NaN'][] = [
['30 June, 2026 @ 16:45:18 UTC', '2026-06-30T16:45:18.000Z'],
['1 January, 2027 @ 00:00:00 UTC', '2027-01-01T00:00:00.000Z'],
['2026-07-22T23:45:18Z', '2026-07-22T23:45:18.000Z'],
['2026-07-22T23:45:18.123Z', '2026-07-22T23:45:18.123Z'],
// must NOT be guessed:
['2026-07-22 23:45:18', 'NaN'], // local-time ambiguity
['22 Julius, 2026 @ 23:45:18 UTC', 'NaN'], // typo'd month
['{{GENERATED_AT_ISO}}', 'NaN'], // un-substituted template
['22 July, 2026 @ 23:45:18', 'NaN'], // no UTC suffix
['', 'NaN']
];
for (const [input, want] of cases) {
const got = parseCanaryTimestamp(input);
const ok = want === 'NaN' ? Number.isNaN(got) : new Date(got).toISOString() === want;
check(`parses ${JSON.stringify(input)} -> ${want}`, ok);
}
console.log('');
if (fail === 0) {
console.log(`\u2713 all ${pass} canary-timestamp-parity scenarios passed`);
} else {
console.error(`\u2717 ${fail} of ${pass + fail} canary-timestamp-parity checks FAILED`);
process.exit(1);
}