// node --test relay/test/guard.test.mjs (no dependencies, no network) import { test } from 'node:test'; import assert from 'node:assert/strict'; import { authVia, runCanon, keygen, signRun, verifyRun, machineTag, sameTag, checkRun, wantsReboot, feedLimit, retentionCutoff, machineForSecret, secretHash, newNonce, newSecret, FEED_LIMIT_MAX, RETENTION_DAYS, POST_ALLOWED, DROP_KINDS, mayRead } from '../lib/guard.mjs'; const T = 'ABCDEFGHIJKLMNOPQRST'; // the token shape: 20 characters const K = 'relaykeyrelaykeyrelaykeyrelaykeyrelaykeyrelayke'; // 48 const I = 'intakekeyintakekeyintakekeyinta'; // 32 const env = { RELAY_TOKEN: T, RELAY_KEY: K, LOG_INTAKE_KEY: I }; test('authVia: the header alone is the token tier (X24); the path token still works for the phone page', () => { assert.equal(authVia({ headers: { 'x-relay-token': T } }, env), 'token'); assert.equal(authVia({ query: { token: T }, headers: {} }, env), 'token'); assert.equal(authVia({ headers: { 'x-relay-token': T.slice(0, 19) + 'x' } }, env), null); assert.equal(authVia({ headers: {} }, env), null); }); test('authVia: three tiers; the intake key is its own tier and RELAY_INTAKE_COMPAT=0 closes it (X23)', () => { assert.equal(authVia({ headers: { 'x-igneum-key': K } }, env), 'key'); assert.equal(authVia({ headers: { 'x-igneum-key': I } }, env), 'intake'); assert.equal(authVia({ headers: { 'x-igneum-key': I } }, { ...env, LOG_INTAKE_KEY: '', LOG_INTAKE_KEY_NEXT: I }), 'intake'); assert.equal(authVia({ headers: { 'x-igneum-key': I } }, { ...env, RELAY_INTAKE_COMPAT: '0' }), null); assert.equal(authVia({ headers: { 'x-igneum-key': 'wrongwrongwrongwrongwrongwrongwr' } }, env), null); }); test('tiers: what each may post and read', () => { assert.equal(POST_ALLOWED.token.has('task'), true); assert.equal(POST_ALLOWED.key.has('task'), false); assert.equal(POST_ALLOWED.key.has('secret'), false); assert.deepEqual([...POST_ALLOWED.intake].sort(), ['drop', 'upload']); assert.equal(DROP_KINDS.intake.has('result'), false); assert.equal(DROP_KINDS.key.has('run'), false); assert.equal(DROP_KINDS.token, null); assert.deepEqual(['token', 'key', 'intake', null].map(mayRead), [true, true, false, false]); }); test('runCanon: deterministic, names the machine, the nonce, the flags and the body hash', () => { const a = runCanon({ to: 'PC1', nonce: 'a'.repeat(32), body: 'Write-Host hi', flags: { elevated: true } }); const b = runCanon({ to: 'PC1', nonce: 'a'.repeat(32), body: 'Write-Host hi', flags: { elevated: 1 } }); assert.equal(a, b); assert.match(a, /^igneum-relay-run\/1\nto=PC1\nnonce=a{32}\nelevated=1\nreboot_continue=0\nreboot=0\nbody_sha256=[0-9a-f]{64}\n$/); assert.notEqual(a, runCanon({ to: 'PC2', nonce: 'a'.repeat(32), body: 'Write-Host hi', flags: { elevated: true } })); assert.notEqual(a, runCanon({ to: 'PC1', nonce: 'a'.repeat(32), body: 'Write-Host hi ', flags: { elevated: true } })); assert.notEqual(a, runCanon({ to: 'PC1', nonce: 'a'.repeat(32), body: 'Write-Host hi', flags: {} })); }); test('Ed25519: a good signature verifies; a changed byte, another key or a malformed signature does not', () => { const { seed, pub } = keygen(); const other = keygen(); const canon = runCanon({ to: 'PC1', nonce: newNonce(), body: 'x' }); const sig = signRun(canon, seed); assert.equal(sig.length, 128); assert.equal(verifyRun(canon, sig, pub), true); assert.equal(verifyRun(canon + ' ', sig, pub), false); assert.equal(verifyRun(canon, sig, other.pub), false); assert.equal(verifyRun(canon, sig.slice(0, 127) + (sig.endsWith('0') ? '1' : '0'), pub), false); assert.equal(verifyRun(canon, 'nothex', pub), false); assert.equal(verifyRun(canon, sig, 'nothex'), false); }); test('machineTag: HMAC with the machine secret; sameTag compares in constant time and refuses malformed tags', () => { const s = newSecret(); const canon = runCanon({ to: 'PC1', nonce: newNonce(), body: 'x' }); const t = machineTag(s, canon); assert.equal(t.length, 64); assert.equal(sameTag(t, machineTag(s, canon)), true); assert.equal(sameTag(t, machineTag(newSecret(), canon)), false); assert.equal(sameTag(t, machineTag(s, canon + 'x')), false); assert.equal(sameTag(t, 'short'), false); }); test('checkRun: a run without the signature, the tag or the nonce is refused; a complete one passes (X23)', () => { const { seed, pub } = keygen(); const nonce = newNonce(); const body = 'Write-Host hi'; const flags = { elevated: true, nonce, mac: machineTag(newSecret(), runCanon({ to: 'PC1', nonce, body, flags: { elevated: true } })) }; flags.sig = signRun(runCanon({ to: 'PC1', nonce, body, flags }), seed); assert.equal(checkRun({ to: 'PC1', body, flags }, pub), null); assert.match(checkRun({ to: 'PC1', body, flags: {} }, pub), /nonce/); assert.match(checkRun({ to: 'PC1', body, flags: { nonce } }, pub), /mac/); assert.match(checkRun({ to: 'PC1', body, flags: { nonce, mac: flags.mac } }, pub), /sig/); assert.match(checkRun({ to: 'PC1', body, flags }, ''), /RELAY_RUN_PUB/); assert.match(checkRun({ to: 'PC1', body: body + ' ', flags }, pub), /does not verify/); assert.match(checkRun({ to: 'PC2', body, flags }, pub), /does not verify/); assert.match(checkRun({ to: 'PC1', body, flags: { ...flags, elevated: false } }, pub), /does not verify/); assert.match(checkRun({ to: 'all', body, flags }, pub), /one named machine/); }); test('wantsReboot: the marker on its own line only (X28)', () => { assert.equal(wantsReboot('features enabled\nRELAY-REBOOT\n'), true); assert.equal(wantsReboot('RELAY-REBOOT'), true); assert.equal(wantsReboot('a\r\nRELAY-REBOOT\r\nb'), true); assert.equal(wantsReboot('the script prints RELAY-REBOOT when it wants a restart\n'), false); assert.equal(wantsReboot('RELAY-REBOOT-NOT\n'), false); assert.equal(wantsReboot(''), false); }); test('feedLimit and retention (X26)', () => { assert.equal(feedLimit({}), 50); assert.equal(feedLimit({ limit: '500' }), FEED_LIMIT_MAX); assert.equal(feedLimit({ limit: '0' }), 50); assert.equal(feedLimit({ limit: '7' }), 7); assert.equal(RETENTION_DAYS, 30); assert.equal(retentionCutoff(Date.UTC(2026, 9, 5, 22, 0, 0)), '2026-09-05T22:00:00.000Z'); }); test('machineForSecret: the stored sha256 names the machine; a wrong or malformed secret names nothing (X27)', () => { const s = newSecret(); const rows = [{ name: 'PC1', secret_hash: secretHash(s) }, { name: 'PC2', secret_hash: secretHash(newSecret()) }, { name: 'Mac', secret_hash: null }]; assert.deepEqual(machineForSecret(s, rows), { name: 'PC1' }); assert.deepEqual(machineForSecret(newSecret(), rows), { error: 'unknown machine secret' }); assert.deepEqual(machineForSecret('short', rows), { error: 'x-machine-secret must be 64 hex' }); });