112 lines
4.0 KiB
JavaScript
112 lines
4.0 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
const {
|
|
ARTIFACT_SHA256,
|
|
KSTUFF_REVISION,
|
|
LIBPROSPERO_REVISION,
|
|
OBSERVER_ENGINE_SHA256,
|
|
OBSERVER_PAYLOAD_SHA256,
|
|
OBSERVER_SCHEDULE_MS,
|
|
PS5UPLOAD_REVISION,
|
|
assessP15R1LaunchReadiness,
|
|
createP15R1PpsaProfile,
|
|
verifyP15R1Profile,
|
|
} = require('../../src/services/ps5-p15-r1-profile');
|
|
|
|
function completeInstalledContent() {
|
|
return {
|
|
installedObserved: true,
|
|
titleIdExact: true,
|
|
contentIdExact: true,
|
|
versionExact: true,
|
|
applicationDrmTypeExpected: true,
|
|
sonyManagedInstallation: true,
|
|
manifestCoverageComplete: true,
|
|
manifestMatchesReference: true,
|
|
paramJsonPresent: true,
|
|
paramJsonMatchesReference: true,
|
|
ebootPresent: true,
|
|
ebootMatchesReference: true,
|
|
materiallyComplete: true,
|
|
};
|
|
}
|
|
|
|
function input(overrides = {}) {
|
|
return {
|
|
libProsperoRevision: LIBPROSPERO_REVISION,
|
|
repository: { commit: 'a'.repeat(40), workingTreeDigest: 'b'.repeat(64) },
|
|
runtime: {
|
|
firmware: '9.60',
|
|
ps5uploadRevision: PS5UPLOAD_REVISION,
|
|
engineSha256: OBSERVER_ENGINE_SHA256,
|
|
payloadSha256: OBSERVER_PAYLOAD_SHA256,
|
|
kstuffRevision: KSTUFF_REVISION,
|
|
identityExact: true,
|
|
kstuffIdentityExact: true,
|
|
dpiRuntimeActive: false,
|
|
},
|
|
observer: {
|
|
engineSha256: OBSERVER_ENGINE_SHA256,
|
|
payloadSha256: OBSERVER_PAYLOAD_SHA256,
|
|
scheduleMs: [...OBSERVER_SCHEDULE_MS],
|
|
shellUiObservation: true,
|
|
bigAppObservation: true,
|
|
processObservation: true,
|
|
},
|
|
installedContent: completeInstalledContent(),
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test('R1 freezes exact PPSA and observer identity into a tamper-evident profile', () => {
|
|
const profile = createP15R1PpsaProfile(input());
|
|
assert.equal(profile.id, 'P15-R1-PPSA99099');
|
|
assert.equal(profile.artifactSha256, ARTIFACT_SHA256);
|
|
assert.equal(Object.isFrozen(profile), true);
|
|
assert.equal(verifyP15R1Profile(profile), profile);
|
|
const tampered = structuredClone(profile);
|
|
tampered.runtime.identityExact = false;
|
|
assert.throws(() => verifyP15R1Profile(tampered), { code: 'P15_R1_PROFILE_CORRUPT' });
|
|
});
|
|
|
|
test('R1 readiness fails closed on historical installed-title visibility', () => {
|
|
const profile = createP15R1PpsaProfile(input({
|
|
installedContent: { installedObserved: true },
|
|
runtime: { ...input().runtime, identityExact: false, kstuffIdentityExact: false },
|
|
}));
|
|
const readiness = assessP15R1LaunchReadiness(profile);
|
|
assert.equal(readiness.launchEligible, false);
|
|
assert.deepEqual(readiness.reasons, ['installed_content_integrity_unproven', 'active_runtime_identity_unproven']);
|
|
assert.equal(readiness.launchBudget.used, 0);
|
|
assert.equal(readiness.confirmation, null);
|
|
});
|
|
|
|
test('R1 readiness exposes exactly one launch only after every read-only gate passes', () => {
|
|
const profile = createP15R1PpsaProfile(input());
|
|
const ready = assessP15R1LaunchReadiness(profile);
|
|
assert.equal(ready.launchEligible, true);
|
|
assert.deepEqual(ready.launchBudget, { used: 0, total: 1, remaining: 1 });
|
|
assert.equal(ready.confirmation, 'LAUNCH VERIFY PPSA99099');
|
|
assert.equal(ready.installAuthorized, false);
|
|
const consumed = assessP15R1LaunchReadiness(profile, { launchRequestsUsed: 1 });
|
|
assert.equal(consumed.launchEligible, false);
|
|
assert.deepEqual(consumed.reasons, ['one_run_budget_consumed']);
|
|
});
|
|
|
|
test('R1 readiness rejects an exact production runtime when the A10 observer is not active', () => {
|
|
const profile = createP15R1PpsaProfile(input({
|
|
runtime: {
|
|
...input().runtime,
|
|
engineSha256: 'd4055f43a57b36d1d2dec3e70ec03f73c9c47bc311d2b2f87145509ed53c8ba5',
|
|
payloadSha256: '33665dd87ede0dd020522222e9240405bac5036157132ba5fa92624378f94c7c',
|
|
},
|
|
}));
|
|
assert.deepEqual(assessP15R1LaunchReadiness(profile).reasons, ['active_runtime_identity_unproven']);
|
|
});
|
|
|
|
test('R1 profile rejects host and secret-bearing fields', () => {
|
|
assert.throws(() => createP15R1PpsaProfile({ ...input(), consoleHost: 'private' }), { code: 'P15_R1_PROFILE_SECRET' });
|
|
});
|