296 lines
16 KiB
JavaScript
296 lines
16 KiB
JavaScript
'use strict';
|
|
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const crypto = require('node:crypto');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { PINNED_MANAGER, createPayloadManagerAutoloadRepairService } = require('../../src/services/payload-manager-autoload-repair-service');
|
|
|
|
const sha256 = value => crypto.createHash('sha256').update(value).digest('hex');
|
|
|
|
function fixture({ failAutoloadPublish = false, failManagerDelete = false, failEtaDelete = false, autoload = 'pldmgr.elf\n', missingDirectory = false } = {}) {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-pldmgr-autoload-'));
|
|
const payloadRoot = path.join(root, 'payloads');
|
|
const recoveryRoot = path.join(root, 'recovery');
|
|
const temporaryRoot = path.join(root, 'tmp');
|
|
for (const directory of [payloadRoot, recoveryRoot, temporaryRoot]) fs.mkdirSync(directory, { recursive: true });
|
|
const newManager = Buffer.from('official-payload-manager-v0.5.1');
|
|
const oldManager = Buffer.from('old-payload-manager-v0.4.2');
|
|
const artifactPath = path.join(payloadRoot, PINNED_MANAGER.asset);
|
|
fs.writeFileSync(artifactPath, newManager);
|
|
const etaHen = Buffer.alloc(96, 0x41);
|
|
Buffer.from([0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01]).copy(etaHen);
|
|
etaHen.writeUInt16LE(0x3e, 18);
|
|
const etaHenSpec = {
|
|
source: 'user-supplied-test/extracted-direct-payload', version: '2.6B', asset: 'etaHEN-2.6B-direct.elf', remoteAsset: 'etaHEN-2.6B.elf',
|
|
sha256: sha256(etaHen), size: etaHen.length,
|
|
confirmation: 'PERSIST DIRECT ETAHEN 2.6B', rollbackConfirmation: 'HERSTEL VOOR ETAHEN 2.6B',
|
|
};
|
|
fs.writeFileSync(path.join(payloadRoot, etaHenSpec.asset), etaHen);
|
|
const remote = new Map([
|
|
['/data/ps5_autoloader/pldmgr.elf', oldManager],
|
|
['/data/ps5_autoloader/autoload.txt', Buffer.from(autoload)],
|
|
['/data/ps5_autoloader/etaHEN.elf', Buffer.from('preserved-payload')],
|
|
]);
|
|
if (missingDirectory) remote.clear();
|
|
const ftp = {
|
|
isConnected: () => true,
|
|
hasCredentials: () => true,
|
|
listDir: async directory => {
|
|
const files = [...remote.entries()].filter(([filename]) => path.posix.dirname(filename) === directory);
|
|
if (!files.length && missingDirectory) throw Object.assign(new Error('550 Requested action not taken. File unavailable.'), { code: 550 });
|
|
return files.map(([filename, bytes]) => ({ name: path.posix.basename(filename), isDir: false, size: bytes.length }));
|
|
},
|
|
downloadFile: async (remotePath, localPath) => {
|
|
if (!remote.has(remotePath)) throw Object.assign(new Error('missing remote file'), { code: 'ENOENT' });
|
|
fs.writeFileSync(localPath, remote.get(remotePath));
|
|
},
|
|
uploadFile: async (localPath, remotePath) => { remote.set(remotePath, fs.readFileSync(localPath)); },
|
|
renameRemote: async (source, destination) => {
|
|
if (failAutoloadPublish && /-autoload\.tmp$/.test(source)) throw new Error('injected autoload publish failure');
|
|
if (!remote.has(source)) throw new Error(`missing rename source ${source}`);
|
|
remote.set(destination, remote.get(source)); remote.delete(source);
|
|
},
|
|
deleteRemote: async remotePath => {
|
|
if (failManagerDelete && remotePath.endsWith('/pldmgr.elf')) throw new Error('injected manager delete failure');
|
|
if (failEtaDelete && remotePath.endsWith('/etaHEN-2.6B.elf')) throw new Error('injected etaHEN delete failure');
|
|
if (!remote.has(remotePath)) throw new Error('missing delete target');
|
|
remote.delete(remotePath);
|
|
},
|
|
removeDir: async remotePath => {
|
|
if ([...remote.keys()].some(filename => filename.startsWith(`${remotePath}/`))) throw new Error('directory not empty');
|
|
},
|
|
};
|
|
const artifactHash = sha256(newManager);
|
|
const starts = [];
|
|
const managerStarts = [];
|
|
const service = createPayloadManagerAutoloadRepairService({
|
|
ftp,
|
|
catalogProvider: () => ({ files: [{
|
|
source_name: PINNED_MANAGER.source,
|
|
trust: 'official',
|
|
asset_name: PINNED_MANAGER.asset,
|
|
version: PINNED_MANAGER.version,
|
|
local_path: artifactPath,
|
|
local_hash: artifactHash,
|
|
remote_hash: artifactHash,
|
|
local_size: newManager.length,
|
|
}] }),
|
|
payloadRoot,
|
|
recoveryRoot,
|
|
temporaryRoot,
|
|
managerProbe: async () => ({ ok: true, version: '0.5.1' }),
|
|
etaHenStarter: async artifact => { starts.push(artifact); return { bytes: artifact.size, loaderPort: 9021 }; },
|
|
managerStarter: async artifact => { managerStarts.push(artifact); return { bytes: artifact.size, loaderPort: 9021 }; },
|
|
etaHenSpec,
|
|
now: (() => { let value = 1786420800000; return () => value++; })(),
|
|
nonce: () => 'abc123',
|
|
});
|
|
return { root, remote, service, newManager, oldManager, etaHen, etaHenSpec, starts, managerStarts };
|
|
}
|
|
|
|
test('Payload Manager autoload repair snapshots, atomically publishes and post-verifies v0.5.1', async () => {
|
|
const value = fixture();
|
|
try {
|
|
const plan = await value.service.plan();
|
|
assert.equal(plan.available, true);
|
|
assert.deepEqual(plan.current.entries, ['pldmgr.elf']);
|
|
assert.equal(plan.artifact.sha256, sha256(value.newManager));
|
|
const result = await value.service.apply({ confirmation: PINNED_MANAGER.confirmation, planDigest: plan.planDigest });
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.persistent, true);
|
|
assert.equal(result.installedEvidenceCreated, false);
|
|
assert.deepEqual(value.remote.get('/data/ps5_autoloader/pldmgr.elf'), value.newManager);
|
|
assert.equal(value.remote.get('/data/ps5_autoloader/autoload.txt').toString(), 'pldmgr.elf\n');
|
|
const snapshot = path.join(value.root, 'recovery', result.snapshotId);
|
|
assert.deepEqual(fs.readFileSync(path.join(snapshot, 'pldmgr.elf')), value.oldManager);
|
|
assert.equal(fs.readFileSync(path.join(snapshot, 'autoload.txt'), 'utf8'), 'pldmgr.elf\n');
|
|
assert.equal(JSON.parse(fs.readFileSync(path.join(snapshot, 'meta.json'), 'utf8')).kind, 'payload-manager-autoload-repair');
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('Payload Manager autoload repair rejects drift and restores both remote targets after publish failure', async () => {
|
|
const drift = fixture();
|
|
try {
|
|
const plan = await drift.service.plan();
|
|
drift.remote.set('/data/ps5_autoloader/autoload.txt', Buffer.from('# changed\npldmgr.elf\n'));
|
|
await assert.rejects(() => drift.service.apply({ confirmation: PINNED_MANAGER.confirmation, planDigest: plan.planDigest }), error => error.code === 'PLDMGR_AUTOLOAD_DRIFT');
|
|
} finally { fs.rmSync(drift.root, { recursive: true, force: true }); }
|
|
|
|
const rollback = fixture({ failAutoloadPublish: true });
|
|
try {
|
|
const plan = await rollback.service.plan();
|
|
await assert.rejects(
|
|
() => rollback.service.apply({ confirmation: PINNED_MANAGER.confirmation, planDigest: plan.planDigest }),
|
|
error => error.details?.rolledBack === true,
|
|
);
|
|
assert.deepEqual(rollback.remote.get('/data/ps5_autoloader/pldmgr.elf'), rollback.oldManager);
|
|
assert.equal(rollback.remote.get('/data/ps5_autoloader/autoload.txt').toString(), 'pldmgr.elf\n');
|
|
} finally { fs.rmSync(rollback.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('Payload Manager autoload repair fails closed when another external payload is active', async () => {
|
|
const value = fixture({ autoload: 'pldmgr.elf\netaHEN.elf\n' });
|
|
try {
|
|
const plan = await value.service.plan();
|
|
assert.equal(plan.blocked, true);
|
|
assert.deepEqual(plan.unsupportedEntries, ['etaHEN.elf']);
|
|
await assert.rejects(
|
|
() => value.service.apply({ confirmation: PINNED_MANAGER.confirmation, planDigest: plan.planDigest }),
|
|
error => error.code === 'PLDMGR_AUTOLOAD_SEQUENCE',
|
|
);
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('Payload Manager autoload repair safely creates a missing first-install directory', async () => {
|
|
const value = fixture({ missingDirectory: true });
|
|
try {
|
|
const plan = await value.service.plan();
|
|
assert.equal(plan.current.directoryExists, false);
|
|
assert.equal(plan.current.managerExists, false);
|
|
const result = await value.service.apply({ confirmation: PINNED_MANAGER.confirmation, planDigest: plan.planDigest });
|
|
assert.equal(result.ok, true);
|
|
assert.deepEqual(value.remote.get('/data/ps5_autoloader/pldmgr.elf'), value.newManager);
|
|
assert.equal(value.remote.get('/data/ps5_autoloader/autoload.txt').toString(), 'pldmgr.elf\n');
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('Payload Manager autoload rollback restores an absent first-install state', async () => {
|
|
const value = fixture({ missingDirectory: true });
|
|
try {
|
|
const installPlan = await value.service.plan();
|
|
const installed = await value.service.apply({ confirmation: PINNED_MANAGER.confirmation, planDigest: installPlan.planDigest });
|
|
const rollbackPlan = await value.service.rollbackPlan();
|
|
assert.equal(rollbackPlan.snapshotId, installed.snapshotId);
|
|
assert.equal(rollbackPlan.restores.directoryExists, false);
|
|
const result = await value.service.rollback({ confirmation: PINNED_MANAGER.rollbackConfirmation, planDigest: rollbackPlan.planDigest });
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.directoryExists, false);
|
|
assert.equal(value.remote.size, 0);
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('Payload Manager autoload rollback restores deleted files after a partial failure', async () => {
|
|
const value = fixture({ missingDirectory: true, failManagerDelete: true });
|
|
try {
|
|
const installPlan = await value.service.plan();
|
|
await value.service.apply({ confirmation: PINNED_MANAGER.confirmation, planDigest: installPlan.planDigest });
|
|
const rollbackPlan = await value.service.rollbackPlan();
|
|
await assert.rejects(
|
|
() => value.service.rollback({ confirmation: PINNED_MANAGER.rollbackConfirmation, planDigest: rollbackPlan.planDigest }),
|
|
error => error.details?.rolledBack === true,
|
|
);
|
|
assert.deepEqual(value.remote.get('/data/ps5_autoloader/pldmgr.elf'), value.newManager);
|
|
assert.equal(value.remote.get('/data/ps5_autoloader/autoload.txt').toString(), 'pldmgr.elf\n');
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('etaHEN 2.6B persistence publishes only the attested direct user ELF and exact manual autoload entry', async () => {
|
|
const value = fixture({ missingDirectory: true });
|
|
try {
|
|
const plan = await value.service.etaHenPlan();
|
|
assert.equal(plan.available, true);
|
|
assert.equal(plan.artifact.sha256, value.etaHenSpec.sha256);
|
|
assert.equal(plan.artifact.provenance, 'user-supplied-test/extracted-direct-payload');
|
|
const result = await value.service.etaHenApply({ confirmation: value.etaHenSpec.confirmation, planDigest: plan.planDigest });
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.version, '2.6B');
|
|
assert.equal(result.installedEvidenceCreated, false);
|
|
assert.deepEqual(value.remote.get('/data/ps5_autoloader/etaHEN-2.6B.elf'), value.etaHen);
|
|
assert.equal(value.remote.get('/data/ps5_autoloader/autoload.txt').toString(), 'etaHEN-2.6B.elf\n');
|
|
const meta = JSON.parse(fs.readFileSync(path.join(value.root, 'recovery', result.snapshotId, 'meta.json'), 'utf8'));
|
|
assert.equal(meta.kind, 'etahen-autoload-persistence');
|
|
assert.equal(meta.before.directoryExists, false);
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('etaHEN 2.6B persistence safely replaces the attested wrapper while preserving its remote boot name', async () => {
|
|
const value = fixture({ missingDirectory: true });
|
|
const wrapper = Buffer.from('attested-wrapper-that-failed-its-second-hop');
|
|
value.remote.set('/data/ps5_autoloader/etaHEN-2.6B.elf', wrapper);
|
|
value.remote.set('/data/ps5_autoloader/autoload.txt', Buffer.from('etaHEN-2.6B.elf\n'));
|
|
try {
|
|
const plan = await value.service.etaHenPlan();
|
|
assert.equal(plan.available, true);
|
|
assert.equal(plan.current.payloadSha256, sha256(wrapper));
|
|
assert.equal(plan.target.payload, '/data/ps5_autoloader/etaHEN-2.6B.elf');
|
|
const result = await value.service.etaHenApply({ confirmation: value.etaHenSpec.confirmation, planDigest: plan.planDigest });
|
|
assert.deepEqual(value.remote.get('/data/ps5_autoloader/etaHEN-2.6B.elf'), value.etaHen);
|
|
assert.equal(value.remote.get('/data/ps5_autoloader/autoload.txt').toString(), 'etaHEN-2.6B.elf\n');
|
|
assert.deepEqual(fs.readFileSync(path.join(value.root, 'recovery', result.snapshotId, 'etaHEN-2.6B.elf')), wrapper);
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('etaHEN 2.6B direct start sends only the pinned direct artifact and creates no persistence evidence', async () => {
|
|
const value = fixture({ missingDirectory: true });
|
|
try {
|
|
const result = await value.service.etaHenDirectStart();
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.persistent, false);
|
|
assert.equal(result.installedEvidenceCreated, false);
|
|
assert.equal(result.payloadSha256, value.etaHenSpec.sha256);
|
|
assert.equal(value.starts.length, 1);
|
|
assert.equal(value.starts[0].localPath, path.join(value.root, 'payloads', value.etaHenSpec.asset));
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('Payload Manager recovery start sends only the checksum-verified v0.5.1 artifact', async () => {
|
|
const value = fixture({ missingDirectory: true });
|
|
try {
|
|
const result = await value.service.managerDirectStart();
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.version, 'v0.5.1');
|
|
assert.equal(result.persistent, false);
|
|
assert.equal(result.installedEvidenceCreated, false);
|
|
assert.equal(result.payloadSha256, sha256(value.newManager));
|
|
assert.equal(value.managerStarts.length, 1);
|
|
assert.equal(value.managerStarts[0].localPath.endsWith(PINNED_MANAGER.asset), true);
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('etaHEN 2.6B persistence rejects other boot content and rolls back partial publication', async () => {
|
|
const blocked = fixture({ autoload: 'pldmgr.elf\n' });
|
|
try {
|
|
const plan = await blocked.service.etaHenPlan();
|
|
assert.equal(plan.blocked, true);
|
|
assert.deepEqual(plan.unsupportedEntries, ['pldmgr.elf']);
|
|
} finally { fs.rmSync(blocked.root, { recursive: true, force: true }); }
|
|
|
|
const rollback = fixture({ missingDirectory: true, failAutoloadPublish: true });
|
|
try {
|
|
const plan = await rollback.service.etaHenPlan();
|
|
await assert.rejects(
|
|
() => rollback.service.etaHenApply({ confirmation: rollback.etaHenSpec.confirmation, planDigest: plan.planDigest }),
|
|
error => error.details?.rolledBack === true,
|
|
);
|
|
assert.equal(rollback.remote.size, 0);
|
|
} finally { fs.rmSync(rollback.root, { recursive: true, force: true }); }
|
|
});
|
|
|
|
test('etaHEN 2.6B rollback restores the absent boot directory and recovers from partial delete failure', async () => {
|
|
const value = fixture({ missingDirectory: true });
|
|
try {
|
|
const plan = await value.service.etaHenPlan();
|
|
await value.service.etaHenApply({ confirmation: value.etaHenSpec.confirmation, planDigest: plan.planDigest });
|
|
const rollbackPlan = await value.service.etaHenRollbackPlan();
|
|
const result = await value.service.etaHenRollback({ confirmation: value.etaHenSpec.rollbackConfirmation, planDigest: rollbackPlan.planDigest });
|
|
assert.equal(result.directoryExists, false);
|
|
assert.equal(value.remote.size, 0);
|
|
} finally { fs.rmSync(value.root, { recursive: true, force: true }); }
|
|
|
|
const partial = fixture({ missingDirectory: true, failEtaDelete: true });
|
|
try {
|
|
const plan = await partial.service.etaHenPlan();
|
|
await partial.service.etaHenApply({ confirmation: partial.etaHenSpec.confirmation, planDigest: plan.planDigest });
|
|
const rollbackPlan = await partial.service.etaHenRollbackPlan();
|
|
await assert.rejects(
|
|
() => partial.service.etaHenRollback({ confirmation: partial.etaHenSpec.rollbackConfirmation, planDigest: rollbackPlan.planDigest }),
|
|
error => error.details?.rolledBack === true,
|
|
);
|
|
assert.deepEqual(partial.remote.get('/data/ps5_autoloader/etaHEN-2.6B.elf'), partial.etaHen);
|
|
assert.equal(partial.remote.get('/data/ps5_autoloader/autoload.txt').toString(), 'etaHEN-2.6B.elf\n');
|
|
} finally { fs.rmSync(partial.root, { recursive: true, force: true }); }
|
|
});
|