99 lines
6.1 KiB
JavaScript
99 lines
6.1 KiB
JavaScript
'use strict';
|
|
|
|
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 test = require('node:test');
|
|
const { Readable } = require('node:stream');
|
|
const { createPs5UpstreamControlPackageService, CONTROL } = require('../../src/services/ps5-upstream-control-package-service');
|
|
|
|
function fixture() {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ps5-control-'));
|
|
const bytes = Buffer.from('pinned-open-source-control');
|
|
const registrations = [];
|
|
const service = createPs5UpstreamControlPackageService({
|
|
outputRoot: root,
|
|
stateFile: path.join(root, 'state.json'),
|
|
descriptor: { ...CONTROL, size: bytes.length, sha256: crypto.createHash('sha256').update(bytes).digest('hex') },
|
|
fetchImpl: async url => ({ ok: url === CONTROL.url, status: 200, body: Readable.toWeb(Readable.from(bytes)) }),
|
|
inspectPackage: () => ({ format: 'ps5-fih-debug-package', validation: { structurallyValid: true, validationLevel: 'fih-cnt-structural-v3', contentId: CONTROL.contentId, imageCount: 0, imageKey: { profile: 'opaque-filled-0x800' } } }),
|
|
inspectInstallGeometry: async () => ({ packageSize: 17, mountImageSize: 17, installedAppPkgSize: 17, provenance: 'signed-image:pfsimage.xml' }),
|
|
registrar: async manifest => { registrations.push(manifest); return { packageSetId: 99, titleId: 42 }; },
|
|
});
|
|
return { root, bytes, registrations, service };
|
|
}
|
|
|
|
test('imports only the exact hash-pinned upstream control atomically', async t => {
|
|
const f = fixture(); t.after(() => fs.rmSync(f.root, { recursive: true, force: true }));
|
|
const result = await f.service.importPackage();
|
|
assert.equal(result.status, 'ready');
|
|
assert.equal(result.installTrust.status, 'unproven');
|
|
assert.equal(result.installAuthorized, false);
|
|
assert.equal(result.packageSetId, 99);
|
|
assert.deepEqual(fs.readFileSync(result.absolutePath), f.bytes);
|
|
assert.equal(f.registrations[0].controlProfile, 'upstream-stock-9084c0e');
|
|
assert.equal(f.registrations[0].components[0].sha256, crypto.createHash('sha256').update(f.bytes).digest('hex'));
|
|
assert.equal(fs.readdirSync(path.dirname(result.absolutePath)).some(name => name.endsWith('.tmp')), false);
|
|
const proven = await f.service.recordInstallEvidence({ operationId: 'control-op-1', source: 'post-install-console-scan', observed_at: Date.now() });
|
|
assert.equal(proven.installTrust.status, 'post-scan-proven');
|
|
assert.equal(proven.installAuthorized, false);
|
|
assert.equal((await f.service.status()).installTrust.operationId, 'control-op-1');
|
|
assert.equal((await f.service.status()).currentArtifactVerified, true);
|
|
});
|
|
|
|
test('status never reports ready when only the historical state remains', async t => {
|
|
const f = fixture(); t.after(() => fs.rmSync(f.root, { recursive: true, force: true }));
|
|
await f.service.importPackage();
|
|
fs.unlinkSync(f.service.targetPath());
|
|
const status = await f.service.status();
|
|
assert.equal(status.status, 'missing');
|
|
assert.equal(status.currentArtifactVerified, false);
|
|
assert.equal(status.historicalRegistration.status, 'ready');
|
|
});
|
|
|
|
test('rejects hash drift and unexpected structural profiles without publishing', async t => {
|
|
const f = fixture(); t.after(() => fs.rmSync(f.root, { recursive: true, force: true }));
|
|
const badHash = createPs5UpstreamControlPackageService({
|
|
outputRoot: f.root, stateFile: path.join(f.root, 'bad-state.json'), descriptor: { ...CONTROL, size: f.bytes.length, sha256: '0'.repeat(64) },
|
|
fetchImpl: async () => ({ ok: true, status: 200, body: Readable.toWeb(Readable.from(f.bytes)) }), inspectPackage: () => ({}), registrar: async () => ({}),
|
|
});
|
|
await assert.rejects(badHash.importPackage(), error => error.code === 'PS5_CONTROL_HASH');
|
|
assert.equal(fs.existsSync(badHash.targetPath()), false);
|
|
|
|
const badProfile = createPs5UpstreamControlPackageService({
|
|
outputRoot: f.root, stateFile: path.join(f.root, 'profile-state.json'), descriptor: { ...CONTROL, size: f.bytes.length, sha256: crypto.createHash('sha256').update(f.bytes).digest('hex') },
|
|
fetchImpl: async () => ({ ok: true, status: 200, body: Readable.toWeb(Readable.from(f.bytes)) }), inspectPackage: () => ({ format: 'ps5-fih-debug-package', validation: { contentId: CONTROL.contentId, errors: [{ code: 'FIH_MAGIC' }] } }), registrar: async () => ({}),
|
|
});
|
|
await assert.rejects(badProfile.importPackage(), error => error.code === 'PS5_CONTROL_PROFILE');
|
|
assert.equal(fs.existsSync(badProfile.targetPath()), false);
|
|
});
|
|
|
|
test('control routes remain separate and require an exact destructive confirmation', () => {
|
|
const registry = fs.readFileSync('src/server/create-registry.js', 'utf8');
|
|
assert.match(registry, /ps5-native-packages:control-status[\s\S]*classification: 'read-only'/);
|
|
assert.match(registry, /ps5-native-packages:control-import[\s\S]*classification: 'mutating'/);
|
|
assert.match(registry, /ps5-native-packages:control-restore[\s\S]*classification: 'destructive'[\s\S]*INSTALL PS5 UPSTREAM CONTROL PACKAGE/);
|
|
assert.match(registry, /ps5-native-packages:control-restore-verify[\s\S]*classification: 'mutating'/);
|
|
assert.match(registry, /PPSA99099[\s\S]*post-install-console-scan/);
|
|
});
|
|
|
|
test('control UI and both bridges expose import, exact-confirmed restore and post-scan verification', () => {
|
|
const preload = fs.readFileSync('preload.js', 'utf8');
|
|
const web = fs.readFileSync('renderer/pork-web-shim.js', 'utf8');
|
|
const main = fs.readFileSync('main.js', 'utf8');
|
|
const modal = fs.readFileSync('renderer/modules/modal.js', 'utf8');
|
|
const surface = `${fs.readFileSync('renderer/index.html', 'utf8')}\n${modal}`;
|
|
const css = fs.readFileSync('renderer/styles/ps5-native-packages.css', 'utf8');
|
|
for (const source of [preload, web]) {
|
|
assert.match(source, /ps5UpstreamControl/);
|
|
assert.match(source, /ps5-native-packages:control-/);
|
|
}
|
|
assert.match(main, /PS5_CONTROL_SERVER_REQUIRED/);
|
|
assert.match(surface, /ps5-upstream-control-import/);
|
|
assert.match(modal, /INSTALL PS5 UPSTREAM CONTROL PACKAGE/);
|
|
assert.match(modal, /ps5UpstreamControl\('restore-verify'/);
|
|
assert.match(css, /ps5-upstream-control/);
|
|
});
|