Files
chimera-Public/test/server/ch-1207-etahen-link-operations.test.js
T

617 lines
64 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { SecretsStore } = require('../../src/security/secrets-store');
const { canonical, signEnvelope, createEnvelopeVerifier } = require('../../src/services/etahen-link-agent');
const { createFileJobJournal, createEtahenLinkOrchestrator } = require('../../src/services/etahen-link-orchestrator');
const {
createEtahenLinkKeyring,
createEtahenLinkAuditLedger,
createEtahenLinkRecoverySupervisor,
openManagedEtahenLinkJournal,
} = require('../../src/services/etahen-link-operations');
const runtimeEpoch = 'runtime_12345678';
function fixture(t, options = {}) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-link-operations-'));
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
let clock = options.now ?? 1_000_000;
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.enc.json'), keyFile: path.join(root, 'secrets', 'master.key') });
const audits = [];
const keyring = createEtahenLinkKeyring({
secrets,
stateFile: path.join(root, 'link', 'keyring.json'),
root: path.join(root, 'link'),
now: () => clock,
randomBytes: size => Buffer.alloc(size, options.randomByte ?? 0x11),
audit: (event, details) => audits.push({ event, details }),
});
return { root, secrets, keyring, audits, now: () => clock, advance: ms => { clock += ms; } };
}
function job(id = 'job_rotate1234') { return { jobId: id, type: 'package.install', runtimeEpoch, confirmationEpoch: runtimeEpoch, input: { artifactId: 'artifact_12345678' } }; }
test('keyring bootstraps encrypted material and exposes identifiers only', t => {
const f = fixture(t); const status = f.keyring.status();
assert.match(status.activeKeyId, /^key_[a-f0-9]{24}$/); assert.equal(status.pending, null); assert.deepEqual(status.previousKeyIds, []);
assert.doesNotMatch(JSON.stringify(status), /1111111111111111/);
const publicState = fs.readFileSync(path.join(f.root, 'link', 'keyring.json'), 'utf8');
assert.doesNotMatch(publicState, /1111111111111111/); assert.doesNotMatch(publicState, /journal\.[A-Za-z0-9_-]+/);
assert.match(fs.readFileSync(path.join(f.root, 'secrets', 'secrets.enc.json'), 'utf8'), /"data"/);
});
test('staged rotation atomically rekeys a journal without changing jobs', t => {
const f = fixture(t); const opened = openManagedEtahenLinkJournal({ file: path.join(f.root, 'link', 'jobs.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now });
opened.journal.begin(job(), 'a'.repeat(64)); const before = opened.journal.get('job_rotate1234'); const oldKeyId = opened.journal.integrity().keyId;
const pending = f.keyring.prepareRotation({ reason: 'scheduled-maintenance' });
const rotated = f.keyring.commitRotation(opened.journal);
assert.equal(rotated.activeKeyId, pending.keyId); assert.notEqual(rotated.activeKeyId, oldKeyId);
const after = opened.journal.get('job_rotate1234'); assert.deepEqual({ ...after, recordHash: null }, { ...before, recordHash: null }); assert.notEqual(after.recordHash, before.recordHash);
assert.equal(openManagedEtahenLinkJournal({ file: path.join(f.root, 'link', 'jobs.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now }).journal.integrity().keyId, pending.keyId);
assert.throws(() => f.keyring.resolveJournalKey(oldKeyId), /retired/i);
});
test('rotation fails before retiring a key shared by multiple durable journals', t => {
const f = fixture(t); const directory = path.join(f.root, 'link');
const first = openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs-one.json'), root: directory, keyring: f.keyring, now: f.now }).journal;
const second = openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs-two.json'), root: directory, keyring: f.keyring, now: f.now }).journal;
first.begin(job('job_multijrnl1'), '1'.repeat(64)); second.begin(job('job_multijrnl2'), '2'.repeat(64));
assert.throws(() => f.keyring.prepareRotation({ reason: 'must-rekey-all-journals' }), error => error?.code === 'ETAHEN_KEYRING_JOURNAL'); assert.equal(f.keyring.status().pending, null);
assert.equal(openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs-one.json'), root: directory, keyring: f.keyring, now: f.now }).journal.get('job_multijrnl1').status, 'accepted');
assert.equal(openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs-two.json'), root: directory, keyring: f.keyring, now: f.now }).journal.get('job_multijrnl2').status, 'accepted');
});
test('rotation target binding prevents an unrelated journal from aborting an in-flight rekey', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const firstFile = path.join(directory, 'jobs-target.json'); const secondFile = path.join(directory, 'jobs-racer.json');
const first = openManagedEtahenLinkJournal({ file: firstFile, root: directory, keyring: f.keyring, now: f.now }).journal; first.begin(job('job_targetbind'), '3'.repeat(64));
const pending = f.keyring.prepareRotation({ reason: 'bind-rekey-target' });
const hooked = { integrity: () => first.integrity(), rotateIntegrityKey(descriptor) { const result = first.rotateIntegrityKey(descriptor); assert.throws(() => openManagedEtahenLinkJournal({ file: secondFile, root: directory, keyring: f.keyring, now: f.now }), error => error?.code === 'ETAHEN_KEYRING_JOURNAL'); return result; } };
const committed = f.keyring.commitRotation(hooked); assert.equal(committed.activeKeyId, pending.keyId); assert.equal(committed.pending, null);
assert.equal(openManagedEtahenLinkJournal({ file: firstFile, root: directory, keyring: f.keyring, now: f.now }).journal.get('job_targetbind').status, 'accepted');
});
test('a durable rotation binding cannot be retargeted before its first journal write', t => {
const f = fixture(t); const activeKeyId = f.keyring.status().activeKeyId; const firstId = `journal_${'a'.repeat(24)}`; const secondId = `journal_${'b'.repeat(24)}`;
f.keyring.prepareRotation({ reason: 'bind-empty-target' });
const interrupted = { integrity: () => ({ keyId: activeKeyId, commitmentId: firstId }), rotateIntegrityKey() { throw Object.assign(new Error('simulated rekey interruption'), { code: 'REKEY_INTERRUPTED' }); } };
assert.throws(() => f.keyring.commitRotation(interrupted), error => error?.code === 'REKEY_INTERRUPTED');
const bound = f.keyring.status().pending; assert.equal(bound.phase, 'rekeying'); assert.equal(bound.targetJournalId, firstId);
const unrelated = { integrity: () => ({ keyId: activeKeyId, commitmentId: secondId }), rotateIntegrityKey() { throw new Error('must not run'); } };
assert.throws(() => f.keyring.commitRotation(unrelated), error => error?.code === 'ETAHEN_KEYRING_JOURNAL'); assert.equal(f.keyring.status().pending.targetJournalId, firstId);
assert.equal(f.keyring.reconcileJournalKey(activeKeyId, firstId).outcome, 'pending-aborted');
});
test('empty managed journals register durably and block unsafe single-target rotation', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const firstFile = path.join(directory, 'jobs-empty-a.json'); const secondFile = path.join(directory, 'jobs-empty-b.json');
const first = openManagedEtahenLinkJournal({ file: firstFile, root: directory, keyring: f.keyring, now: f.now }).journal;
const second = openManagedEtahenLinkJournal({ file: secondFile, root: directory, keyring: f.keyring, now: f.now }).journal;
assert.equal(f.keyring.journalAnchor(first.integrity().commitmentId).generation, 0); assert.equal(f.keyring.journalAnchor(second.integrity().commitmentId).generation, 0);
assert.throws(() => f.keyring.prepareRotation({ reason: 'must-not-strand-empty-writer' }), error => error?.code === 'ETAHEN_KEYRING_JOURNAL');
assert.equal(second.begin(job('job_emptywriter'), '4'.repeat(64)).status, 'accepted');
assert.equal(openManagedEtahenLinkJournal({ file: secondFile, root: directory, keyring: f.keyring, now: f.now }).journal.get('job_emptywriter').status, 'accepted');
});
test('journal and audit commitment caps reject before corrupting keyring state', t => {
const f = fixture(t); const directory = path.join(f.root, 'link');
for (let index = 0; index < 32; index += 1) openManagedEtahenLinkJournal({ file: path.join(directory, `jobs-cap-${index}.json`), root: directory, keyring: f.keyring, now: f.now });
assert.throws(() => openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs-cap-overflow.json'), root: directory, keyring: f.keyring, now: f.now }), error => error?.code === 'ETAHEN_KEYRING_RETENTION');
assert.doesNotThrow(() => createEtahenLinkKeyring({ secrets: f.secrets, stateFile: path.join(directory, 'keyring.json'), root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0x34) }));
for (let index = 0; index < 32; index += 1) createEtahenLinkAuditLedger({ file: path.join(directory, `audit-cap-${index}.json`), root: directory, keyring: f.keyring, now: f.now }).append('etahen.link.audit.cap', { index, outcome: 'allowed' });
const overflow = createEtahenLinkAuditLedger({ file: path.join(directory, 'audit-cap-overflow.json'), root: directory, keyring: f.keyring, now: f.now });
assert.throws(() => overflow.append('etahen.link.audit.cap', { index: 32, outcome: 'denied' }), error => error?.code === 'ETAHEN_KEYRING_RETENTION');
const publicState = JSON.parse(fs.readFileSync(path.join(directory, 'keyring.json'), 'utf8')); assert.equal(Object.keys(publicState.journalAnchors).length, 32); assert.equal(Object.keys(publicState.auditAnchors).length, 32);
assert.doesNotThrow(() => createEtahenLinkKeyring({ secrets: f.secrets, stateFile: path.join(directory, 'keyring.json'), root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0x35) }));
});
test('failed rotation persistence does not advance in-memory key state', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'keyring.json'); const initialBytes = fs.statSync(file).size;
const constrained = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: file, root: path.dirname(file), now: f.now, randomBytes: size => Buffer.alloc(size, 0x22), maxBytes: initialBytes + 8 });
assert.throws(() => constrained.prepareRotation({ reason: 'quota-interruption' }), error => error?.code === 'ETAHEN_OPERATIONS_QUOTA');
assert.equal(constrained.status().pending, null);
const reopened = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: file, root: path.dirname(file), now: f.now, randomBytes: size => Buffer.alloc(size, 0x33) });
assert.equal(reopened.status().pending, null); assert.equal(reopened.status().activeKeyId, constrained.status().activeKeyId);
});
test('stale keyring writers cannot overwrite newer authenticated state', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'keyring.json');
const stale = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: file, root: path.dirname(file), now: f.now, randomBytes: size => Buffer.alloc(size, 0x44) });
const prepared = f.keyring.prepareRotation({ reason: 'authoritative-rotation' });
assert.throws(() => stale.prepareRotation({ reason: 'stale-rotation' }), error => error?.code === 'ETAHEN_KEYRING_CONCURRENT');
const reopened = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: file, root: path.dirname(file), now: f.now, randomBytes: size => Buffer.alloc(size, 0x55) });
assert.equal(reopened.status().pending.keyId, prepared.keyId); assert.equal(reopened.status().pending.reason, 'authoritative-rotation');
});
test('key rotation audit intent survives a sink interruption and replays idempotently', t => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-link-key-audit-')); t.after(() => fs.rmSync(root, { recursive: true, force: true }));
const secretOptions = { filePath: path.join(root, 'secrets', 'secrets.enc.json'), keyFile: path.join(root, 'secrets', 'master.key') }; const stateFile = path.join(root, 'link', 'keyring.json');
const events = []; const dedupe = new Set(); let interruptPrepared = true;
const audit = (event, details, options = {}) => {
if (event === 'etahen.link.keyring.rotation-prepared' && interruptPrepared) { interruptPrepared = false; throw Object.assign(new Error('audit unavailable'), { code: 'AUDIT_DOWN' }); }
if (options.dedupeKey && dedupe.has(options.dedupeKey)) return; if (options.dedupeKey) dedupe.add(options.dedupeKey); events.push({ event, details, options });
};
const first = createEtahenLinkKeyring({ secrets: new SecretsStore(secretOptions), stateFile, root: path.dirname(stateFile), now: () => 1_000_000, randomBytes: size => Buffer.alloc(size, 0x61), audit });
assert.throws(() => first.prepareRotation({ reason: 'durable-audit-replay' }), error => error?.code === 'AUDIT_DOWN'); assert.ok(first.status().pending);
const reopened = createEtahenLinkKeyring({ secrets: new SecretsStore(secretOptions), stateFile, root: path.dirname(stateFile), now: () => 1_000_000, randomBytes: size => Buffer.alloc(size, 0x62), audit });
assert.equal(reopened.status().pending.reason, 'durable-audit-replay');
createEtahenLinkKeyring({ secrets: new SecretsStore(secretOptions), stateFile, root: path.dirname(stateFile), now: () => 1_000_000, randomBytes: size => Buffer.alloc(size, 0x63), audit });
assert.equal(events.filter(item => item.event === 'etahen.link.keyring.rotation-prepared').length, 1);
});
test('stale independent secret stores cannot erase a committed pending key', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'keyring.json');
const secretOptions = { filePath: path.join(f.root, 'secrets', 'secrets.enc.json'), keyFile: path.join(f.root, 'secrets', 'master.key') };
const staleSecrets = new SecretsStore(secretOptions);
const stale = createEtahenLinkKeyring({ secrets: staleSecrets, stateFile: file, root: path.dirname(file), now: f.now, randomBytes: size => Buffer.alloc(size, 0x66) });
const prepared = f.keyring.prepareRotation({ reason: 'retain-pending-secret' });
assert.throws(() => stale.prepareRotation({ reason: 'stale-secret-store' }), error => error?.code === 'ETAHEN_KEYRING_CONCURRENT');
const reloadedSecrets = new SecretsStore(secretOptions);
assert.equal(reloadedSecrets.has(`etahen.link.journal.${prepared.keyId}`), true);
const reopened = createEtahenLinkKeyring({ secrets: reloadedSecrets, stateFile: file, root: path.dirname(file), now: f.now, randomBytes: size => Buffer.alloc(size, 0x77) });
assert.equal(reopened.resolvePendingKey(prepared.keyId).keyId, prepared.keyId);
});
test('concurrent bootstrap cannot overwrite the winning encrypted key material', t => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-link-bootstrap-race-')); t.after(() => fs.rmSync(root, { recursive: true, force: true }));
const stateFile = path.join(root, 'link', 'keyring.json'); const secretOptions = { filePath: path.join(root, 'secrets', 'secrets.enc.json'), keyFile: path.join(root, 'secrets', 'master.key') };
const staleSecrets = new SecretsStore(secretOptions); const winningSecrets = new SecretsStore(secretOptions); let winner; let triggered = false;
const hookedSecrets = {
get: name => staleSecrets.get(name), set: (name, value) => staleSecrets.set(name, value),
has(name) {
if (!triggered) { triggered = true; winner = createEtahenLinkKeyring({ secrets: winningSecrets, stateFile, root: path.dirname(stateFile), now: () => 1_000_000, randomBytes: size => Buffer.alloc(size, 0xb1) }); }
return staleSecrets.has(name);
},
};
assert.throws(() => createEtahenLinkKeyring({ secrets: hookedSecrets, stateFile, root: path.dirname(stateFile), now: () => 1_000_000, randomBytes: size => Buffer.alloc(size, 0xb2) }), error => error?.code === 'ETAHEN_KEYRING_CONCURRENT');
const reopened = createEtahenLinkKeyring({ secrets: new SecretsStore(secretOptions), stateFile, root: path.dirname(stateFile), now: () => 1_000_000, randomBytes: size => Buffer.alloc(size, 0xb3) });
assert.equal(reopened.status().activeKeyId, winner.status().activeKeyId); assert.equal(reopened.activeKey().keyId, winner.status().activeKeyId);
});
test('orphaned writer locks are reclaimed without bypassing malformed locks', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const keyringFile = path.join(directory, 'keyring.json');
const orphan = file => fs.writeFileSync(`${file}.lock`, JSON.stringify({ schemaVersion: 1, pid: process.pid, threadId: require('node:worker_threads').threadId, token: require('node:crypto').randomUUID(), createdAt: Date.now() }));
orphan(keyringFile); assert.doesNotThrow(() => f.keyring.prepareRotation({ reason: 'orphan-lock-recovery' }));
const journalFile = path.join(directory, 'jobs.json'); const journal = openManagedEtahenLinkJournal({ file: journalFile, root: directory, keyring: f.keyring, now: f.now }).journal;
orphan(journalFile); assert.doesNotThrow(() => journal.begin(job('job_lockreclaim'), '9'.repeat(64)));
const auditFile = path.join(directory, 'audit.json'); const ledger = createEtahenLinkAuditLedger({ file: auditFile, root: directory, keyring: f.keyring, now: f.now });
orphan(auditFile); assert.doesNotThrow(() => ledger.append('etahen.link.lock.reclaimed', { outcome: 'allowed' }));
fs.writeFileSync(`${auditFile}.lock`, '{"schemaVersion":1,"pid":"tampered"}');
assert.throws(() => ledger.append('etahen.link.lock.blocked', { outcome: 'denied' }), error => error?.code === 'ETAHEN_AUDIT_BUSY');
fs.rmSync(`${auditFile}.lock`);
if (process.ppid > 0 && process.ppid !== process.pid) {
fs.writeFileSync(`${auditFile}.lock`, JSON.stringify({ schemaVersion: 1, pid: process.ppid, threadId: 0, token: require('node:crypto').randomUUID(), createdAt: Date.now() }));
assert.throws(() => ledger.append('etahen.link.lock.active', { outcome: 'denied' }), error => error?.code === 'ETAHEN_AUDIT_BUSY');
}
});
test('failed orphan verification restores a canonical fail-closed lock', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'keyring.json');
fs.writeFileSync(`${file}.lock`, JSON.stringify({ schemaVersion: 1, pid: process.pid, threadId: require('node:worker_threads').threadId, token: require('node:crypto').randomUUID(), createdAt: Date.now() }));
const originalRead = fs.readFileSync;
fs.readFileSync = function injectedRead(target, ...args) { if (String(target).includes('.lock.reclaim.')) throw Object.assign(new Error('simulated lock read failure'), { code: 'EIO' }); return originalRead.call(this, target, ...args); };
try { assert.throws(() => f.keyring.prepareRotation({ reason: 'must-stay-fail-closed' }), error => error?.code === 'ETAHEN_KEYRING_BUSY'); }
finally { fs.readFileSync = originalRead; }
assert.equal(fs.existsSync(`${file}.lock`), true); fs.rmSync(`${file}.lock`);
});
test('lock release failure preserves committed journal state and forces reopen', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'jobs-release.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now }; const journal = openManagedEtahenLinkJournal(options).journal;
const originalUnlink = fs.unlinkSync; let interrupt = true;
fs.unlinkSync = function injectedUnlink(target, ...args) { if (interrupt && String(target) === `${file}.lock`) { interrupt = false; throw Object.assign(new Error('simulated release failure'), { code: 'EACCES' }); } return originalUnlink.call(this, target, ...args); };
try { assert.throws(() => journal.begin(job('job_releaseerr'), '5'.repeat(64)), error => error?.code === 'EACCES'); }
finally { fs.unlinkSync = originalUnlink; }
assert.throws(() => journal.get('job_releaseerr'), error => error?.code === 'ETAHEN_JOURNAL_RESTART_REQUIRED'); fs.rmSync(`${file}.lock`);
const reopened = openManagedEtahenLinkJournal(options).journal; assert.equal(reopened.get('job_releaseerr').status, 'accepted'); assert.equal(reopened.list().length, 1);
});
test('restart reconciles both rotation crash windows deterministically', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'jobs.json'); const opened = openManagedEtahenLinkJournal({ file, root: path.dirname(file), keyring: f.keyring, now: f.now });
const oldKeyId = opened.journal.integrity().keyId; const pending = f.keyring.prepareRotation({ reason: 'crash-window' });
assert.throws(() => f.keyring.reconcileJournalKey(pending.keyId), error => error?.code === 'ETAHEN_KEYRING_JOURNAL');
assert.equal(f.keyring.reconcileJournalKey(oldKeyId).outcome, 'pending-aborted'); assert.equal(f.keyring.status().pending, null);
const second = f.keyring.prepareRotation({ reason: 'crash-after-rekey' });
const interrupted = { integrity: () => opened.journal.integrity(), rotateIntegrityKey(descriptor) { opened.journal.rotateIntegrityKey(descriptor); throw Object.assign(new Error('simulated crash after rekey'), { code: 'REKEY_COMMITTED' }); } };
assert.throws(() => f.keyring.commitRotation(interrupted), error => error?.code === 'REKEY_COMMITTED'); assert.equal(f.keyring.status().pending.phase, 'rekeying');
const restarted = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: path.join(f.root, 'link', 'keyring.json'), root: path.join(f.root, 'link'), now: f.now, randomBytes: size => Buffer.alloc(size, 0x33) });
const commitmentId = opened.journal.integrity().commitmentId;
assert.throws(() => restarted.reconcileJournalKey(oldKeyId, commitmentId), error => error?.code === 'ETAHEN_KEYRING_JOURNAL'); assert.equal(restarted.status().pending.keyId, second.keyId);
assert.equal(restarted.reconcileJournalKey(second.keyId, commitmentId).outcome, 'pending-committed'); assert.equal(restarted.status().activeKeyId, second.keyId);
});
test('an interrupted pending-key cleanup cannot roll back the committed abort', t => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-link-abort-cleanup-')); t.after(() => fs.rmSync(root, { recursive: true, force: true }));
const secretOptions = { filePath: path.join(root, 'secrets', 'secrets.enc.json'), keyFile: path.join(root, 'secrets', 'master.key') }; const store = new SecretsStore(secretOptions); let rejectDelete = false;
const secrets = { get: name => store.get(name), has: name => store.has(name), set(name, value) { if (rejectDelete && name.startsWith('etahen.link.journal.') && value === '') throw Object.assign(new Error('cleanup unavailable'), { code: 'CLEANUP_DOWN' }); return store.set(name, value); } };
const stateFile = path.join(root, 'link', 'keyring.json'); const keyring = createEtahenLinkKeyring({ secrets, stateFile, root: path.dirname(stateFile), now: () => 1_000_000, randomBytes: size => Buffer.alloc(size, 0x71) });
const activeKeyId = keyring.status().activeKeyId; const pending = keyring.prepareRotation({ reason: 'abort-cleanup-crash' }); rejectDelete = true;
assert.throws(() => keyring.reconcileJournalKey(activeKeyId), error => error?.code === 'CLEANUP_DOWN'); assert.equal(keyring.status().pending, null);
const reopened = createEtahenLinkKeyring({ secrets: new SecretsStore(secretOptions), stateFile, root: path.dirname(stateFile), now: () => 1_000_000 });
assert.equal(reopened.status().pending, null); assert.equal(reopened.status().activeKeyId, activeKeyId); assert.throws(() => reopened.resolveJournalKey(pending.keyId), /unknown/i);
});
test('stale managed journal writers cannot erase durable replay evidence', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'jobs.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now };
const current = openManagedEtahenLinkJournal(options).journal; const stale = openManagedEtahenLinkJournal(options).journal;
current.begin(job('job_current123'), 'a'.repeat(64));
assert.throws(() => stale.begin(job('job_stale12345'), 'b'.repeat(64)), error => error?.code === 'ETAHEN_JOURNAL_CONCURRENT');
const reopened = openManagedEtahenLinkJournal(options).journal;
assert.deepEqual(reopened.list().map(item => item.jobId), ['job_current123']);
});
test('journal rejects non-object audit details without mutating reopenable state', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'jobs-audit-shape.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now }; const journal = openManagedEtahenLinkJournal(options).journal;
assert.throws(() => journal.recordAudit({ event: 'etahen.link.audit.invalid', dedupeKey: 'invalid_primitive', details: 'primitive' }), error => error?.code === 'ETAHEN_JOURNAL_AUDIT');
assert.throws(() => journal.begin(job('job_auditshape1'), 'a'.repeat(64), { event: 'etahen.link.audit.invalid', dedupeKey: 'invalid_array', details: [] }), error => error?.code === 'ETAHEN_JOURNAL_AUDIT');
journal.begin(job('job_auditshape2'), 'b'.repeat(64));
assert.throws(() => journal.transition('job_auditshape2', 'completed', { installed: false }, { event: 'etahen.link.audit.invalid', dedupeKey: 'invalid_transition', details: 42 }), error => error?.code === 'ETAHEN_JOURNAL_AUDIT');
assert.equal(journal.get('job_auditshape2').status, 'accepted'); assert.equal(journal.auditEvidence().length, 0);
const reopened = openManagedEtahenLinkJournal(options).journal; assert.equal(reopened.get('job_auditshape2').status, 'accepted'); assert.equal(reopened.auditEvidence().length, 0);
});
test('journal validates the durable job identity before accepting it', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'jobs-identity-shape.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now }; const journal = openManagedEtahenLinkJournal(options).journal;
assert.throws(() => journal.begin({ ...job('job_badepoch1'), runtimeEpoch: 'x' }, 'c'.repeat(64)), error => error?.code === 'ETAHEN_JOURNAL_JOB');
const deceptive = job('job_deceptive1'); Object.defineProperty(deceptive, 'toJSON', { value: () => ({ ...deceptive, jobId: 'job_changed123' }) });
assert.throws(() => journal.begin(deceptive, 'd'.repeat(64)), error => error?.code === 'ETAHEN_JOURNAL_JOB'); assert.equal(journal.list().length, 0);
journal.begin(job('job_identityok'), 'e'.repeat(64));
const reopened = openManagedEtahenLinkJournal(options).journal; assert.equal(reopened.get('job_identityok').job.jobId, 'job_identityok'); assert.equal(reopened.list().length, 1);
});
test('managed journal commitment detects valid-record truncation and deletion', t => {
const first = fixture(t); const firstFile = path.join(first.root, 'link', 'jobs.json'); const firstOptions = { file: firstFile, root: path.dirname(firstFile), keyring: first.keyring, now: first.now };
const journal = openManagedEtahenLinkJournal(firstOptions).journal; journal.begin(job('job_retained123'), 'a'.repeat(64)); journal.begin(job('job_removed123'), 'b'.repeat(64));
const truncated = JSON.parse(fs.readFileSync(firstFile, 'utf8')); truncated.jobs.pop(); fs.writeFileSync(firstFile, JSON.stringify(truncated));
assert.throws(() => openManagedEtahenLinkJournal(firstOptions), error => ['ETAHEN_JOURNAL_CORRUPT', 'ETAHEN_JOURNAL_ANCHOR'].includes(error?.code));
const second = fixture(t); const secondFile = path.join(second.root, 'link', 'jobs.json'); const secondOptions = { file: secondFile, root: path.dirname(secondFile), keyring: second.keyring, now: second.now };
openManagedEtahenLinkJournal(secondOptions).journal.begin(job('job_deleted123'), 'c'.repeat(64)); fs.rmSync(secondFile);
assert.throws(() => openManagedEtahenLinkJournal(secondOptions), error => error?.code === 'ETAHEN_JOURNAL_ANCHOR');
});
test('combined public journal rollback and encrypted commitment deletion fails closed', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'jobs.json'); const keyringFile = path.join(directory, 'keyring.json'); const options = { file, root: directory, keyring: f.keyring, now: f.now };
const journal = openManagedEtahenLinkJournal(options).journal; journal.begin(job('job_first12345'), 'a'.repeat(64)); const oldJournal = fs.readFileSync(file); const oldKeyring = fs.readFileSync(keyringFile);
journal.begin(job('job_second1234'), 'b'.repeat(64)); fs.writeFileSync(file, oldJournal); fs.writeFileSync(keyringFile, oldKeyring);
const anchorId = `journal_${require('node:crypto').createHash('sha256').update(path.resolve(file)).digest('hex').slice(0, 24)}`;
f.secrets.set(`etahen.link.journal-anchor.${anchorId}`, '');
const rolledBackKeyring = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: keyringFile, root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0xab) });
assert.throws(() => openManagedEtahenLinkJournal({ ...options, keyring: rolledBackKeyring }), error => error?.code === 'ETAHEN_JOURNAL_ANCHOR');
});
test('newer encrypted journal commitment rejects public keyring and file rollback', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'jobs.json'); const keyringFile = path.join(directory, 'keyring.json'); const options = { file, root: directory, keyring: f.keyring, now: f.now };
const journal = openManagedEtahenLinkJournal(options).journal; journal.begin(job('job_first67890'), 'a'.repeat(64)); const oldJournal = fs.readFileSync(file); const oldKeyring = fs.readFileSync(keyringFile);
journal.begin(job('job_second6789'), 'b'.repeat(64)); fs.writeFileSync(file, oldJournal); fs.writeFileSync(keyringFile, oldKeyring);
const rolledBackKeyring = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: keyringFile, root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0xac) });
assert.throws(() => openManagedEtahenLinkJournal({ ...options, keyring: rolledBackKeyring }), error => error?.code === 'ETAHEN_JOURNAL_ANCHOR');
});
test('staged encrypted journal commitment reconciles before keyring commit', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'jobs.json'); const keyringFile = path.join(directory, 'keyring.json'); const options = { file, root: directory, keyring: f.keyring, now: f.now };
const journal = openManagedEtahenLinkJournal(options).journal; journal.begin(job('job_first24680'), 'a'.repeat(64)); const oldKeyring = fs.readFileSync(keyringFile);
journal.begin(job('job_second2468'), 'b'.repeat(64)); fs.writeFileSync(keyringFile, oldKeyring);
const interruptedKeyring = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: keyringFile, root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0xad) });
const reopened = openManagedEtahenLinkJournal({ ...options, keyring: interruptedKeyring }).journal;
assert.deepEqual(reopened.list().map(item => item.jobId), ['job_first24680', 'job_second2468']); assert.equal(reopened.integrity().generation, 2);
});
test('staged empty-journal registration reconciles after a mirror-only crash', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'jobs-empty-crash.json'); let mirrorWritten = false; let interruptRegistry = true;
const interruptedSecrets = {
has: name => f.secrets.has(name), get: name => f.secrets.get(name),
set(name, value) {
if (String(name).startsWith('etahen.link.journal-anchor.')) { f.secrets.set(name, value); mirrorWritten = true; return; }
if (name === 'etahen.link.commitment-registry' && mirrorWritten && interruptRegistry) { interruptRegistry = false; throw Object.assign(new Error('simulated registry interruption'), { code: 'REGISTRY_INTERRUPTED' }); }
f.secrets.set(name, value);
},
};
const interrupted = createEtahenLinkKeyring({ secrets: interruptedSecrets, stateFile: path.join(directory, 'keyring.json'), root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0x36) });
assert.throws(() => openManagedEtahenLinkJournal({ file, root: directory, keyring: interrupted, now: f.now }), error => error?.code === 'REGISTRY_INTERRUPTED'); assert.equal(fs.existsSync(file), false);
const restarted = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: path.join(directory, 'keyring.json'), root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0x37) });
const journal = openManagedEtahenLinkJournal({ file, root: directory, keyring: restarted, now: f.now }).journal; assert.equal(restarted.journalAnchor(journal.integrity().commitmentId).pending, false);
journal.begin(job('job_emptycrash'), '7'.repeat(64)); assert.equal(openManagedEtahenLinkJournal({ file, root: directory, keyring: restarted, now: f.now }).journal.get('job_emptycrash').status, 'accepted');
});
test('managed open adopts a valid legacy schema-two journal before upgrading it', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'jobs-legacy-two.json'); const descriptor = f.keyring.activeKey();
const legacyWriter = createFileJobJournal({ file, root: directory, integrityKey: descriptor.key, integrityKeyId: descriptor.keyId, now: f.now }); legacyWriter.begin(job('job_legacytwo1'), '8'.repeat(64));
const legacy = JSON.parse(fs.readFileSync(file, 'utf8')); legacy.schemaVersion = 2; delete legacy.integrity; fs.writeFileSync(file, JSON.stringify(legacy, null, 2));
const managed = openManagedEtahenLinkJournal({ file, root: directory, keyring: f.keyring, now: f.now }).journal; assert.equal(managed.get('job_legacytwo1').status, 'accepted'); assert.equal(managed.integrity().generation, 0);
managed.begin(job('job_legacytwo2'), '9'.repeat(64)); const reopened = openManagedEtahenLinkJournal({ file, root: directory, keyring: f.keyring, now: f.now }).journal;
assert.deepEqual(reopened.list().map(item => item.jobId), ['job_legacytwo1', 'job_legacytwo2']); assert.equal(reopened.integrity().generation, 1);
});
test('missing, wrong and retired journal keys fail closed', t => {
const f = fixture(t); const old = f.keyring.status().activeKeyId;
assert.throws(() => f.keyring.resolveJournalKey('key_' + 'f'.repeat(24)), /unknown/i);
const journal = openManagedEtahenLinkJournal({ file: path.join(f.root, 'link', 'jobs.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now }).journal;
const pending = f.keyring.prepareRotation({ reason: 'retire-old' });
f.keyring.commitRotation(journal); assert.equal(f.keyring.status().activeKeyId, pending.keyId);
assert.throws(() => f.keyring.resolveJournalKey(old), /retired/i);
f.secrets.set(`etahen.link.journal.${pending.keyId}`, ''); assert.throws(() => f.keyring.resolveJournalKey(pending.keyId), /missing/i);
});
test('tampered or symlinked keyring metadata cannot select keys', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'keyring.json'); const state = JSON.parse(fs.readFileSync(file, 'utf8'));
state.active.keyId = 'key_' + 'f'.repeat(24); fs.writeFileSync(file, JSON.stringify(state));
assert.throws(() => createEtahenLinkKeyring({ secrets: f.secrets, stateFile: file, root: path.dirname(file) }), /keyring/i);
if (process.platform !== 'win32') {
fs.rmSync(file); fs.symlinkSync(path.join(f.root, 'secrets', 'secrets.enc.json'), file);
assert.throws(() => createEtahenLinkKeyring({ secrets: f.secrets, stateFile: file, root: path.dirname(file) }), /symlink/i);
}
});
test('missing public keyring state recovers from the registry while a missing root fails closed', t => {
const first = fixture(t); const firstFile = path.join(first.root, 'link', 'keyring.json'); const activeKeyId = first.keyring.status().activeKeyId; fs.rmSync(firstFile);
const recovered = createEtahenLinkKeyring({ secrets: first.secrets, stateFile: firstFile, root: path.dirname(firstFile) });
assert.equal(recovered.status().activeKeyId, activeKeyId); assert.equal(fs.existsSync(firstFile), true);
const second = fixture(t); const secondFile = path.join(second.root, 'link', 'keyring.json'); second.secrets.set('etahen.link.keyring.root', '');
assert.throws(() => createEtahenLinkKeyring({ secrets: second.secrets, stateFile: secondFile, root: path.dirname(secondFile) }), error => error?.code === 'ETAHEN_KEYRING_ROOT');
assert.equal(second.secrets.has('etahen.link.keyring.root'), false);
});
test('legacy registry recovery preserves its authenticated shape across restarts', t => {
const f = fixture(t); const stateFile = path.join(f.root, 'link', 'keyring.json'); const legacy = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
delete legacy.auditAnchors; delete legacy.journalAnchors; delete legacy.auditEvidence; const digestValue = { ...legacy }; delete digestValue.stateHash;
legacy.stateHash = require('node:crypto').createHmac('sha256', Buffer.from(f.secrets.get('etahen.link.keyring.root'), 'hex')).update(canonical(digestValue)).digest('hex');
f.secrets.set('etahen.link.commitment-registry', JSON.stringify({ schemaVersion: 1, previousStateHash: '0'.repeat(64), state: legacy })); fs.rmSync(stateFile);
const first = createEtahenLinkKeyring({ secrets: f.secrets, stateFile, root: path.dirname(stateFile), now: f.now }); assert.equal(first.status().activeKeyId, legacy.active.keyId);
const second = createEtahenLinkKeyring({ secrets: f.secrets, stateFile, root: path.dirname(stateFile), now: f.now }); assert.equal(second.status().activeKeyId, legacy.active.keyId);
});
test('encrypted keyring registry is mandatory and detects genesis rollback', t => {
const missing = fixture(t); const missingFile = path.join(missing.root, 'link', 'keyring.json'); missing.secrets.set('etahen.link.commitment-registry', '');
assert.throws(() => createEtahenLinkKeyring({ secrets: missing.secrets, stateFile: missingFile, root: path.dirname(missingFile), now: missing.now }), error => error?.code === 'ETAHEN_KEYRING_REGISTRY');
const f = fixture(t); const directory = path.join(f.root, 'link'); const keyringFile = path.join(directory, 'keyring.json'); const bootstrapState = fs.readFileSync(keyringFile);
const jobFile = path.join(directory, 'jobs.json'); openManagedEtahenLinkJournal({ file: jobFile, root: directory, keyring: f.keyring, now: f.now }).journal.begin(job('job_genesis123'), 'e'.repeat(64));
const auditFile = path.join(directory, 'audit.json'); createEtahenLinkAuditLedger({ file: auditFile, root: directory, keyring: f.keyring, now: f.now }).append('etahen.link.genesis', { outcome: 'allowed' });
fs.writeFileSync(keyringFile, bootstrapState); fs.rmSync(jobFile); fs.rmSync(auditFile);
const journalAnchorId = `journal_${require('node:crypto').createHash('sha256').update(path.resolve(jobFile)).digest('hex').slice(0, 24)}`;
const auditAnchorId = `audit_${require('node:crypto').createHash('sha256').update(path.resolve(auditFile)).digest('hex').slice(0, 24)}`;
f.secrets.set(`etahen.link.journal-anchor.${journalAnchorId}`, ''); f.secrets.set(`etahen.link.audit-anchor.${auditAnchorId}`, '');
assert.throws(() => createEtahenLinkKeyring({ secrets: f.secrets, stateFile: keyringFile, root: directory, now: f.now }), error => error?.code === 'ETAHEN_KEYRING_REGISTRY');
});
test('authenticated audit ledger redacts secrets and deduplicates decisions', t => {
const f = fixture(t); const ledger = createEtahenLinkAuditLedger({ file: path.join(f.root, 'link', 'audit.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now });
const first = ledger.append('etahen.link.dispatch.denied', { jobId: 'job_audit1234', outcome: 'denied', token: 'raw-token', reason: 'bad-signature' }, { dedupeKey: 'deny_job_audit1234_r1' });
const duplicate = ledger.append('etahen.link.dispatch.denied', { jobId: 'job_audit1234', outcome: 'denied' }, { dedupeKey: 'deny_job_audit1234_r1' });
assert.deepEqual(duplicate, first); assert.equal(ledger.list().length, 1); assert.equal(first.details.token, '[REDACTED]');
assert.doesNotMatch(fs.readFileSync(path.join(f.root, 'link', 'audit.json'), 'utf8'), /raw-token/);
});
test('public audit identifiers are derived from redacted details', t => {
const first = fixture(t); const second = fixture(t);
const firstEntry = createEtahenLinkAuditLedger({ file: path.join(first.root, 'link', 'audit.json'), root: path.join(first.root, 'link'), keyring: first.keyring, now: first.now }).append('etahen.link.secret.test', { outcome: 'denied', token: 'short-secret-one' });
const secondEntry = createEtahenLinkAuditLedger({ file: path.join(second.root, 'link', 'audit.json'), root: path.join(second.root, 'link'), keyring: second.keyring, now: second.now }).append('etahen.link.secret.test', { outcome: 'denied', token: 'short-secret-two' });
assert.equal(firstEntry.eventId, secondEntry.eventId); assert.deepEqual(firstEntry.details, secondEntry.details);
});
test('audit ledger detects record tampering and tail truncation', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'audit.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now };
const ledger = createEtahenLinkAuditLedger(options); ledger.append('etahen.link.one', { outcome: 'allowed' }); ledger.append('etahen.link.two', { outcome: 'denied' });
const tampered = JSON.parse(fs.readFileSync(file, 'utf8')); tampered.entries[0].details.outcome = 'allowed-after-tamper'; fs.writeFileSync(file, JSON.stringify(tampered));
assert.throws(() => createEtahenLinkAuditLedger(options), /audit/i);
const f2 = fixture(t); const file2 = path.join(f2.root, 'link', 'audit.json');
const options2 = { file: file2, root: path.dirname(file2), keyring: f2.keyring, now: f2.now };
const fresh = createEtahenLinkAuditLedger(options2); fresh.append('etahen.link.one', { outcome: 'allowed' }); fresh.append('etahen.link.two', { outcome: 'denied' });
const truncated = JSON.parse(fs.readFileSync(file2, 'utf8')); truncated.entries.pop(); truncated.entryCount = truncated.entries.length; truncated.headHash = truncated.entries.at(-1).recordHash; fs.writeFileSync(file2, JSON.stringify(truncated));
assert.throws(() => createEtahenLinkAuditLedger(options2), /audit/i);
});
test('audit ledger detects reordered records and sequence gaps', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'audit.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now };
const ledger = createEtahenLinkAuditLedger(options); ledger.append('etahen.link.one', { outcome: 'allowed' }); ledger.append('etahen.link.two', { outcome: 'denied' });
const reordered = JSON.parse(fs.readFileSync(file, 'utf8')); reordered.entries.reverse(); fs.writeFileSync(file, JSON.stringify(reordered));
assert.throws(() => createEtahenLinkAuditLedger(options), /audit/i);
const f2 = fixture(t); const file2 = path.join(f2.root, 'link', 'audit.json');
const options2 = { file: file2, root: path.dirname(file2), keyring: f2.keyring, now: f2.now };
const fresh = createEtahenLinkAuditLedger(options2); fresh.append('etahen.link.one', { outcome: 'allowed' }); fresh.append('etahen.link.two', { outcome: 'denied' });
const gap = JSON.parse(fs.readFileSync(file2, 'utf8')); gap.entries[1].sequence = 3; fs.writeFileSync(file2, JSON.stringify(gap));
assert.throws(() => createEtahenLinkAuditLedger(options2), /audit/i);
});
test('encrypted audit anchor detects complete ledger deletion', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'audit.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now };
createEtahenLinkAuditLedger(options).append('etahen.link.retained', { outcome: 'allowed' }); fs.rmSync(file);
assert.throws(() => createEtahenLinkAuditLedger(options), /missing.*anchor/i);
});
test('deleting the encrypted anchor mirror cannot hide ledger rollback', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'audit.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now };
const ledger = createEtahenLinkAuditLedger(options); ledger.append('etahen.link.first', { outcome: 'allowed' }); const oldLedger = fs.readFileSync(file);
ledger.append('etahen.link.second', { outcome: 'allowed' });
const anchorId = `audit_${require('node:crypto').createHash('sha256').update(path.resolve(file)).digest('hex').slice(0, 24)}`;
f.secrets.set(`etahen.link.audit-anchor.${anchorId}`, ''); fs.writeFileSync(file, oldLedger);
assert.throws(() => createEtahenLinkAuditLedger(options), /anchor/i);
});
test('newer encrypted anchor rejects authenticated keyring and ledger rollback', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'audit.json'); const keyringFile = path.join(directory, 'keyring.json');
const ledger = createEtahenLinkAuditLedger({ file, root: directory, keyring: f.keyring, now: f.now });
ledger.append('etahen.link.first', { outcome: 'allowed' }); const oldLedger = fs.readFileSync(file); const oldKeyring = fs.readFileSync(keyringFile);
ledger.append('etahen.link.second', { outcome: 'allowed' }); fs.writeFileSync(file, oldLedger); fs.writeFileSync(keyringFile, oldKeyring);
const rolledBackKeyring = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: keyringFile, root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0x88) });
assert.throws(() => createEtahenLinkAuditLedger({ file, root: directory, keyring: rolledBackKeyring, now: f.now }), error => error?.code === 'ETAHEN_AUDIT_ANCHOR');
});
test('combined public rollback and encrypted anchor deletion fails closed', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'audit.json'); const keyringFile = path.join(directory, 'keyring.json');
const ledger = createEtahenLinkAuditLedger({ file, root: directory, keyring: f.keyring, now: f.now });
ledger.append('etahen.link.first', { outcome: 'allowed' }); const oldLedger = fs.readFileSync(file); const oldKeyring = fs.readFileSync(keyringFile);
ledger.append('etahen.link.second', { outcome: 'allowed' }); fs.writeFileSync(file, oldLedger); fs.writeFileSync(keyringFile, oldKeyring);
const anchorId = `audit_${require('node:crypto').createHash('sha256').update(path.resolve(file)).digest('hex').slice(0, 24)}`;
f.secrets.set(`etahen.link.audit-anchor.${anchorId}`, '');
const rolledBackKeyring = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: keyringFile, root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0x99) });
assert.throws(() => createEtahenLinkAuditLedger({ file, root: directory, keyring: rolledBackKeyring, now: f.now }), error => error?.code === 'ETAHEN_AUDIT_ANCHOR');
});
test('staged encrypted anchor reconciles a crash before public commitment', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const file = path.join(directory, 'audit.json'); const keyringFile = path.join(directory, 'keyring.json');
const ledger = createEtahenLinkAuditLedger({ file, root: directory, keyring: f.keyring, now: f.now });
ledger.append('etahen.link.first', { outcome: 'allowed' }); const oldKeyring = fs.readFileSync(keyringFile);
ledger.append('etahen.link.second', { outcome: 'allowed' }); fs.writeFileSync(keyringFile, oldKeyring);
const interruptedKeyring = createEtahenLinkKeyring({ secrets: f.secrets, stateFile: keyringFile, root: directory, now: f.now, randomBytes: size => Buffer.alloc(size, 0xaa) });
const reopened = createEtahenLinkAuditLedger({ file, root: directory, keyring: interruptedKeyring, now: f.now });
assert.equal(reopened.verify().entries, 2); assert.equal(reopened.list()[1].event, 'etahen.link.second');
});
test('stale audit writers fail before forking anchored evidence', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'audit.json'); const options = { file, root: path.dirname(file), keyring: f.keyring, now: f.now };
const current = createEtahenLinkAuditLedger(options); const stale = createEtahenLinkAuditLedger(options);
current.append('etahen.link.current', { outcome: 'allowed' });
assert.throws(() => stale.append('etahen.link.stale', { outcome: 'allowed' }), error => error?.code === 'ETAHEN_AUDIT_CONCURRENT');
const reopened = createEtahenLinkAuditLedger(options);
assert.equal(reopened.verify().entries, 1); assert.equal(reopened.list()[0].event, 'etahen.link.current');
});
test('restart reconciles the single audit write-before-anchor crash window', t => {
const f = fixture(t); const file = path.join(f.root, 'link', 'audit.json'); let interrupted = true;
const flakyKeyring = {
...f.keyring,
writeAuditAnchor(anchorId, value) {
if (interrupted) { interrupted = false; throw Object.assign(new Error('simulated anchor interruption'), { code: 'SIMULATED_ANCHOR_STOP' }); }
return f.keyring.writeAuditAnchor(anchorId, value);
},
};
const interruptedLedger = createEtahenLinkAuditLedger({ file, root: path.dirname(file), keyring: flakyKeyring, now: f.now });
assert.throws(() => interruptedLedger.append('etahen.link.before-anchor', { outcome: 'checkpointed' }), /anchor interruption/i);
assert.throws(() => interruptedLedger.append('etahen.link.must-reopen', { outcome: 'blocked' }), error => error?.code === 'ETAHEN_AUDIT_RESTART_REQUIRED');
const reopened = createEtahenLinkAuditLedger({ file, root: path.dirname(file), keyring: f.keyring, now: f.now });
assert.equal(reopened.verify().entries, 1); assert.equal(reopened.list()[0].event, 'etahen.link.before-anchor');
});
test('audit history remains verifiable across journal key rotation', t => {
const f = fixture(t); const journal = openManagedEtahenLinkJournal({ file: path.join(f.root, 'link', 'jobs.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now }).journal;
const auditFile = path.join(f.root, 'link', 'audit.json'); const ledger = createEtahenLinkAuditLedger({ file: auditFile, root: path.dirname(auditFile), keyring: f.keyring, now: f.now });
const oldKeyId = ledger.append('etahen.link.before', { outcome: 'allowed' }).keyId;
f.keyring.prepareRotation({ reason: 'audit-continuity' }); f.keyring.commitRotation(journal);
const newKeyId = ledger.append('etahen.link.after', { outcome: 'allowed' }).keyId;
assert.notEqual(newKeyId, oldKeyId); assert.equal(createEtahenLinkAuditLedger({ file: auditFile, root: path.dirname(auditFile), keyring: f.keyring, now: f.now }).verify().entries, 2);
});
test('recovery supervisor emits bounded idempotent alerts without retrying or installing', t => {
const f = fixture(t); const journal = openManagedEtahenLinkJournal({ file: path.join(f.root, 'link', 'jobs.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now }).journal;
journal.begin(job('job_unknown123'), 'b'.repeat(64)); journal.transition('job_unknown123', 'applying', { installed: false }); journal.recover(runtimeEpoch);
const calls = []; const supervisor = createEtahenLinkRecoverySupervisor({ journal, now: f.now, alertAfterMs: 1000, escalateAfterMs: 5000, maxAlerts: 10, audit: (event, details, options) => { calls.push({ event, details, options }); return { event }; } });
assert.equal(supervisor.inspect().alerts.length, 0); f.advance(1000);
const attention = supervisor.inspect(); assert.equal(attention.alerts[0].severity, 'attention'); assert.equal(attention.alerts[0].installed, false);
supervisor.inspect(); f.advance(4000); const expired = supervisor.inspect(); assert.equal(expired.alerts[0].severity, 'expired');
assert.equal(journal.get('job_unknown123').status, 'outcome_unknown'); assert.equal(journal.get('job_unknown123').result.installed, false);
assert.deepEqual(calls.map(item => item.options.dedupeKey), ['recovery_job_unknown123_attention_r3', 'recovery_job_unknown123_attention_r3', 'recovery_job_unknown123_expired_r3']);
});
test('repeated recovery does not revise already paused work or advance its journal', t => {
const f = fixture(t); const journal = openManagedEtahenLinkJournal({ file: path.join(f.root, 'link', 'jobs.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now }).journal;
journal.begin(job('job_pauseonce1'), '7'.repeat(64)); const first = journal.recover(runtimeEpoch)[0]; const generation = journal.integrity().generation; const second = journal.recover(runtimeEpoch)[0];
assert.equal(first.status, 'paused'); assert.equal(second.revision, first.revision); assert.equal(journal.integrity().generation, generation);
});
test('recovery supervision is bounded and validates timing policy', t => {
const f = fixture(t); const fakeJournal = { list: () => Array.from({ length: 5 }, (_, index) => ({ jobId: `job_bound${index}0000`, status: 'outcome_unknown', revision: 2, updatedAt: 1, result: { installed: false }, history: [{ status: 'outcome_unknown', at: 1 }] })) };
assert.throws(() => createEtahenLinkRecoverySupervisor({ journal: fakeJournal, alertAfterMs: 5000, escalateAfterMs: 1000 }), /timing policy/i);
const report = createEtahenLinkRecoverySupervisor({ journal: fakeJournal, now: () => 10000, alertAfterMs: 1, escalateAfterMs: 2, maxAlerts: 2 }).inspect();
assert.equal(report.alerts.length, 2); assert.equal(report.truncated, true); assert.equal(report.totalAmbiguous, 5);
});
test('recovery supervision preserves epoch-zero transition timestamps', () => {
const fakeJournal = { list: () => [{ jobId: 'job_epochzero1', status: 'outcome_unknown', revision: 2, updatedAt: 0, result: { installed: false }, history: [{ status: 'accepted', at: 0 }, { status: 'outcome_unknown', at: 0 }] }] };
const report = createEtahenLinkRecoverySupervisor({ journal: fakeJournal, now: () => 10_000, alertAfterMs: 1_000, escalateAfterMs: 5_000 }).inspect();
assert.equal(report.alerts[0].enteredAt, 0); assert.equal(report.alerts[0].ageMs, 10_000); assert.equal(report.alerts[0].severity, 'expired');
});
test('orchestrator mirrors denials, mutation checkpoints and recovery into authenticated audit', t => {
const f = fixture(t); const journal = openManagedEtahenLinkJournal({ file: path.join(f.root, 'link', 'jobs.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now }).journal;
const ledger = createEtahenLinkAuditLedger({ file: path.join(f.root, 'link', 'audit.json'), root: path.join(f.root, 'link'), keyring: f.keyring, now: f.now });
const consoleId = 'console_12345678'; const sessionKey = 'a'.repeat(64); const capabilities = [{ name: 'package.install.etahen-dpi-v1', available: true, authorized: true, healthy: true }];
const verifier = createEnvelopeVerifier({ consoleId, runtimeEpoch, sessionKey, now: f.now });
const orchestrator = createEtahenLinkOrchestrator({ consoleId, runtimeEpoch, capabilities, verifyEnvelope: verifier, journal, handlers: { 'package.install': () => { throw Object.assign(new Error('simulated stop'), { code: 'SIMULATED_STOP' }); } }, audit: (event, details, options) => ledger.append(event, details, options), now: f.now });
const deniedJob = { jobId: 'job_denied1234', type: 'package.install', runtimeEpoch, confirmationEpoch: runtimeEpoch, input: { artifactId: 'artifact_12345678', token: 'must-not-leak' } };
const envelopeFor = (value, nonce) => signEnvelope({ jobId: value.jobId, nonce, consoleId, runtimeEpoch, issuedAt: f.now(), expiresAt: f.now() + 1000, job: value }, sessionKey);
assert.throws(() => orchestrator.dispatch(envelopeFor(deniedJob, 'nonce_denied123')), /unknown typed job field/i);
const activeJob = { jobId: 'job_audited1234', type: 'package.install', runtimeEpoch, confirmationEpoch: runtimeEpoch, input: { artifactId: 'artifact_12345678' } };
assert.throws(() => orchestrator.dispatch(envelopeFor(activeJob, 'nonce_active123')), /simulated stop/i); orchestrator.recover();
const events = ledger.list(); assert.deepEqual(events.map(item => item.event), ['etahen.link.dispatch.denied', 'etahen.link.dispatch.accepted', 'etahen.link.mutation.applying', 'etahen.link.dispatch.failed']);
assert.doesNotMatch(JSON.stringify(events), /must-not-leak|aaaaaaaaaaaaaaaa/); assert.equal(journal.get(activeJob.jobId).status, 'outcome_unknown');
});
test('rejected asynchronous post-scan evidence is authenticated and remains uninstalled', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const journal = openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs.json'), root: directory, keyring: f.keyring, now: f.now }).journal;
const ledger = createEtahenLinkAuditLedger({ file: path.join(directory, 'audit.json'), root: directory, keyring: f.keyring, now: f.now });
const consoleId = 'console_12345678'; const sessionKey = 'b'.repeat(64); const capabilities = [{ name: 'package.install.etahen-dpi-v1', available: true, authorized: true, healthy: true }];
const verifier = createEnvelopeVerifier({ consoleId, runtimeEpoch, sessionKey, now: f.now });
const orchestrator = createEtahenLinkOrchestrator({ consoleId, runtimeEpoch, capabilities, verifyEnvelope: verifier, journal, handlers: { 'package.install': () => ({ status: 'acknowledged', acknowledged: true, installed: false, postScanRequired: true }) }, verifyInstallation: () => Promise.resolve({ status: 'verified', installed: true }), audit: (event, details, options) => ledger.append(event, details, options), now: f.now });
const activeJob = { jobId: 'job_asyncscan12', type: 'package.install', runtimeEpoch, confirmationEpoch: runtimeEpoch, input: { artifactId: 'artifact_12345678' } };
const envelope = signEnvelope({ jobId: activeJob.jobId, nonce: 'nonce_asyncscan1', consoleId, runtimeEpoch, issuedAt: f.now(), expiresAt: f.now() + 1000, job: activeJob }, sessionKey);
assert.equal(orchestrator.dispatch(envelope).status, 'acknowledged');
assert.throws(() => orchestrator.applyPostScan(activeJob.jobId, {}), error => error?.code === 'ETAHEN_POST_SCAN_ASYNC');
assert.equal(journal.get(activeJob.jobId).status, 'outcome_unknown'); assert.equal(journal.get(activeJob.jobId).result.installed, false);
assert.deepEqual(ledger.list().slice(-2).map(item => item.event), ['etahen.link.post-scan.started', 'etahen.link.post-scan.failed']);
});
test('verified install audit evidence survives a sink interruption without replaying the mutation', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const journal = openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs.json'), root: directory, keyring: f.keyring, now: f.now }).journal;
const ledger = createEtahenLinkAuditLedger({ file: path.join(directory, 'audit.json'), root: directory, keyring: f.keyring, now: f.now });
const consoleId = 'console_12345678'; const sessionKey = 'c'.repeat(64); const capabilities = [{ name: 'package.install.etahen-dpi-v1', available: true, authorized: true, healthy: true }];
const verifier = createEnvelopeVerifier({ consoleId, runtimeEpoch, sessionKey, now: f.now }); let handlerCalls = 0; let verifierCalls = 0; let interruptVerified = true;
const orchestrator = createEtahenLinkOrchestrator({ consoleId, runtimeEpoch, capabilities, verifyEnvelope: verifier, journal, handlers: { 'package.install': () => { handlerCalls += 1; return { status: 'acknowledged', acknowledged: true, installed: false, postScanRequired: true }; } }, verifyInstallation: () => { verifierCalls += 1; return { status: 'verified', installed: true, scanRunId: 'scanrun_audit123' }; }, audit: (event, details, options) => {
if (event === 'etahen.link.post-scan.verified' && interruptVerified) { interruptVerified = false; throw Object.assign(new Error('audit unavailable'), { code: 'AUDIT_DOWN' }); }
return ledger.append(event, details, options);
}, now: f.now });
const activeJob = { jobId: 'job_auditverify', type: 'package.install', runtimeEpoch, confirmationEpoch: runtimeEpoch, input: { artifactId: 'artifact_12345678' } };
const envelope = signEnvelope({ jobId: activeJob.jobId, nonce: 'nonce_auditverify', consoleId, runtimeEpoch, issuedAt: f.now(), expiresAt: f.now() + 1000, job: activeJob }, sessionKey);
assert.equal(orchestrator.dispatch(envelope).status, 'acknowledged');
assert.throws(() => orchestrator.applyPostScan(activeJob.jobId, { coverage: 'complete' }), error => error?.code === 'AUDIT_DOWN');
assert.equal(journal.get(activeJob.jobId).status, 'verified'); assert.equal(journal.get(activeJob.jobId).result.installed, true);
const reopenedJournal = openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs.json'), root: directory, keyring: f.keyring, now: f.now }).journal;
const restarted = createEtahenLinkOrchestrator({ consoleId, runtimeEpoch, capabilities, verifyEnvelope: verifier, journal: reopenedJournal, handlers: { 'package.install': () => { handlerCalls += 1; throw new Error('must not replay'); } }, verifyInstallation: () => { verifierCalls += 1; throw new Error('must not rescan'); }, audit: (event, details, options) => ledger.append(event, details, options), now: f.now });
assert.doesNotThrow(() => restarted.reconcileAudit()); assert.doesNotThrow(() => restarted.reconcileAudit());
assert.equal(ledger.list().filter(item => item.event === 'etahen.link.post-scan.verified').length, 1); assert.equal(handlerCalls, 1); assert.equal(verifierCalls, 1);
});
test('recovery audit retries idempotently after an audit sink interruption', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const journal = openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs.json'), root: directory, keyring: f.keyring, now: f.now }).journal;
const ledger = createEtahenLinkAuditLedger({ file: path.join(directory, 'audit.json'), root: directory, keyring: f.keyring, now: f.now });
journal.begin(job('job_reaudit123'), 'd'.repeat(64)); journal.transition('job_reaudit123', 'applying', { installed: false, postScanRequired: true });
let interrupted = true;
const orchestrator = createEtahenLinkOrchestrator({ consoleId: 'console_12345678', runtimeEpoch, capabilities: [], verifyEnvelope: value => value, journal, handlers: {}, audit: (event, details, options) => {
if (event === 'etahen.link.runtime.recovered' && interrupted) { interrupted = false; throw Object.assign(new Error('audit unavailable'), { code: 'AUDIT_DOWN' }); }
return ledger.append(event, details, options);
}, now: f.now });
assert.throws(() => orchestrator.recover(), error => error?.code === 'AUDIT_DOWN'); assert.equal(journal.get('job_reaudit123').status, 'outcome_unknown');
assert.doesNotThrow(() => orchestrator.recover()); assert.doesNotThrow(() => orchestrator.recover());
const recovered = ledger.list().filter(item => item.event === 'etahen.link.runtime.recovered');
assert.equal(recovered.length, 1); assert.equal(recovered[0].details.fromStatus, 'applying'); assert.equal(recovered[0].details.status, 'outcome_unknown');
});
test('denial reason survives audit outage after nonce consumption', t => {
const f = fixture(t); const directory = path.join(f.root, 'link'); const journal = openManagedEtahenLinkJournal({ file: path.join(directory, 'jobs.json'), root: directory, keyring: f.keyring, now: f.now }).journal;
const ledger = createEtahenLinkAuditLedger({ file: path.join(directory, 'audit.json'), root: directory, keyring: f.keyring, now: f.now });
const consoleId = 'console_12345678'; const sessionKey = 'd'.repeat(64); const verifier = createEnvelopeVerifier({ consoleId, runtimeEpoch, sessionKey, now: f.now }); let interrupt = true;
const orchestrator = createEtahenLinkOrchestrator({ consoleId, runtimeEpoch, capabilities: [{ name: 'console.inventory.read', available: true, authorized: true, healthy: true }], verifyEnvelope: verifier, journal, handlers: {}, audit: (event, details, options) => {
if (event === 'etahen.link.dispatch.denied' && interrupt) { interrupt = false; throw Object.assign(new Error('audit unavailable'), { code: 'AUDIT_DOWN' }); }
return ledger.append(event, details, options);
}, now: f.now });
const invalidJob = { jobId: 'job_denyretain1', type: 'inventory.scan', runtimeEpoch, input: { path: '/forbidden' } };
const envelope = signEnvelope({ jobId: invalidJob.jobId, nonce: 'nonce_denyretain', consoleId, runtimeEpoch, issuedAt: f.now(), expiresAt: f.now() + 1000, job: invalidJob }, sessionKey);
assert.throws(() => orchestrator.dispatch(envelope), error => error?.code === 'AUDIT_DOWN'); assert.equal(journal.list().length, 0);
assert.doesNotThrow(() => orchestrator.reconcileAudit());
const denial = ledger.list().find(item => item.event === 'etahen.link.dispatch.denied'); assert.equal(denial.details.reasonId, 'ETAHEN_LINK_FORBIDDEN_FIELD'); assert.equal(denial.details.installed, false);
});
test('backwards clocks fail before corrupting journal or keyring state', t => {
let clock = 100; const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-link-clock-')); t.after(() => fs.rmSync(root, { recursive: true, force: true }));
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.enc.json'), keyFile: path.join(root, 'secrets', 'master.key') });
const keyring = createEtahenLinkKeyring({ secrets, stateFile: path.join(root, 'link', 'keyring.json'), root: path.join(root, 'link'), now: () => clock, randomBytes: size => Buffer.alloc(size, 0x81) });
clock = 90; assert.throws(() => keyring.prepareRotation({ reason: 'clock-must-not-rewind' }), error => error?.code === 'ETAHEN_KEYRING_TIME'); assert.equal(keyring.status().pending, null);
clock = 100; const journal = openManagedEtahenLinkJournal({ file: path.join(root, 'link', 'jobs.json'), root: path.join(root, 'link'), keyring, now: () => clock }).journal; journal.begin(job('job_clockbound'), '6'.repeat(64));
clock = 50; assert.throws(() => journal.transition('job_clockbound', 'applying', { installed: false }), error => error?.code === 'ETAHEN_JOURNAL_TIME'); assert.equal(journal.get('job_clockbound').status, 'accepted');
});