186 lines
8.7 KiB
JavaScript
186 lines
8.7 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('node:assert/strict');
|
|
const crypto = require('node:crypto');
|
|
const test = require('node:test');
|
|
const {
|
|
A10_OBSERVER,
|
|
PPSA_ARTIFACT,
|
|
armP15R2LaunchBudget,
|
|
assessP15R2Dependencies,
|
|
assessP15R2Foreground,
|
|
assessP15R2InstalledContent,
|
|
assessP15R2LaunchReadiness,
|
|
classifyP15R2LaunchResult,
|
|
consumeP15R2LaunchBudget,
|
|
createP15R2LaunchBudget,
|
|
createP15R2Profile,
|
|
selectP15R2ObserverLane,
|
|
} = require('../../src/services/ps5-p15-r2-qualification');
|
|
|
|
function installedComplete() {
|
|
return {
|
|
installedObserved: true,
|
|
scanCoverageComplete: true,
|
|
scanCurrent: true,
|
|
titleIdExact: true,
|
|
contentIdExact: true,
|
|
versionExact: true,
|
|
applicationDrmTypeExpected: true,
|
|
sonyManagedInstallation: true,
|
|
appPkgPresent: true,
|
|
appPkgFullRead: true,
|
|
appPkgSizeCoherent: true,
|
|
appPkgHashStable: true,
|
|
paramJsonPresent: true,
|
|
paramJsonMatchesReference: true,
|
|
sourceManifestEbootPresent: true,
|
|
manifestCoverageComplete: true,
|
|
materiallyComplete: true,
|
|
ghostRegistrationAbsent: true,
|
|
mountRedirectAbsent: true,
|
|
};
|
|
}
|
|
|
|
function exactProfileInput() {
|
|
const tree = 'c'.repeat(40);
|
|
return {
|
|
repository: { commit: 'a'.repeat(40), tree, workingTreeDigest: crypto.createHash('sha256').update(`git-tree:${tree}`).digest('hex') },
|
|
firmware: '9.60',
|
|
installedContent: installedComplete(),
|
|
runtime: {
|
|
production: { status: 'exact', lane: 'production', identityExact: true },
|
|
ps5uploadRevision: A10_OBSERVER.baseRevision,
|
|
engineSha256: A10_OBSERVER.engineSha256,
|
|
payloadSha256: A10_OBSERVER.payloadSha256,
|
|
identityExact: true,
|
|
kstuffRevision: '3b2ab4a16ba43c8ab38daf7ec83cc297014e0e47',
|
|
kstuffIdentityExact: true,
|
|
},
|
|
observer: { ...A10_OBSERVER, identityExact: true },
|
|
foreground: {
|
|
inventoryComplete: true,
|
|
shellUiPid: 110,
|
|
runningBigAppId: -1,
|
|
applicationProcesses: [],
|
|
},
|
|
};
|
|
}
|
|
|
|
test('FTP offline only blocks when no complete alternative installed-content provider exists', () => {
|
|
const blocked = assessP15R2Dependencies({ ftp: { online: false }, alternativeInstalledContentProvider: { complete: false } });
|
|
assert.equal(blocked.ready, false);
|
|
assert.deepEqual(blocked.blocking, ['installed_content_provider_unavailable']);
|
|
const alternative = assessP15R2Dependencies({ ftp: { online: false }, alternativeInstalledContentProvider: { complete: true } });
|
|
assert.equal(alternative.ready, true);
|
|
});
|
|
|
|
test('optional provider outages do not block R2 qualification', () => {
|
|
const result = assessP15R2Dependencies({
|
|
ftp: { online: true },
|
|
optionalProviders: { standaloneDpi: false, voidPkg: false, websrv: false },
|
|
});
|
|
assert.equal(result.ready, true);
|
|
assert.deepEqual(result.blocking, []);
|
|
assert.deepEqual([...result.optionalOffline].sort(), ['standaloneDpi', 'voidPkg', 'websrv']);
|
|
});
|
|
|
|
test('installed visibility remains unproven until current full material evidence is complete', () => {
|
|
assert.equal(assessP15R2InstalledContent({ installedObserved: true }).status, 'installed_unproven');
|
|
assert.equal(assessP15R2InstalledContent({ ...installedComplete(), appPkgFullRead: false }).status, 'installed_incomplete');
|
|
const complete = assessP15R2InstalledContent({ ...installedComplete(), appPkgMatchesTransportHash: false });
|
|
assert.equal(complete.status, 'installed_complete');
|
|
assert.equal(complete.transportHashComparisonRequired, false);
|
|
});
|
|
|
|
test('launch stays blocked unless install, runtime, observer and foreground are exact', () => {
|
|
const input = exactProfileInput();
|
|
const cases = [
|
|
{ installedContent: { installedObserved: true }, reason: 'installed_content_integrity_unproven' },
|
|
{ runtime: { ...input.runtime, identityExact: false }, reason: 'active_runtime_identity_unproven' },
|
|
{ observer: { ...input.observer, identityExact: false }, reason: 'observer_identity_unproven' },
|
|
{ foreground: { ...input.foreground, applicationProcesses: [{ titleId: 'FAKE00000', pid: 222 }] }, reason: 'foreground_not_clean' },
|
|
];
|
|
for (const entry of cases) {
|
|
const readiness = assessP15R2LaunchReadiness({ ...input, ...entry });
|
|
assert.equal(readiness.launchEligible, false);
|
|
assert.ok(readiness.reasons.includes(entry.reason));
|
|
assert.deepEqual(readiness.launchBudget, { state: 'blocked', used: 0, total: 1, remaining: 1 });
|
|
}
|
|
});
|
|
|
|
test('profile rejects missing or mismatched Git tree identity', () => {
|
|
const missing = exactProfileInput();
|
|
delete missing.repository.tree;
|
|
assert.throws(() => createP15R2Profile(missing), error => error.code === 'P15_R2_PROFILE_UNPROVEN' && error.details.reasons.includes('repository_identity_unproven'));
|
|
const mismatch = exactProfileInput();
|
|
mismatch.repository.workingTreeDigest = 'f'.repeat(64);
|
|
assert.throws(() => createP15R2Profile(mismatch), error => error.code === 'P15_R2_PROFILE_UNPROVEN' && error.details.reasons.includes('repository_identity_unproven'));
|
|
});
|
|
|
|
test('budget arms once, is consumed before dispatch and ambiguity can never rearm it', () => {
|
|
const profile = createP15R2Profile(exactProfileInput());
|
|
const readiness = assessP15R2LaunchReadiness(profile);
|
|
const initial = createP15R2LaunchBudget();
|
|
assert.deepEqual(initial, { schema: 'chimera.ps5-p15-r2-launch-budget.v1', state: 'blocked', used: 0, total: 1, profileFingerprint: null, operationId: null, terminalOutcome: null });
|
|
const armed = armP15R2LaunchBudget(initial, readiness);
|
|
assert.equal(armed.state, 'armed');
|
|
const consumed = consumeP15R2LaunchBudget(armed, {
|
|
confirmation: 'LAUNCH VERIFY PPSA99099', operationId: 'p15-r2-owned-hardware-1', profileFingerprint: profile.fingerprint,
|
|
});
|
|
assert.equal(consumed.state, 'consumed');
|
|
assert.equal(consumed.used, 1);
|
|
assert.throws(() => armP15R2LaunchBudget(consumed, readiness), { code: 'P15_R2_LAUNCH_BUDGET_FINAL' });
|
|
});
|
|
|
|
test('R2 profile and observer lane bind exact artifact, runtime, observer and clean baseline', () => {
|
|
const profile = createP15R2Profile(exactProfileInput());
|
|
assert.equal(profile.id, 'P15-R2-PPSA99099');
|
|
assert.equal(profile.artifact.sha256, PPSA_ARTIFACT.sha256);
|
|
assert.equal(Object.isFrozen(profile), true);
|
|
const readiness = assessP15R2LaunchReadiness(profile);
|
|
assert.equal(readiness.launchEligible, true);
|
|
assert.equal(readiness.confirmation, 'LAUNCH VERIFY PPSA99099');
|
|
assert.equal(selectP15R2ObserverLane({ titleId: 'PPSA99099', readiness }), 'a10_transition');
|
|
assert.equal(selectP15R2ObserverLane({ titleId: 'PPSA99099', readiness: { ...readiness, launchEligible: false } }), 'blocked');
|
|
assert.equal(selectP15R2ObserverLane({ titleId: 'FAKE00000', readiness }), 'production');
|
|
});
|
|
|
|
test('foreground requires complete inventory, idle BigApp and no application process', () => {
|
|
assert.equal(assessP15R2Foreground(exactProfileInput().foreground).clean, true);
|
|
assert.equal(assessP15R2Foreground({ ...exactProfileInput().foreground, inventoryComplete: false }).clean, false);
|
|
assert.equal(assessP15R2Foreground({ ...exactProfileInput().foreground, runningBigAppId: 7 }).clean, false);
|
|
assert.equal(assessP15R2Foreground({ ...exactProfileInput().foreground, applicationProcesses: [{ titleId: 'CHIM00003', pid: 321 }] }).clean, false);
|
|
});
|
|
|
|
test('a numeric BigApp allocation without exact title attribution or process is not verified', () => {
|
|
const result = classifyP15R2LaunchResult({
|
|
lncAccepted: true, preRunningBigAppId: -1,
|
|
samples: [{ observedAfterMs: 100, runningBigAppId: 44, processInventoryComplete: true, targetPid: null }],
|
|
});
|
|
assert.equal(result.classification, 'accepted_unattributed_bigapp');
|
|
assert.equal(result.launchVerified, false);
|
|
});
|
|
|
|
test('exact PPSA BigApp attribution narrows the boundary but does not verify launch without a process', () => {
|
|
const result = classifyP15R2LaunchResult({
|
|
lncAccepted: true, preRunningBigAppId: -1,
|
|
samples: [{ observedAfterMs: 100, runningBigAppId: 44, resolvedTitleId: 'PPSA99099', processInventoryComplete: true, targetPid: null }],
|
|
});
|
|
assert.equal(result.classification, 'exact_title_bigapp_observed');
|
|
assert.equal(result.launchVerified, false);
|
|
});
|
|
|
|
test('stable exact PPSA process qualifies while content-auth internals remain unknown', () => {
|
|
const result = classifyP15R2LaunchResult({
|
|
lncAccepted: true, preRunningBigAppId: -1,
|
|
samples: [
|
|
{ observedAfterMs: 250, runningBigAppId: 44, processInventoryComplete: true, targetPid: 777, targetTitleId: 'PPSA99099' },
|
|
{ observedAfterMs: 1000, runningBigAppId: 44, processInventoryComplete: true, targetPid: 777, targetTitleId: 'PPSA99099' },
|
|
],
|
|
});
|
|
assert.equal(result.classification, 'stable_exact_title_process_observed');
|
|
assert.equal(result.launchVerified, true);
|
|
assert.deepEqual(result.contentAuthentication, { verifyImage: 'unknown', eicv: 'unknown', pfs: 'unknown' });
|
|
});
|