Initial curated chimera source from a8ae5b1db07fb49926c94585e2718e5130330974
This commit is contained in:
commit
c737a37f71
531 files changed
+119270
No files matched your search
@@ -0,0 +1,645 @@
|
||||
'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 { createPs5FpkgCompatibilityProfileService } = require('../../src/services/ps5-fpkg-compatibility-profile-service');
|
||||
const { createPs5UploadPackageInstallerProvider, P15_SHELLUI_DIAGNOSTIC } = require('../../src/services/ps5upload-package-installer-provider');
|
||||
const { normalizeShellUiLaunchObservation } = require('../../src/services/ps5-shellui-launch-observation');
|
||||
const { classifyPs5UploadRuntimeIdentity } = require('../../src/services/ps5upload-runtime-identity');
|
||||
|
||||
const PS5UPLOAD_REVISION = 'ec0e5c4e95520f2dc26c226a909dc5a95e385f41';
|
||||
const PS5UPLOAD_ENGINE_SHA256 = 'd4055f43a57b36d1d2dec3e70ec03f73c9c47bc311d2b2f87145509ed53c8ba5';
|
||||
const PS5UPLOAD_PAYLOAD_SHA256 = '33665dd87ede0dd020522222e9240405bac5036157132ba5fa92624378f94c7c';
|
||||
|
||||
function productionRuntimeIdentity() {
|
||||
return {
|
||||
expected: { version: '5.4.19', revision: PS5UPLOAD_REVISION, engineSha256: PS5UPLOAD_ENGINE_SHA256, payloadSha256: PS5UPLOAD_PAYLOAD_SHA256 },
|
||||
observed: {
|
||||
engine: { revision: PS5UPLOAD_REVISION, sha256: PS5UPLOAD_ENGINE_SHA256, evidence: 'running-process-bytes' },
|
||||
payload: { revision: PS5UPLOAD_REVISION, sha256: PS5UPLOAD_PAYLOAD_SHA256, evidence: 'loader-input-and-instance-transition' },
|
||||
dpi: { active: false },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function response(body, ok = true, status = 200) {
|
||||
return { ok, status, json: async () => body, text: async () => JSON.stringify(body) };
|
||||
}
|
||||
|
||||
function packageFixture() {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-pkg-'));
|
||||
const bytes = Buffer.concat([Buffer.from([0x7f, 0x46, 0x49, 0x48]), Buffer.alloc(64, 0x44)]);
|
||||
const filePath = path.join(root, 'UP9000-PPSA99099_00-PROSPERO00000000.pkg');
|
||||
fs.writeFileSync(filePath, bytes);
|
||||
return {
|
||||
root,
|
||||
component: {
|
||||
componentId: 'base', type: 'base', size: bytes.length,
|
||||
sha256: crypto.createHash('sha256').update(bytes).digest('hex'),
|
||||
contentId: 'UP9000-PPSA99099_00-PROSPERO00000000',
|
||||
metadata: { absolutePath: filePath, titleId: { value: 'PPSA99099' } },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeFetch(syslogs, requests) {
|
||||
return async (url, options = {}) => {
|
||||
const href = String(url); requests.push({ href, body: options.body ? JSON.parse(options.body) : null });
|
||||
if (href.endsWith('/api/version')) return response({ version: '5.4.19' });
|
||||
if (href.includes('/api/ps5/status')) return response({ version: '5.4.19', ps5_kernel: '9.60', instance_id: '12', ucred_elevated: true, running_big_app_id: -1 });
|
||||
if (href.includes('/api/ps5/readiness')) return response({ ready: true });
|
||||
if (href.includes('/api/ps5/process/list')) return response({ processes: [
|
||||
{ pid: 58, name: 'SceShellUI', comm: 'SceShellUI', kind: 'system' },
|
||||
{ pid: 107, name: 'kstuff.elf', comm: 'kstuff.elf', kind: 'payload' },
|
||||
{ pid: 108, name: 'etaHEN Utility Daemon', comm: 'etaHEN Utility Daemon', kind: 'system' },
|
||||
], truncated: false });
|
||||
if (href.includes('/api/ps5/syslog/tail')) return response({ text: syslogs.shift() ?? '' });
|
||||
if (href.includes('/api/ps5/app/launch')) return response({ ok: true });
|
||||
return response({});
|
||||
};
|
||||
}
|
||||
|
||||
test('read-only runtime observation reports ShellUI, BigApp and kstuff from one snapshot', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const observation = await createProvider(item, ['']).observeRuntime();
|
||||
assert.equal(observation.inventoryComplete, true);
|
||||
assert.equal(observation.shellUiPid, 58);
|
||||
assert.equal(observation.runningBigAppId, -1);
|
||||
assert.deepEqual(observation.kstuffProcesses, [{ pid: 107, name: 'kstuff.elf' }]);
|
||||
assert.deepEqual(observation.applicationProcesses, []);
|
||||
});
|
||||
|
||||
function createProvider(item, syslogs, requests = []) {
|
||||
return createPs5UploadPackageInstallerProvider({
|
||||
engineOrigin: 'http://127.0.0.1:19113', consoleHost: 'owned-console.local', packageRoot: item.root,
|
||||
getRuntimeIdentity: productionRuntimeIdentity,
|
||||
fetch: runtimeFetch(syslogs, requests),
|
||||
});
|
||||
}
|
||||
|
||||
const OPERATION_ID = '123e4567-e89b-42d3-a456-426614174000';
|
||||
const DIAGNOSTIC_SOURCE_SHA256 = '1'.repeat(64);
|
||||
const DIAGNOSTIC_DIFF_SHA256 = '2'.repeat(64);
|
||||
|
||||
function shellUiAttempt(overrides = {}) {
|
||||
return {
|
||||
index: 1,
|
||||
path: 'shellui_rpc',
|
||||
call_entered: true,
|
||||
dispatched: true,
|
||||
sony_return_observed: true,
|
||||
raw_rax_u64_hex: '0x0000000000000000',
|
||||
raw_low32_hex: '0x00000000',
|
||||
raw_signed32: 0,
|
||||
timed_out: false,
|
||||
tracee_lost: false,
|
||||
wrapper_rc: 0,
|
||||
wrapper_hex: '0x00000000',
|
||||
branch_taken: 'accepted',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function diagnosticObservation(overrides = {}) {
|
||||
return {
|
||||
schema: 'ps5upload.shellui-launch-observation.v1',
|
||||
diagnostic_identity: 'chimera-p15-shellui-observe-v1',
|
||||
base_revision: 'ec0e5c4e95520f2dc26c226a909dc5a95e385f41',
|
||||
operation_id: OPERATION_ID,
|
||||
title_id: 'FAKE00000',
|
||||
shellui: { pid_before: 186, pid_after: 186, same_process: true, init_rc: 0, ready: true },
|
||||
foreground_user_present: true,
|
||||
attempts: [shellUiAttempt()],
|
||||
internal_retry_occurred: false,
|
||||
retry_delay_ms: 0,
|
||||
terminal_attempt_index: 1,
|
||||
terminal_wrapper_rc: 0,
|
||||
terminal_wrapper_hex: '0x00000000',
|
||||
provider_normalized_result: 'accepted',
|
||||
provider_accepted: true,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test('A3 observation preserves raw zero separately from acknowledgement', () => {
|
||||
const normalized = normalizeShellUiLaunchObservation(diagnosticObservation(), {
|
||||
expectedIdentity: 'chimera-p15-shellui-observe-v1', operationId: OPERATION_ID, titleId: 'FAKE00000',
|
||||
});
|
||||
assert.equal(normalized.attempts[0].rawSigned32, 0);
|
||||
assert.equal(normalized.attempts[0].rawLow32Hex, '0x00000000');
|
||||
assert.equal(normalized.attempts[0].wrapperRc, 0);
|
||||
assert.equal(normalized.providerAccepted, true);
|
||||
assert.equal(normalized.terminalAttemptIndex, 1);
|
||||
});
|
||||
|
||||
test('A3 soft dispatch records wrapper -2 while raw Sony result remains unknown', () => {
|
||||
const observation = diagnosticObservation({
|
||||
attempts: [shellUiAttempt({ sony_return_observed: false, raw_rax_u64_hex: null, raw_low32_hex: null, raw_signed32: null, wrapper_rc: -2, wrapper_hex: '0xfffffffe', branch_taken: 'soft_dispatch' })],
|
||||
terminal_wrapper_rc: -2,
|
||||
terminal_wrapper_hex: '0xfffffffe',
|
||||
provider_normalized_result: 'accepted_or_soft_dispatched',
|
||||
});
|
||||
const normalized = normalizeShellUiLaunchObservation(observation, { expectedIdentity: observation.diagnostic_identity, operationId: OPERATION_ID, titleId: 'FAKE00000' });
|
||||
assert.equal(normalized.attempts[0].sonyReturnObserved, false);
|
||||
assert.equal(normalized.attempts[0].rawSigned32, null);
|
||||
assert.equal(normalized.attempts[0].wrapperRc, -2);
|
||||
assert.equal(normalized.attempts[0].wrapperHex, '0xfffffffe');
|
||||
assert.equal(normalized.internalRetryOccurred, false);
|
||||
});
|
||||
|
||||
test('A3 preserves an entered ShellUI call that failed before dispatch', () => {
|
||||
const observation = diagnosticObservation({
|
||||
attempts: [shellUiAttempt({
|
||||
dispatched: false,
|
||||
sony_return_observed: false,
|
||||
raw_rax_u64_hex: null,
|
||||
raw_low32_hex: null,
|
||||
raw_signed32: null,
|
||||
wrapper_rc: -1,
|
||||
wrapper_hex: '0xffffffff',
|
||||
branch_taken: 'fallback_pre_dispatch',
|
||||
})],
|
||||
terminal_wrapper_rc: -1,
|
||||
terminal_wrapper_hex: '0xffffffff',
|
||||
provider_normalized_result: 'launch_service_unavailable',
|
||||
provider_accepted: false,
|
||||
});
|
||||
const normalized = normalizeShellUiLaunchObservation(observation, {
|
||||
expectedIdentity: observation.diagnostic_identity, operationId: OPERATION_ID, titleId: 'FAKE00000',
|
||||
});
|
||||
assert.equal(normalized.attempts[0].callEntered, true);
|
||||
assert.equal(normalized.attempts[0].dispatched, false);
|
||||
assert.equal(normalized.attempts[0].sonyReturnObserved, false);
|
||||
});
|
||||
|
||||
test('A3 represents RPC not entered without inventing a Sony return', () => {
|
||||
const observation = diagnosticObservation({
|
||||
shellui: { pid_before: 0, pid_after: 0, same_process: false, init_rc: -1, ready: false },
|
||||
attempts: [],
|
||||
terminal_attempt_index: 0,
|
||||
terminal_wrapper_rc: -1,
|
||||
terminal_wrapper_hex: '0xffffffff',
|
||||
provider_normalized_result: 'launch_service_unavailable',
|
||||
provider_accepted: false,
|
||||
});
|
||||
const normalized = normalizeShellUiLaunchObservation(observation, {
|
||||
expectedIdentity: observation.diagnostic_identity, operationId: OPERATION_ID, titleId: 'FAKE00000',
|
||||
});
|
||||
assert.equal(normalized.attempts.length, 0);
|
||||
assert.equal(normalized.shellUi.ready, false);
|
||||
assert.equal(normalized.terminalAttemptIndex, 0);
|
||||
});
|
||||
|
||||
test('A3 retains a changed ShellUI PID as continuity evidence', () => {
|
||||
const observation = diagnosticObservation({
|
||||
shellui: { pid_before: 186, pid_after: 187, same_process: false, init_rc: 0, ready: true },
|
||||
});
|
||||
const normalized = normalizeShellUiLaunchObservation(observation, {
|
||||
expectedIdentity: observation.diagnostic_identity, operationId: OPERATION_ID, titleId: 'FAKE00000',
|
||||
});
|
||||
assert.equal(normalized.shellUi.pidBefore, 186);
|
||||
assert.equal(normalized.shellUi.pidAfter, 187);
|
||||
assert.equal(normalized.shellUi.sameProcess, false);
|
||||
assert.equal(normalized.providerAccepted, true);
|
||||
});
|
||||
|
||||
test('A3 represents two internal attempts without creating a second Chimera request', () => {
|
||||
const observation = diagnosticObservation({
|
||||
attempts: [
|
||||
shellUiAttempt({ raw_rax_u64_hex: '0x000000000000002a', raw_low32_hex: '0x0000002a', raw_signed32: 42, wrapper_rc: 42, wrapper_hex: '0x0000002a', branch_taken: 'retry_positive' }),
|
||||
shellUiAttempt({ index: 2 }),
|
||||
],
|
||||
internal_retry_occurred: true,
|
||||
retry_delay_ms: 250,
|
||||
terminal_attempt_index: 2,
|
||||
});
|
||||
const normalized = normalizeShellUiLaunchObservation(observation, { expectedIdentity: observation.diagnostic_identity, operationId: OPERATION_ID, titleId: 'FAKE00000' });
|
||||
assert.equal(normalized.attempts.length, 2);
|
||||
assert.equal(normalized.internalRetryOccurred, true);
|
||||
assert.equal(normalized.retryDelayMs, 250);
|
||||
assert.equal(normalized.terminalAttemptIndex, 2);
|
||||
});
|
||||
|
||||
test('A3 retains high-bit signed and hexadecimal semantics without changing the taken branch', () => {
|
||||
const observation = diagnosticObservation({
|
||||
attempts: [shellUiAttempt({ raw_rax_u64_hex: '0x0000000080940020', raw_low32_hex: '0x80940020', raw_signed32: -2137784288, wrapper_rc: -2137784288, wrapper_hex: '0x80940020', branch_taken: 'fallback_negative' })],
|
||||
terminal_wrapper_rc: -2137784288,
|
||||
terminal_wrapper_hex: '0x80940020',
|
||||
provider_normalized_result: 'launch_service_unavailable',
|
||||
provider_accepted: false,
|
||||
});
|
||||
const normalized = normalizeShellUiLaunchObservation(observation, { expectedIdentity: observation.diagnostic_identity, operationId: OPERATION_ID, titleId: 'FAKE00000' });
|
||||
assert.equal(normalized.attempts[0].rawSigned32, -2137784288);
|
||||
assert.equal(normalized.attempts[0].rawLow32Hex, '0x80940020');
|
||||
assert.equal(normalized.attempts[0].branchTaken, 'fallback_negative');
|
||||
const inconsistent = structuredClone(observation);
|
||||
inconsistent.attempts[0].raw_low32_hex = '0x80940021';
|
||||
assert.throws(() => normalizeShellUiLaunchObservation(inconsistent, { expectedIdentity: observation.diagnostic_identity, operationId: OPERATION_ID, titleId: 'FAKE00000' }), error => error.code === 'PS5_FPKG_DIAGNOSTIC_RESPONSE_INVALID');
|
||||
});
|
||||
|
||||
test('A3 rejects uncorrelated operations, titles, identities, attempts and secret-bearing fields', () => {
|
||||
const expected = { expectedIdentity: 'chimera-p15-shellui-observe-v1', operationId: OPERATION_ID, titleId: 'FAKE00000' };
|
||||
assert.throws(() => normalizeShellUiLaunchObservation({ ...diagnosticObservation(), operation_id: crypto.randomUUID() }, expected), error => error.code === 'PS5_FPKG_DIAGNOSTIC_CORRELATION');
|
||||
assert.throws(() => normalizeShellUiLaunchObservation({ ...diagnosticObservation(), title_id: 'PPSA99099' }, expected), error => error.code === 'PS5_FPKG_DIAGNOSTIC_CORRELATION');
|
||||
assert.throws(() => normalizeShellUiLaunchObservation({ ...diagnosticObservation(), diagnostic_identity: 'wrong' }, expected), error => error.code === 'PS5_FPKG_DIAGNOSTIC_IDENTITY');
|
||||
assert.throws(() => normalizeShellUiLaunchObservation({ ...diagnosticObservation(), attempts: [shellUiAttempt({ index: 2 })] }, expected), error => error.code === 'PS5_FPKG_DIAGNOSTIC_RESPONSE_INVALID');
|
||||
assert.throws(() => normalizeShellUiLaunchObservation({ ...diagnosticObservation(), token: 'must-not-persist' }, expected), error => error.code === 'PS5_FPKG_DIAGNOSTIC_RESPONSE_INVALID');
|
||||
assert.throws(() => normalizeShellUiLaunchObservation({ ...diagnosticObservation(), attempts: [shellUiAttempt({ branch_taken: 'retry_positive', raw_rax_u64_hex: '0x0000000000000001', raw_low32_hex: '0x00000001', raw_signed32: 1, wrapper_rc: 1, wrapper_hex: '0x00000001' })] }, expected), error => error.code === 'PS5_FPKG_DIAGNOSTIC_RESPONSE_INVALID');
|
||||
assert.throws(() => normalizeShellUiLaunchObservation({ ...diagnosticObservation(), provider_normalized_result: 'accepted', provider_accepted: false }, expected), error => error.code === 'PS5_FPKG_DIAGNOSTIC_RESPONSE_INVALID');
|
||||
});
|
||||
|
||||
test('diagnostic provider uses one correlated request and preserves a structured HTTP 502 result', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const requests = [];
|
||||
const observation = diagnosticObservation({
|
||||
attempts: [
|
||||
shellUiAttempt({ raw_rax_u64_hex: '0x000000000000001b', raw_low32_hex: '0x0000001b', raw_signed32: 27, wrapper_rc: 27, wrapper_hex: '0x0000001b', branch_taken: 'retry_positive' }),
|
||||
shellUiAttempt({ index: 2, raw_rax_u64_hex: '0x000000000000001b', raw_low32_hex: '0x0000001b', raw_signed32: 27, wrapper_rc: 27, wrapper_hex: '0x0000001b', branch_taken: 'terminal_positive' }),
|
||||
],
|
||||
internal_retry_occurred: true,
|
||||
retry_delay_ms: 250,
|
||||
terminal_attempt_index: 2,
|
||||
terminal_wrapper_rc: 27,
|
||||
terminal_wrapper_hex: '0x0000001b',
|
||||
provider_normalized_result: 'sony_rejected',
|
||||
provider_accepted: false,
|
||||
});
|
||||
const provider = createPs5UploadPackageInstallerProvider({
|
||||
engineOrigin: 'http://127.0.0.1:19113', consoleHost: 'owned-console.local', packageRoot: item.root,
|
||||
launchDiagnostic: P15_SHELLUI_DIAGNOSTIC,
|
||||
getRuntimeIdentity: () => ({
|
||||
expected: {
|
||||
version: '5.4.19', revision: PS5UPLOAD_REVISION,
|
||||
engineSha256: '4'.repeat(64), payloadSha256: '5'.repeat(64),
|
||||
diagnostic: { identity: P15_SHELLUI_DIAGNOSTIC.identity, baseRevision: PS5UPLOAD_REVISION, sourceSha256: DIAGNOSTIC_SOURCE_SHA256, diffSha256: DIAGNOSTIC_DIFF_SHA256 },
|
||||
},
|
||||
observed: {
|
||||
engine: { revision: PS5UPLOAD_REVISION, sha256: '4'.repeat(64), evidence: 'running-process-bytes' },
|
||||
payload: { revision: PS5UPLOAD_REVISION, sha256: '5'.repeat(64), evidence: 'loader-input-and-instance-transition', diagnosticIdentity: P15_SHELLUI_DIAGNOSTIC.identity },
|
||||
dpi: { active: false },
|
||||
},
|
||||
}),
|
||||
fetch: async (url, options = {}) => {
|
||||
const href = String(url); requests.push({ href, body: options.body ? JSON.parse(options.body) : null });
|
||||
if (href.endsWith('/api/version')) return response({
|
||||
version: '5.4.19', diagnostic_identity: P15_SHELLUI_DIAGNOSTIC.identity,
|
||||
base_revision: P15_SHELLUI_DIAGNOSTIC.baseRevision,
|
||||
observation_schema: P15_SHELLUI_DIAGNOSTIC.observationSchema,
|
||||
});
|
||||
if (href.endsWith('/api/ps5/app/launch')) return response({ ok: false, launch_observation: observation }, false, 502);
|
||||
return response({});
|
||||
},
|
||||
});
|
||||
const probe = await provider.probe();
|
||||
assert.equal(probe.available, true);
|
||||
assert.equal(probe.diagnostic.verified, true);
|
||||
const result = await provider.launch({ titleId: 'FAKE00000', operationId: OPERATION_ID });
|
||||
assert.equal(result.accepted, false);
|
||||
assert.equal(result.operationId, OPERATION_ID);
|
||||
assert.equal(result.diagnostic.terminalWrapperRc, 27);
|
||||
assert.equal(result.acknowledgement.httpStatus, 502);
|
||||
const launchRequests = requests.filter(entry => entry.href.endsWith('/api/ps5/app/launch'));
|
||||
assert.equal(launchRequests.length, 1);
|
||||
assert.deepEqual(launchRequests[0].body, { addr: 'owned-console.local:9114', title_id: 'FAKE00000', operation_id: OPERATION_ID });
|
||||
});
|
||||
|
||||
test('production and diagnostic providers fail closed across runtime identities', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const diagnosticVersion = {
|
||||
version: '5.4.19', diagnostic_identity: P15_SHELLUI_DIAGNOSTIC.identity,
|
||||
base_revision: P15_SHELLUI_DIAGNOSTIC.baseRevision,
|
||||
observation_schema: P15_SHELLUI_DIAGNOSTIC.observationSchema,
|
||||
};
|
||||
const production = createPs5UploadPackageInstallerProvider({
|
||||
engineOrigin: 'http://127.0.0.1:19113', consoleHost: 'owned-console.local', packageRoot: item.root,
|
||||
fetch: async () => response(diagnosticVersion),
|
||||
});
|
||||
const productionProbe = await production.probe();
|
||||
assert.equal(productionProbe.available, false);
|
||||
assert.equal(productionProbe.reason, 'diagnostic-runtime-not-production');
|
||||
|
||||
const diagnostic = createPs5UploadPackageInstallerProvider({
|
||||
engineOrigin: 'http://127.0.0.1:19113', consoleHost: 'owned-console.local', packageRoot: item.root,
|
||||
launchDiagnostic: P15_SHELLUI_DIAGNOSTIC,
|
||||
fetch: async () => response({ version: '5.4.19' }),
|
||||
});
|
||||
const diagnosticProbe = await diagnostic.probe();
|
||||
assert.equal(diagnosticProbe.available, false);
|
||||
assert.equal(diagnosticProbe.reason, 'diagnostic-identity-mismatch');
|
||||
});
|
||||
|
||||
test('A5 mutation fails closed before launch when running-byte identity is absent', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
let mutationRequests = 0;
|
||||
const provider = createPs5UploadPackageInstallerProvider({
|
||||
engineOrigin: 'http://127.0.0.1:19113', consoleHost: 'owned-console.local', packageRoot: item.root,
|
||||
fetch: async (url, options = {}) => {
|
||||
if (options.method === 'POST') mutationRequests += 1;
|
||||
const href = String(url);
|
||||
if (href.endsWith('/api/version')) return response({ version: '5.4.19' });
|
||||
if (href.includes('/api/ps5/status')) return response({ version: '5.4.19' });
|
||||
return response({});
|
||||
},
|
||||
});
|
||||
await assert.rejects(
|
||||
provider.launch({ titleId: 'FAKE00000' }),
|
||||
error => error.code === 'PS5_FPKG_RUNTIME_IDENTITY_UNPROVEN',
|
||||
);
|
||||
assert.equal(mutationRequests, 0);
|
||||
});
|
||||
|
||||
test('A5 provider accepts the classified identity returned by the owned runtime service', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
let launches = 0;
|
||||
const provider = createPs5UploadPackageInstallerProvider({
|
||||
engineOrigin: 'http://127.0.0.1:19113', consoleHost: 'owned-console.local', packageRoot: item.root,
|
||||
getRuntimeIdentity: async () => classifyPs5UploadRuntimeIdentity({ lane: 'production', ...productionRuntimeIdentity() }),
|
||||
fetch: async (url, options = {}) => {
|
||||
const href = String(url);
|
||||
if (href.endsWith('/api/version')) return response({ version: '5.4.19' });
|
||||
if (href.includes('/api/ps5/status')) return response({ version: '5.4.19' });
|
||||
if (href.includes('/api/ps5/app/launch') && options.method === 'POST') { launches += 1; return response({ ok: true }); }
|
||||
return response({});
|
||||
},
|
||||
});
|
||||
const result = await provider.launch({ titleId: 'FAKE00000' });
|
||||
assert.equal(result.accepted, true);
|
||||
assert.equal(launches, 1);
|
||||
});
|
||||
|
||||
test('launch syslog watermark excludes stale failures and classifies only the current window', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const stale = '[old] verifyImage failed for another title\n[old] idle';
|
||||
const current = `${stale}\n[now] PfsMountGameData_PPR() = 0x80020060`;
|
||||
const requests = [];
|
||||
const provider = createProvider(item, [stale, current], requests);
|
||||
const preflight = await provider.preflightLaunch({ titleId: 'PPSA99099', components: [item.component] });
|
||||
assert.equal(preflight.ready, true);
|
||||
assert.equal(preflight.capabilities.syslogObservationReady, true);
|
||||
assert.match(preflight.logWatermark.sha256, /^[a-f0-9]{64}$/);
|
||||
const observed = await provider.observeLaunch({ titleId: 'PPSA99099', logWatermark: preflight.logWatermark });
|
||||
assert.equal(observed.failureBoundary, 'PFS mount');
|
||||
assert.equal(observed.failureCode, 'PS5_FPKG_PFS_MOUNT_FAILED');
|
||||
assert.equal(observed.syslog.continuity, 'exact-watermark');
|
||||
assert.doesNotMatch(observed.syslog.currentWindow, /verifyImage/);
|
||||
assert.ok(requests.some(entry => entry.href.includes('/api/ps5/syslog/tail')));
|
||||
});
|
||||
|
||||
test('current exact-title ShellUI LaunchFlowError is a distinct executable boundary', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const baselineText = '[old] idle';
|
||||
const currentText = `${baselineText}\n[SceShellUI] SceneQ Loaded: LaunchFlowError.FAKE00000 : Scene`;
|
||||
const provider = createProvider(item, [baselineText, currentText]);
|
||||
const preflight = await provider.preflightLaunch({ titleId: 'PPSA99099', components: [item.component] });
|
||||
const unrelated = await provider.observeLaunch({ titleId: 'PPSA99099', logWatermark: preflight.logWatermark });
|
||||
assert.equal(unrelated.failureBoundary, null);
|
||||
|
||||
const exactProvider = createProvider(item, [baselineText, currentText]);
|
||||
const exactPreflight = await exactProvider.preflightLaunch({ titleId: 'FAKE00000', components: [{ ...item.component, contentId: 'IV9999-FAKE00000_00-HOMEBREWLOADER01', metadata: { ...item.component.metadata, titleId: { value: 'FAKE00000' } } }] });
|
||||
const exact = await exactProvider.observeLaunch({ titleId: 'FAKE00000', logWatermark: exactPreflight.logWatermark });
|
||||
assert.equal(exact.failureBoundary, 'ShellUI launch flow');
|
||||
assert.equal(exact.failureCode, 'PS5_FPKG_SHELLUI_LAUNCH_FLOW_FAILED');
|
||||
});
|
||||
|
||||
test('A6 combined log separates network refusal and retains verifyImage as the auth boundary', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const baselineText = '[old] idle';
|
||||
const currentText = `${baselineText}\nResourceArbitrator returned 0x8041013d\nERROR: verifyImage(989) ret -1\nverify error=0xffffffff -> EICV\nPfsMountGameData_PPR() ret = 0x80020060\nLaunchFlowError.FAKE00000`;
|
||||
const provider = createProvider(item, [baselineText, currentText]);
|
||||
const preflight = await provider.preflightLaunch({ titleId: 'FAKE00000', components: [{ ...item.component, contentId: 'IV9999-FAKE00000_00-HOMEBREWLOADER01', metadata: { ...item.component.metadata, titleId: { value: 'FAKE00000' } } }] });
|
||||
const observed = await provider.observeLaunch({ titleId: 'FAKE00000', logWatermark: preflight.logWatermark });
|
||||
assert.equal(observed.failureBoundary, 'verifyImage');
|
||||
assert.equal(observed.failureCode, 'PS5_FPKG_VERIFY_IMAGE_FAILED');
|
||||
assert.equal(observed.normalizedEvents[0].subsystem, 'network');
|
||||
assert.equal(observed.normalizedEvents[0].causalStatus, 'unknown');
|
||||
});
|
||||
|
||||
test('launch preflight fails closed while an ordinary foreground app is active', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const provider = createPs5UploadPackageInstallerProvider({
|
||||
engineOrigin: 'http://127.0.0.1:19113', consoleHost: 'owned-console.local', packageRoot: item.root,
|
||||
getRuntimeIdentity: productionRuntimeIdentity,
|
||||
fetch: async url => {
|
||||
const href = String(url);
|
||||
if (href.endsWith('/api/version')) return response({ version: '5.4.19' });
|
||||
if (href.includes('/api/ps5/status')) return response({ version: '5.4.19', instance_id: '12', ucred_elevated: true });
|
||||
if (href.includes('/api/ps5/readiness')) return response({ ready: true });
|
||||
if (href.includes('/api/ps5/process/list')) return response({ processes: [
|
||||
{ pid: 107, name: 'kstuff.elf', kind: 'payload' },
|
||||
{ pid: 108, name: 'etaHEN Utility Daemon', kind: 'system' },
|
||||
{ pid: 121, name: 'eboot.bin', title_id: 'PPSA02774', kind: 'app' },
|
||||
], truncated: false });
|
||||
if (href.includes('/api/ps5/syslog/tail')) return response({ text: '' });
|
||||
return response({});
|
||||
},
|
||||
});
|
||||
const preflight = await provider.preflightLaunch({ titleId: 'PPSA99099', components: [item.component] });
|
||||
assert.equal(preflight.ready, false);
|
||||
assert.equal(preflight.capabilities.foregroundClean, false);
|
||||
assert.deepEqual(preflight.runtime.foregroundGameProcesses, [{ pid: 121, titleId: 'PPSA02774', name: 'eboot.bin' }]);
|
||||
});
|
||||
|
||||
test('unchanged or continuity-lost syslog cannot replay stale failure evidence', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const stale = '[old] verifyImage failed\n[old] idle';
|
||||
const unchanged = createProvider(item, [stale, stale]);
|
||||
const baseline = await unchanged.preflightLaunch({ titleId: 'PPSA99099', components: [item.component] });
|
||||
const noNewEvidence = await unchanged.observeLaunch({ titleId: 'PPSA99099', logWatermark: baseline.logWatermark });
|
||||
assert.equal(noNewEvidence.failureBoundary, null);
|
||||
assert.equal(noNewEvidence.syslog.currentWindow, '');
|
||||
|
||||
const rolled = createProvider(item, [stale, '[unrelated buffer rollover]\nEICV failed']);
|
||||
const rolledBaseline = await rolled.preflightLaunch({ titleId: 'PPSA99099', components: [item.component] });
|
||||
const unknown = await rolled.observeLaunch({ titleId: 'PPSA99099', logWatermark: rolledBaseline.logWatermark });
|
||||
assert.equal(unknown.failureBoundary, null);
|
||||
assert.equal(unknown.syslog.continuity, 'lost');
|
||||
assert.equal(unknown.syslog.currentWindow, '');
|
||||
});
|
||||
|
||||
test('syslog watermark and current window redact credential forms before persistence', async t => {
|
||||
const item = packageFixture(); t.after(() => fs.rmSync(item.root, { recursive: true, force: true }));
|
||||
const secretLog = 'Authorization: Bearer header-secret token="json-secret" https://user:pass@example.invalid/path?api_key=query-secret';
|
||||
const provider = createProvider(item, [secretLog, `${secretLog}\n[now] harmless`]);
|
||||
const preflight = await provider.preflightLaunch({ titleId: 'PPSA99099', components: [item.component] });
|
||||
const serializedWatermark = JSON.stringify(preflight.logWatermark);
|
||||
for (const secret of ['header-secret', 'json-secret', 'user', 'pass', 'query-secret']) assert.doesNotMatch(serializedWatermark, new RegExp(secret));
|
||||
assert.match(serializedWatermark, /REDACTED/);
|
||||
|
||||
const observed = await provider.observeLaunch({ titleId: 'PPSA99099', logWatermark: preflight.logWatermark });
|
||||
assert.equal(observed.syslog.currentWindow, '\n[now] harmless');
|
||||
});
|
||||
|
||||
function profileInput() {
|
||||
return {
|
||||
firmware: '9.60',
|
||||
runtime: { etaHenVersion: '2.4b', managementInstanceId: '12' },
|
||||
ps5upload: {
|
||||
version: '5.4.19', revision: 'ec0e5c4e95520f2dc26c226a909dc5a95e385f41',
|
||||
payloadSha256: '3'.repeat(64), engineSha256: 'd'.repeat(64), dpiSha256: '6'.repeat(64),
|
||||
runtimeIdentity: {
|
||||
status: 'exact', lane: 'production',
|
||||
engine: { expectedSha256: 'd'.repeat(64), observedSha256: 'd'.repeat(64), version: '5.4.19', revision: PS5UPLOAD_REVISION },
|
||||
payload: { expectedSha256: '3'.repeat(64), observedSha256: '3'.repeat(64), version: '5.4.19', revision: PS5UPLOAD_REVISION },
|
||||
dpi: { active: false, expectedSha256: '6'.repeat(64) },
|
||||
},
|
||||
routes: ['/api/ps5/app/launch', '/api/ps5/process/list', '/api/ps5/syslog/tail'],
|
||||
},
|
||||
bridge: { revision: '9084c0e88cd8d7cd9c0b353b8b6b89f7d1cc4275', abi: 'chimera-prospero-bridge-v4', clean: true },
|
||||
repository: { commit: '2'.repeat(40), dirty: false, sourceTreeSha256: 'e'.repeat(64) },
|
||||
capabilities: { fpkgEnableActive: true, launchServiceReady: true, processObservationReady: true, syslogObservationReady: true },
|
||||
};
|
||||
}
|
||||
|
||||
test('compatibility profile is immutable, secret-free and drift-addressed', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-profile-'));
|
||||
const stateFile = path.join(root, 'profile.json');
|
||||
try {
|
||||
const service = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 1000, uuid: () => 'profile-1' });
|
||||
const frozen = service.freeze(profileInput());
|
||||
assert.equal(frozen.id, 'profile-1');
|
||||
assert.match(frozen.fingerprint, /^[a-f0-9]{64}$/);
|
||||
assert.deepEqual(service.assertCurrent(profileInput()), frozen);
|
||||
assert.throws(() => service.freeze({ ...profileInput(), firmware: '9.61' }), error => error.code === 'PS5_FPKG_PROFILE_IMMUTABLE');
|
||||
assert.throws(() => service.assertCurrent({ ...profileInput(), firmware: '9.61' }), error => error.code === 'PS5_FPKG_PROFILE_DRIFT');
|
||||
assert.throws(() => service.freeze({ ...profileInput(), token: 'secret' }), error => error.code === 'PS5_FPKG_PROFILE_SECRET');
|
||||
assert.doesNotMatch(fs.readFileSync(stateFile, 'utf8'), /owned-console|token|password/i);
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('A5 compatibility profiles reject missing, split or hash-drifting runtime identity', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-a5-profile-'));
|
||||
try {
|
||||
const missing = profileInput();
|
||||
delete missing.ps5upload.runtimeIdentity;
|
||||
assert.throws(
|
||||
() => createPs5FpkgCompatibilityProfileService({ stateFile: path.join(root, 'missing.json') }).freeze(missing),
|
||||
error => error.code === 'PS5_FPKG_PROFILE_RUNTIME_IDENTITY',
|
||||
);
|
||||
const split = profileInput();
|
||||
split.ps5upload.runtimeIdentity.status = 'split';
|
||||
assert.throws(
|
||||
() => createPs5FpkgCompatibilityProfileService({ stateFile: path.join(root, 'split.json') }).freeze(split),
|
||||
error => error.code === 'PS5_FPKG_PROFILE_RUNTIME_IDENTITY',
|
||||
);
|
||||
const drift = profileInput();
|
||||
drift.ps5upload.runtimeIdentity.engine.observedSha256 = 'a'.repeat(64);
|
||||
assert.throws(
|
||||
() => createPs5FpkgCompatibilityProfileService({ stateFile: path.join(root, 'drift.json') }).freeze(drift),
|
||||
error => error.code === 'PS5_FPKG_PROFILE_RUNTIME_IDENTITY',
|
||||
);
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('A3 diagnostic profile and ledger are isolated from the immutable A2 state', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-profile-isolation-'));
|
||||
const a2File = path.join(root, 'p15-a2-ledger.json');
|
||||
const a3File = path.join(root, 'p15-a3-ledger.json');
|
||||
try {
|
||||
const a2 = createPs5FpkgCompatibilityProfileService({ stateFile: a2File, now: () => 100, uuid: () => 'a2-profile' });
|
||||
const a2Profile = a2.freeze(profileInput());
|
||||
const a2Bytes = fs.readFileSync(a2File);
|
||||
const a3Input = profileInput();
|
||||
a3Input.ps5upload.diagnostic = {
|
||||
identity: P15_SHELLUI_DIAGNOSTIC.identity,
|
||||
baseRevision: P15_SHELLUI_DIAGNOSTIC.baseRevision,
|
||||
observationSchema: P15_SHELLUI_DIAGNOSTIC.observationSchema,
|
||||
sourceSha256: DIAGNOSTIC_SOURCE_SHA256,
|
||||
diffSha256: DIAGNOSTIC_DIFF_SHA256,
|
||||
engineSha256: '4'.repeat(64),
|
||||
payloadSha256: '5'.repeat(64),
|
||||
};
|
||||
a3Input.ps5upload.runtimeIdentity = {
|
||||
status: 'exact', lane: 'diagnostic',
|
||||
engine: { expectedSha256: '4'.repeat(64), observedSha256: '4'.repeat(64), version: '5.4.19', revision: PS5UPLOAD_REVISION },
|
||||
payload: { expectedSha256: '5'.repeat(64), observedSha256: '5'.repeat(64), version: '5.4.19', revision: PS5UPLOAD_REVISION },
|
||||
dpi: { active: false, expectedSha256: '6'.repeat(64) },
|
||||
};
|
||||
const a3 = createPs5FpkgCompatibilityProfileService({ stateFile: a3File, now: () => 200, uuid: () => 'a3-profile' });
|
||||
const a3Profile = a3.freeze(a3Input);
|
||||
assert.notEqual(a3Profile.fingerprint, a2Profile.fingerprint);
|
||||
assert.deepEqual(fs.readFileSync(a2File), a2Bytes);
|
||||
assert.equal(a3Profile.ps5upload.diagnostic.identity, P15_SHELLUI_DIAGNOSTIC.identity);
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('hardware ledger permits one run per exact profile artifact and plan and survives restart', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-ledger-'));
|
||||
const stateFile = path.join(root, 'profile.json');
|
||||
try {
|
||||
const service = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 2000, uuid: () => 'profile-1' });
|
||||
const profile = service.freeze(profileInput());
|
||||
const input = { profileFingerprint: profile.fingerprint, artifactSha256: 'a'.repeat(64), plan: { lane: 'upstream-control', titleId: 'PPSA99099', actions: ['install', 'post-scan', 'launch', 'observe-process'] } };
|
||||
const run = service.beginRun(input);
|
||||
assert.equal(run.status, 'in_progress');
|
||||
assert.throws(() => service.beginRun(input), error => error.code === 'PS5_FPKG_HARDWARE_RUN_ALREADY_USED');
|
||||
const restarted = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 3000, uuid: () => 'unused' });
|
||||
assert.equal(restarted.runs()[0].status, 'outcome_unknown');
|
||||
assert.throws(() => restarted.beginRun(input), error => error.code === 'PS5_FPKG_HARDWARE_RUN_ALREADY_USED');
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('explicit external controller can complete an authorized run across CLI process boundaries', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-external-'));
|
||||
const stateFile = path.join(root, 'profile.json');
|
||||
try {
|
||||
const first = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 100, uuid: () => 'profile-or-run' });
|
||||
const profile = first.freeze(profileInput());
|
||||
const run = first.beginRun({ profileFingerprint: profile.fingerprint, artifactSha256: 'b'.repeat(64), plan: { titleId: 'PPSA99099', automaticRetry: false } });
|
||||
const completion = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 200, recoverInProgress: false });
|
||||
const completed = completion.completeRun(run.id, { status: 'failed', evidence: { boundary: 'executable-not-reached' } });
|
||||
assert.equal(completed.status, 'failed');
|
||||
assert.equal(completed.evidence.boundary, 'executable-not-reached');
|
||||
assert.equal(createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 300 }).runs()[0].status, 'failed');
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('A8 hardware ledger fails closed on corrupt persisted state without overwriting it', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-a8-corrupt-ledger-'));
|
||||
const stateFile = path.join(root, 'profile.json');
|
||||
const corrupt = Buffer.from('{"schema":"wrong","runs":');
|
||||
try {
|
||||
fs.writeFileSync(stateFile, corrupt);
|
||||
assert.throws(
|
||||
() => createPs5FpkgCompatibilityProfileService({ stateFile }),
|
||||
error => error.code === 'PS5_FPKG_HARDWARE_LEDGER_CORRUPT',
|
||||
);
|
||||
assert.deepEqual(fs.readFileSync(stateFile), corrupt);
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('A8 hardware ledger reloads under lock and metadata cannot reopen a consumed role', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ch1401-a8-cas-ledger-'));
|
||||
const stateFile = path.join(root, 'profile.json');
|
||||
try {
|
||||
const owner = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 100, uuid: () => 'profile' });
|
||||
const profile = owner.freeze(profileInput());
|
||||
const first = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 200, uuid: () => 'run-a', recoverInProgress: false });
|
||||
const stale = createPs5FpkgCompatibilityProfileService({ stateFile, now: () => 200, uuid: () => 'run-b', recoverInProgress: false });
|
||||
const base = {
|
||||
profileFingerprint: profile.fingerprint,
|
||||
artifactSha256: 'c'.repeat(64),
|
||||
plan: { experimentId: 'p15-a8', role: 'control', titleId: 'PPSA99099', automaticRetry: false, note: 'first' },
|
||||
};
|
||||
first.beginRun(base);
|
||||
assert.throws(
|
||||
() => stale.beginRun({ ...base, plan: { ...base.plan, note: 'metadata-only-change' } }),
|
||||
error => error.code === 'PS5_FPKG_HARDWARE_RUN_ALREADY_USED',
|
||||
);
|
||||
assert.throws(
|
||||
() => stale.beginRun({ ...base, artifactSha256: 'd'.repeat(64) }),
|
||||
error => error.code === 'PS5_FPKG_HARDWARE_RUN_ALREADY_USED',
|
||||
);
|
||||
assert.equal(stale.runs().length, 1);
|
||||
|
||||
fs.writeFileSync(`${stateFile}.lock`, 'held', { flag: 'wx' });
|
||||
assert.throws(
|
||||
() => stale.beginRun({ ...base, artifactSha256: 'e'.repeat(64), plan: { ...base.plan, role: 'reference', titleId: 'FAKE00000' } }),
|
||||
error => error.code === 'PS5_FPKG_HARDWARE_LEDGER_BUSY',
|
||||
);
|
||||
assert.equal(stale.runs().length, 1);
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
Reference in new issue
Block a user