95 lines
5.1 KiB
JavaScript
95 lines
5.1 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
const { comparePs5PackageSets } = require('../../src/services/ps5-package-comparison-service');
|
|
|
|
function packageSet(id, sha256, overrides = {}) {
|
|
return {
|
|
id,
|
|
platform: 'ps5',
|
|
label: `package ${id}`,
|
|
manifest: { packageFormat: { container: 'FIH', debug: true, retail: false }, title: { titleId: 'PPSA17330' } },
|
|
components: [{
|
|
componentId: 'base', type: 'base', size: 1024, sha256,
|
|
version: '01.00',
|
|
metadata: {
|
|
contentId: { value: 'EP0001-PPSA17330_00-RCTCLASSIC000001' },
|
|
container: { value: 'FIH' },
|
|
},
|
|
}],
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test('compares exact component identities without claiming AppInst trust', () => {
|
|
const digest = 'a'.repeat(64);
|
|
const result = comparePs5PackageSets({
|
|
candidate: packageSet(4, digest),
|
|
reference: packageSet(3, digest),
|
|
operations: [],
|
|
});
|
|
|
|
assert.equal(result.identity.sameArtifacts, true);
|
|
assert.equal(result.differences.length, 0);
|
|
assert.equal(result.referenceTrust.status, 'unproven');
|
|
assert.equal(result.referenceTrust.installable, false);
|
|
assert.equal(result.verdict, 'no-material-difference');
|
|
});
|
|
|
|
test('reports material component changes and durable AppInst outcomes', () => {
|
|
const result = comparePs5PackageSets({
|
|
candidate: packageSet(4, 'b'.repeat(64), { components: [{ componentId: 'base', type: 'base', size: 2048, sha256: 'b'.repeat(64), version: '01.01', metadata: { contentId: { value: 'EP0001-PPSA17330_00-RCTCLASSIC000001' }, container: { value: 'FIH' } } }] }),
|
|
reference: packageSet(3, 'a'.repeat(64)),
|
|
operations: [
|
|
{ id: 'accepted', packageSetId: 3, status: 'completed', installed: true, evidence: { source: 'post-install-console-scan', observed_at: 123 } },
|
|
{ id: 'rejected', packageSetId: 4, status: 'blocked', installed: false, error: { code: 'PS5_PKG_INSTALL_REJECTED', terminalReason: 'sony-appinst-rejected', appInstError: 0x80B2116F, route: 'shellui-rpc' } },
|
|
],
|
|
});
|
|
|
|
assert.equal(result.identity.sameArtifacts, false);
|
|
assert.deepEqual(result.differences.map(item => item.fields), [['sha256', 'size', 'version']]);
|
|
assert.equal(result.referenceTrust.status, 'post-scan-proven');
|
|
assert.equal(result.referenceTrust.installable, true);
|
|
assert.equal(result.candidateTrust.status, 'appinst-rejected');
|
|
assert.equal(result.candidateTrust.appInstError, 0x80B2116F);
|
|
assert.equal(result.verdict, 'material-difference-from-proven-reference');
|
|
});
|
|
|
|
test('rejects cross-title and non-FIH comparisons', () => {
|
|
assert.throws(() => comparePs5PackageSets({
|
|
candidate: packageSet(4, 'b'.repeat(64)),
|
|
reference: packageSet(3, 'a'.repeat(64), { manifest: { packageFormat: { container: 'PKG' }, title: { titleId: 'PPSA99999' } } }),
|
|
}), error => error.code === 'PS5_PKG_COMPARISON_SCOPE');
|
|
});
|
|
|
|
test('compares read-only FIH profiles without exposing managed paths', () => {
|
|
const candidate = packageSet(4, 'b'.repeat(64)); candidate.components[0].metadata.absolutePath = 'C:/vault/candidate.pkg';
|
|
const reference = packageSet(3, 'a'.repeat(64)); reference.components[0].metadata.absolutePath = 'C:/vault/reference.pkg';
|
|
const result = comparePs5PackageSets({ candidate, reference, inspectPackage: filePath => ({
|
|
format: 'ps5-fih-debug-package',
|
|
validation: { validationLevel: 'fih-cnt-structural-v3', contentId: 'EP0001-PPSA17330_00-RCTCLASSIC000001', entryCount: filePath.includes('candidate') ? 18 : 17, geometry: { pfsOffset: 65536, pfsSize: 131072, cntOffset: 196608 }, imageKey: { size: 2048, profile: 'experimental-kstuff-rsa2048-native-stride', rsaRecordCount: 5, nativeSlotStride: 384 }, routeCompatibility: { status: 'unproven', basis: 'mailbox-route-not-established' }, installTrust: { status: 'unproven', basis: 'structural-only' } },
|
|
}) });
|
|
|
|
assert.deepEqual(result.differences[0].fields, ['sha256', 'structure']);
|
|
assert.equal(result.candidate.components[0].structure.entryCount, 18);
|
|
assert.equal(result.candidate.components[0].structure.routeCompatibility.status, 'unproven');
|
|
assert.equal(JSON.stringify(result).includes('C:/vault'), false);
|
|
});
|
|
|
|
test('comparison UI and read-only bridges are present', () => {
|
|
const fs = require('node:fs');
|
|
const html = fs.readFileSync('renderer/index.html', 'utf8');
|
|
const modal = fs.readFileSync('renderer/modules/modal.js', 'utf8');
|
|
const preload = fs.readFileSync('preload.js', 'utf8');
|
|
const shim = fs.readFileSync('renderer/pork-web-shim.js', 'utf8');
|
|
const registry = fs.readFileSync('src/server/create-registry.js', 'utf8');
|
|
const css = fs.readFileSync('renderer/styles/ps5-native-packages.css', 'utf8');
|
|
for (const id of ['ps5-package-comparison-candidate', 'ps5-package-comparison-reference', 'ps5-package-comparison-run', 'ps5-package-comparison-result']) assert.match(`${html}\n${modal}`, new RegExp(`id="${id}"`));
|
|
assert.match(modal, /ps5PackageComparison/);
|
|
assert.match(preload, /ps5PackageComparison/);
|
|
assert.match(shim, /ps5PackageComparison/);
|
|
assert.match(registry, /ps5-native-packages:compare[\s\S]*classification: 'read-only'/);
|
|
assert.match(css, /\.ps5-package-comparison-controls select \{ width: 100%; min-width: 0; \}/);
|
|
});
|