'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 { EventEmitter } = require('node:events'); const { PS5UPLOAD_RUNTIME, createPs5UploadRuntimeService } = require('../../src/services/ps5upload-runtime-service'); const { LINUX_LISTENER_PROCESS_EVIDENCE, LINUX_PROCESS_EVIDENCE } = require('../../src/services/linux-listener-process'); const digest = value => crypto.createHash('sha256').update(value).digest('hex'); const TEST_BOOT_ID = '11111111-2222-4333-8444-555555555555'; const TEST_NAMESPACES = Object.freeze({ net: 'net:[4001]', pid: 'pid:[4002]', mnt: 'mnt:[4003]' }); function listenerIdentity(input, overrides = {}) { return { verified: true, bootId: TEST_BOOT_ID, pid: 4242, startTimeTicks: '123456', socketInode: '555', exePath: input.enginePath, exeDev: '11', exeIno: '22', sha256: input.expectedSha256, uid: 10001, namespaces: TEST_NAMESPACES, cgroup: '0::/docker/chimera', evidence: LINUX_LISTENER_PROCESS_EVIDENCE, ...overrides, }; } function processIdentity(input, overrides = {}) { const { socketInode: _socketInode, ...identity } = listenerIdentity(input, overrides); return { ...identity, evidence: LINUX_PROCESS_EVIDENCE }; } test('A5 production pin selects the clean static 5.4.19 engine proven on the deployed host', () => { assert.equal(PS5UPLOAD_RUNTIME.version, '5.4.19'); assert.equal(PS5UPLOAD_RUNTIME.revision, 'ec0e5c4e95520f2dc26c226a909dc5a95e385f41'); assert.equal(PS5UPLOAD_RUNTIME.enginePath, '/payloads/ps5upload/5.4.19/ps5upload-engine-static'); assert.equal(PS5UPLOAD_RUNTIME.engineSha256, 'd4055f43a57b36d1d2dec3e70ec03f73c9c47bc311d2b2f87145509ed53c8ba5'); }); function fixture(t, overrides = {}) { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ps5upload-runtime-')); t.after(() => fs.rmSync(root, { recursive: true, force: true })); const engine = Buffer.from('engine-5.4.19'); const payload = Buffer.from('elf-5.4.19'); const dpi = Buffer.from('dpi-5.4.19'); const enginePath = path.join(root, 'ps5upload-engine'); const payloadPath = path.join(root, 'ps5upload.elf'); const dpiPath = path.join(root, 'ezremote-dpi.elf'); fs.writeFileSync(enginePath, engine, { mode: 0o750 }); fs.writeFileSync(payloadPath, payload, { mode: 0o640 }); fs.writeFileSync(dpiPath, dpi, { mode: 0o640 }); let payloadGeneration = 1; const customFetch = overrides.fetch; const customTcpSend = overrides.tcpSend; const remainingOverrides = { ...overrides }; delete remainingOverrides.fetch; delete remainingOverrides.tcpSend; if (remainingOverrides.processPlatform === 'linux' && !remainingOverrides.inspectSpawnedProcess) { remainingOverrides.inspectSpawnedProcess = async input => processIdentity(input); } return createPs5UploadRuntimeService({ enginePath, payloadPath, dpiPath, expectedEngineSha256: digest(engine), expectedPayloadSha256: digest(payload), expectedDpiSha256: digest(dpi), consoleHost: () => '192.0.2.55', fetch: customFetch || (async url => { const href = String(url); if (href.endsWith('/api/version')) return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; if (href.includes('/api/ps5/status')) return { ok: true, status: 200, json: async () => ({ version: '5.4.19', instance_id: String(payloadGeneration), started_at_unix: payloadGeneration }) }; return { ok: true, status: 200, json: async () => ({ ok: true, users: [] }) }; }), tcpProbe: async () => true, enginePortProbe: async () => false, tcpSend: async input => { payloadGeneration += 1; return customTcpSend ? customTcpSend(input) : { ok: true, bytes: input.bytes.length }; }, delay: async () => {}, processPlatform: 'win32', inspectExistingEngine: async input => listenerIdentity(input), terminateProvenProcess: async () => ({ terminated: true, identityGone: true, forced: false }), ...remainingOverrides, }); } test('runtime preflight proves exact engine and payload artifacts before reporting ready', async t => { const runtime = fixture(t); const result = await runtime.preflight(); assert.equal(result.ready, true); assert.equal(result.engine.version, '5.4.19'); assert.equal(result.payload.verified, true); assert.equal(result.loader.reachable, true); assert.equal(result.loader.port, 9021); }); test('runtime blocks hash drift and never offers the loader action', async t => { const runtime = fixture(t, { expectedPayloadSha256: '0'.repeat(64) }); const result = await runtime.preflight(); assert.equal(result.ready, false); assert.equal(result.payload.reason, 'sha256-mismatch'); await assert.rejects(() => runtime.startPayload(), error => error.code === 'PS5UPLOAD_PREFLIGHT_BLOCKED'); }); test('engine start uses a fixed executable without shell and keeps stdin open', async t => { const calls = []; const child = new EventEmitter(); child.stdin = { destroyed: false, end() { this.destroyed = true; child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => true; const runtime = fixture(t, { fetch: async () => { throw new Error('not listening yet'); }, spawn: (file, args, options) => { calls.push({ file, args, options }); return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), }); const result = await runtime.startEngine(); assert.equal(result.available, true); assert.equal(calls.length, 1); assert.deepEqual(calls[0].args, []); assert.equal(calls[0].options.shell, false); assert.equal(calls[0].options.env.PS5_ADDR, '192.0.2.55:9113'); assert.equal(calls[0].options.env.PS5UPLOAD_ENGINE_PORT, '19113'); await runtime.stopEngine(); assert.equal(child.stdin.destroyed, true); }); test('Linux engine start goes through the fixed parent-death process guard', async t => { const calls = []; const guardPath = path.join(os.tmpdir(), 'chimera-process-guard-test'); let running = false; const child = new EventEmitter(); child.pid = 4242; child.stdin = { end() { running = false; child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => true; const runtime = fixture(t, { fetch: async url => { if (!running || !String(url).endsWith('/api/version')) throw new Error('not listening'); return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; }, processPlatform: 'linux', processGuardPath: guardPath, verifyProcessGuard: () => ({ verified: true, path: guardPath }), spawn: (file, args, options) => { calls.push({ file, args, options }); running = true; return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), enginePortProbe: async () => running, }); await runtime.startEngine(); assert.equal(calls.length, 1); assert.equal(calls[0].file, guardPath); assert.equal(calls[0].args[0], '--pdeathsig-exec'); assert.equal(path.basename(calls[0].args[1]), 'ps5upload-engine'); assert.equal(calls[0].options.shell, false); await runtime.stopEngine(); }); test('Linux start rejects a matching endpoint unless its listener PID is the spawned child', async t => { const guardPath = path.join(os.tmpdir(), 'chimera-process-guard-test'); let running = false; const child = new EventEmitter(); child.pid = 4242; child.stdin = { end() { running = false; child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => true; const runtime = fixture(t, { fetch: async url => { if (!running || !String(url).endsWith('/api/version')) throw new Error('not listening'); return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; }, processPlatform: 'linux', processGuardPath: guardPath, verifyProcessGuard: () => ({ verified: true, path: guardPath }), spawn: () => { running = true; return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), inspectExistingEngine: async input => listenerIdentity(input, { pid: 5252 }), enginePortProbe: async () => running, }); await assert.rejects( () => runtime.startEngine(), error => error.code === 'PS5UPLOAD_ENGINE_START_FAILED' && error.details?.reason === 'spawned-listener-unproven' && error.details?.cleanup?.stopped === true, ); }); test('Linux spawned fallback revalidates and terminates through pidfd without numeric child kill', async t => { const guardPath = path.join(os.tmpdir(), 'chimera-process-guard-test'); let running = false; let childKills = 0; const terminations = []; const child = new EventEmitter(); child.pid = 4242; child.stdin = { end() {} }; child.stderr = new EventEmitter(); child.kill = () => { childKills += 1; return true; }; const runtime = fixture(t, { fetch: async url => { if (!running || !String(url).endsWith('/api/version')) throw new Error('not listening'); return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; }, processPlatform: 'linux', processGuardPath: guardPath, verifyProcessGuard: () => ({ verified: true, path: guardPath }), spawn: () => { running = true; return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), inspectExistingEngine: async input => listenerIdentity(input), terminateProvenProcess: async identity => { terminations.push(identity); running = false; return { terminated: true, identityGone: true, forced: false }; }, enginePortProbe: async () => running, }); await runtime.startEngine(); assert.deepEqual(await runtime.stopEngine(), { stopped: true, endpointReleased: true, identityGone: true, forced: false, }); assert.equal(terminations.length, 1); assert.equal(terminations[0].pid, 4242); assert.equal(childKills, 0); }); test('Linux spawned ownership can be re-attested after a transient read-only sample drift', async t => { const guardPath = path.join(os.tmpdir(), 'chimera-process-guard-test'); let running = false; let inspections = 0; const child = new EventEmitter(); child.pid = 4242; child.stdin = { end() { running = false; child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => true; const runtime = fixture(t, { fetch: async url => { if (!running || !String(url).endsWith('/api/version')) throw new Error('not listening'); return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; }, processPlatform: 'linux', processGuardPath: guardPath, verifyProcessGuard: () => ({ verified: true, path: guardPath }), spawn: () => { running = true; return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), inspectExistingEngine: async input => { inspections += 1; return listenerIdentity(input, { pid: inspections === 3 ? 5252 : 4242 }); }, enginePortProbe: async () => running, }); await runtime.startEngine(); assert.equal((await runtime.status()).engine.processOwned, false); const recovered = await runtime.status(); assert.equal(recovered.engine.processOwned, true); assert.equal(recovered.engine.processOwnership, 'spawned'); await runtime.stopEngine(); }); test('engine stop waits for the shared endpoint to be released before allowing a replacement runtime', async t => { let stopping = false; let started = false; let portProbes = 0; let waits = 0; const child = new EventEmitter(); child.stdin = { end() { stopping = true; child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => true; const runtime = fixture(t, { fetch: async url => { if (!String(url).endsWith('/api/version') || !stopping) throw new Error('not listening'); throw new Error('HTTP endpoint released'); }, spawn: () => { started = true; return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), enginePortProbe: async () => { if (!started) return false; portProbes += 1; return portProbes < 3; }, delay: async () => { waits += 1; }, }); await runtime.startEngine(); const stopped = await runtime.stopEngine(); assert.deepEqual(stopped, { stopped: true, endpointReleased: true, identityGone: true, forced: false }); assert.equal(portProbes, 3); assert.equal(waits, 2); }); test('not-owned stop reports success only after proving the shared endpoint is already released', async t => { const released = fixture(t, { fetch: async () => { throw new Error('endpoint unavailable'); }, enginePortProbe: async () => false, }); assert.deepEqual(await released.stopEngine(), { stopped: true, endpointReleased: true, identityGone: true, alreadyStopped: true, }); const occupied = fixture(t, { enginePortProbe: async () => true }); assert.deepEqual(await occupied.stopEngine(), { stopped: false, endpointReleased: false, identityGone: false, reason: 'not-owned', }); }); test('engine stop fails closed without signaling again when a replacement endpoint remains occupied', async t => { let kills = 0; let portProbes = 0; let started = false; const child = new EventEmitter(); child.stdin = { end() { child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => { kills += 1; return true; }; const runtime = fixture(t, { fetch: async () => { throw new Error('HTTP endpoint unavailable'); }, spawn: () => { started = true; return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), enginePortProbe: async () => { if (!started) return false; portProbes += 1; return true; }, delay: async () => {}, }); await runtime.startEngine(); const stopped = await runtime.stopEngine(); assert.deepEqual(stopped, { stopped: false, endpointReleased: false, identityGone: true, reason: 'engine-endpoint-still-active' }); assert.equal(portProbes, 20); assert.equal(kills, 0); }); test('failed spawned stop retains the child identity so a later safe retry can finish', async t => { let allowExit = false; const child = new EventEmitter(); child.stdin = { end() { if (allowExit) child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => { if (allowExit) child.emit('exit', 0, 'SIGTERM'); return true; }; const runtime = fixture(t, { fetch: async () => { throw new Error('endpoint unavailable'); }, spawn: () => child, waitForEngine: async () => ({ available: true, version: '5.4.19' }), enginePortProbe: async () => false, }); await runtime.startEngine(); assert.deepEqual(await runtime.stopEngine(), { stopped: false, endpointReleased: false, identityGone: false, reason: 'engine-process-still-active', }); allowExit = true; assert.deepEqual(await runtime.stopEngine(), { stopped: true, endpointReleased: true, identityGone: true, forced: false, }); }); test('failed engine readiness performs the same proven bounded cleanup', async t => { const child = new EventEmitter(); child.stdin = { end() { child.emit('exit', 0, null); } }; child.stderr = new EventEmitter(); child.kill = () => true; const runtime = fixture(t, { fetch: async () => { throw new Error('endpoint unavailable'); }, spawn: () => child, waitForEngine: async () => ({ available: false, version: '', reason: 'unreachable' }), enginePortProbe: async () => false, }); await assert.rejects( () => runtime.startEngine(), error => error.code === 'PS5UPLOAD_ENGINE_START_FAILED' && error.details?.cleanup?.stopped === true && error.details.cleanup.endpointReleased === true && error.details.cleanup.identityGone === true, ); }); test('Linux failed readiness re-attests the spawned listener before proven pidfd cleanup', async t => { const guardPath = path.join(os.tmpdir(), 'chimera-process-guard-test'); let running = false; let childKills = 0; const terminations = []; const child = new EventEmitter(); child.pid = 4242; child.stdin = { end() {} }; child.stderr = new EventEmitter(); child.kill = () => { childKills += 1; return true; }; const runtime = fixture(t, { fetch: async url => { if (!running || !String(url).endsWith('/api/version')) throw new Error('not listening'); return { ok: true, status: 200, json: async () => ({ version: 'wrong-profile' }) }; }, processPlatform: 'linux', processGuardPath: guardPath, verifyProcessGuard: () => ({ verified: true, path: guardPath }), spawn: () => { running = true; return child; }, waitForEngine: async () => ({ available: false, version: 'wrong-profile', reason: 'runtime-profile-mismatch' }), inspectExistingEngine: async input => listenerIdentity(input), inspectSpawnedProcess: async input => processIdentity(input), terminateProvenProcess: async identity => { terminations.push(identity); running = false; return { terminated: true, identityGone: true, forced: false }; }, enginePortProbe: async () => running, }); await assert.rejects( () => runtime.startEngine(), error => error.code === 'PS5UPLOAD_ENGINE_START_FAILED' && error.details?.cleanup?.stopped === true && error.details.cleanup.endpointReleased === true && error.details.cleanup.identityGone === true, ); assert.equal(terminations.length, 1); assert.equal(terminations[0].pid, 4242); assert.equal(childKills, 0); }); test('Linux failed readiness terminates an exact spawned PID that never opens a listener', async t => { const guardPath = path.join(os.tmpdir(), 'chimera-process-guard-test'); let childKills = 0; const terminations = []; const child = new EventEmitter(); child.pid = 4242; child.stdin = { end() {} }; child.stderr = new EventEmitter(); child.kill = () => { childKills += 1; return true; }; const runtime = fixture(t, { fetch: async () => { throw new Error('listener never opened'); }, processPlatform: 'linux', processGuardPath: guardPath, verifyProcessGuard: () => ({ verified: true, path: guardPath }), spawn: () => child, waitForEngine: async () => ({ available: false, version: '', reason: 'unreachable' }), inspectExistingEngine: async () => ({ verified: false, reason: 'listener-not-found' }), inspectSpawnedProcess: async input => processIdentity(input), terminateProvenProcess: async identity => { terminations.push(identity); return { terminated: true, identityGone: true, forced: false }; }, enginePortProbe: async () => false, }); await assert.rejects( () => runtime.startEngine(), error => error.code === 'PS5UPLOAD_ENGINE_START_FAILED' && error.details?.cleanup?.stopped === true && error.details.cleanup.endpointReleased === true && error.details.cleanup.identityGone === true, ); assert.equal(terminations.length, 1); assert.equal(terminations[0].pid, 4242); assert.equal(terminations[0].evidence, LINUX_PROCESS_EVIDENCE); assert.equal(childKills, 0); }); test('payload start sends only the pinned ELF and reports management readiness without user data', async t => { const sends = []; const inspections = []; let spawnCalls = 0; const runtime = fixture(t, { inspectExistingEngine: async input => { inspections.push(input); return listenerIdentity(input); }, spawn: () => { spawnCalls += 1; throw new Error('must adopt before payload start'); }, tcpSend: async input => { sends.push(input); return { ok: true, bytes: input.bytes.length }; }, }); const result = await runtime.startPayload(); const status = await runtime.status(); assert.equal(sends.length, 1); assert.equal(spawnCalls, 0); assert.equal(inspections.length >= 4, true); assert.equal(inspections.every(input => input.host === '127.0.0.1' && input.port === 19113), true); assert.equal(status.engine.processOwned, true); assert.equal(status.engine.processOwnership, 'adopted'); assert.equal(sends[0].host, '192.0.2.55'); assert.equal(sends[0].port, 9021); assert.equal(sends[0].bytes.toString(), 'elf-5.4.19'); assert.deepEqual(result, { sent: true, bytes: 10, managementReady: true, managementPort: 9114 }); }); test('payload start ignores a stale ready daemon until the new management instance is observable', async t => { let sent = false; let postSendStatusReads = 0; const runtime = fixture(t, { fetch: async url => { const href = String(url); if (href.endsWith('/api/version')) return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; if (href.includes('/api/ps5/status')) { if (sent) postSendStatusReads += 1; const transitioned = sent && postSendStatusReads >= 3; return { ok: true, status: 200, json: async () => ({ version: '5.4.19', instance_id: transitioned ? '2' : '1', started_at_unix: transitioned ? 2 : 1 }) }; } return { ok: true, status: 200, json: async () => ({ ok: true, users: [] }) }; }, tcpSend: async input => { sent = true; return { ok: true, bytes: input.bytes.length }; }, }); const result = await runtime.startPayload(); assert.equal(result.managementReady, true); assert.equal(postSendStatusReads, 3); const identity = await runtime.runtimeIdentity(); assert.equal(identity.status, 'unproven'); assert.equal(identity.payload.evidence, 'loader-input-hash-and-instance-transition'); }); test('payload start does not attest or report readiness when the old instance never transitions', async t => { let statusReads = 0; const runtime = fixture(t, { fetch: async url => { const href = String(url); if (href.endsWith('/api/version')) return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; if (href.includes('/api/ps5/status')) { statusReads += 1; return { ok: true, status: 200, json: async () => ({ version: '5.4.19', instance_id: '1', started_at_unix: 1 }) }; } return { ok: true, status: 200, json: async () => ({ ok: true, users: [] }) }; }, }); const result = await runtime.startPayload(); assert.equal(result.managementReady, false); assert.equal(statusReads, 13); assert.equal((await runtime.runtimeIdentity()).status, 'unproven'); }); test('DPI fallback sends only the pinned standalone daemon and waits for port 9040', async t => { const probes = []; const sends = []; const runtime = fixture(t, { tcpProbe: async input => { probes.push(input); return input.port === 9021 || probes.filter(item => item.port === 9040).length > 1; }, tcpSend: async input => { sends.push(input); return { ok: true, bytes: input.bytes.length }; }, }); const result = await runtime.ensureDpi(); assert.equal(result.ready, true); assert.equal(result.port, 9040); assert.equal(result.alreadyRunning, false); assert.equal(sends.length, 1); assert.equal(sends[0].port, 9021); assert.equal(sends[0].bytes.toString(), 'dpi-5.4.19'); assert.equal(probes.some(item => item.port === 9040), true); }); test('missing console host blocks engine and payload setup', async t => { const runtime = fixture(t, { consoleHost: () => '' }); await assert.rejects(() => runtime.startEngine(), error => error.code === 'PS5UPLOAD_CONSOLE_HOST'); const result = await runtime.preflight(); assert.equal(result.ready, false); assert.equal(result.console.reason, 'host-missing'); }); test('A5 runtime identity stays unproven until Chimera owns the exact engine and payload transition', async t => { const child = new EventEmitter(); child.stdin = { end() {} }; child.stderr = new EventEmitter(); child.kill = () => true; let engineReady = false; let payloadLoaded = false; const runtime = fixture(t, { fetch: async url => { const href = String(url); if (href.endsWith('/api/version')) { if (!engineReady) throw new Error('not listening'); return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; } if (href.includes('/api/ps5/status')) { return { ok: true, status: 200, json: async () => ({ version: '5.4.19', instance_id: payloadLoaded ? '2' : '1', started_at_unix: payloadLoaded ? 2 : 1 }) }; } return { ok: true, status: 200, json: async () => ({ ok: true, users: [] }) }; }, spawn: () => { engineReady = true; return child; }, waitForEngine: async () => ({ available: true, version: '5.4.19' }), tcpProbe: async input => input.port !== 9040, tcpSend: async input => { payloadLoaded = true; return { ok: true, bytes: input.bytes.length }; }, }); assert.equal((await runtime.runtimeIdentity()).status, 'unproven'); await runtime.startEngine(); assert.equal((await runtime.runtimeIdentity()).status, 'unproven'); await runtime.startPayload(); const exact = await runtime.runtimeIdentity(); assert.equal(exact.status, 'exact'); assert.equal(exact.mutationAllowed, true); assert.equal(exact.engine.evidence, 'chimera-owned-process-artifact'); assert.equal(exact.payload.evidence, 'loader-input-hash-and-instance-transition'); }); test('an exact same-namespace listener can be re-attested after a server restart', async t => { let spawnCalls = 0; const runtime = fixture(t, { spawn: () => { spawnCalls += 1; throw new Error('must not spawn over an exact existing listener'); }, tcpProbe: async input => input.port !== 9040, inspectExistingEngine: async input => listenerIdentity(input), }); const adopted = await runtime.startEngine(); assert.equal(adopted.available, true); assert.equal(adopted.processOwned, true); assert.equal(adopted.adopted, true); assert.equal(spawnCalls, 0); const beforePayload = await runtime.runtimeIdentity(); assert.equal(beforePayload.status, 'unproven'); assert.equal(beforePayload.engine.evidence, LINUX_LISTENER_PROCESS_EVIDENCE); await runtime.startPayload(); const exact = await runtime.runtimeIdentity(); assert.equal(exact.status, 'exact'); assert.equal(exact.mutationAllowed, true); assert.equal(exact.engine.evidence, LINUX_LISTENER_PROCESS_EVIDENCE); }); test('an existing endpoint is never adopted without exact local process provenance', async t => { let spawnCalls = 0; const runtime = fixture(t, { spawn: () => { spawnCalls += 1; throw new Error('must not spawn over an unowned endpoint'); }, inspectExistingEngine: async () => ({ verified: false, reason: 'listener-owner-not-found' }), }); await assert.rejects( () => runtime.startEngine(), error => error.code === 'PS5UPLOAD_ENGINE_UNOWNED' && error.details?.reason === 'listener-owner-not-found', ); assert.equal(spawnCalls, 0); assert.equal((await runtime.runtimeIdentity()).status, 'unproven'); }); test('a reachable wrong-lane profile is never inspected, signaled or spawned over', async t => { let inspections = 0; let spawnCalls = 0; let terminations = 0; const runtime = fixture(t, { fetch: async url => { if (String(url).endsWith('/api/version')) { return { ok: true, status: 200, json: async () => ({ version: '5.4.19', diagnostic_identity: 'chimera-p15-shellui-observe-v1' }), }; } throw new Error('unexpected request'); }, inspectExistingEngine: async input => { inspections += 1; return listenerIdentity(input); }, spawn: () => { spawnCalls += 1; throw new Error('must not spawn over wrong lane'); }, terminateProvenProcess: async () => { terminations += 1; return { terminated: true, identityGone: true }; }, }); await assert.rejects( () => runtime.startEngine(), error => error.code === 'PS5UPLOAD_ENGINE_UNOWNED' && error.details?.reason === 'runtime-profile-mismatch', ); assert.equal(inspections, 0); assert.equal(spawnCalls, 0); assert.equal(terminations, 0); }); test('an adopted engine is revalidated before a bounded graceful stop', async t => { let terminated = false; const terminations = []; const runtime = fixture(t, { fetch: async url => { const href = String(url); if (href.endsWith('/api/version')) { if (terminated) throw new Error('released'); return { ok: true, status: 200, json: async () => ({ version: '5.4.19' }) }; } if (href.includes('/api/ps5/status')) return { ok: true, status: 200, json: async () => ({ version: '5.4.19', instance_id: '1', started_at_unix: 1 }) }; return { ok: true, status: 200, json: async () => ({ ok: true, users: [] }) }; }, inspectExistingEngine: async input => listenerIdentity(input), terminateProvenProcess: async identity => { terminations.push(identity); terminated = true; return { terminated: true, identityGone: true, forced: false }; }, enginePortProbe: async () => !terminated, }); await runtime.startEngine(); const stopped = await runtime.stopEngine(); assert.deepEqual(stopped, { stopped: true, endpointReleased: true, identityGone: true, forced: false, adopted: true }); assert.equal(terminations.length, 1); assert.equal(terminations[0].pid, 4242); }); test('adopted process identity drift fails closed without signaling any process', async t => { let inspections = 0; const terminations = []; const runtime = fixture(t, { inspectExistingEngine: async input => { inspections += 1; return listenerIdentity(input, { pid: inspections <= 2 ? 4242 : 5252 }); }, terminateProvenProcess: async identity => { terminations.push(identity); return { terminated: true, identityGone: true }; }, }); await runtime.startEngine(); const stopped = await runtime.stopEngine(); assert.deepEqual(stopped, { stopped: false, endpointReleased: false, identityGone: false, reason: 'adopted-process-identity-drift' }); assert.deepEqual(terminations, []); }); test('status clears adopted ownership and attestation immediately on identity drift', async t => { let inspections = 0; const runtime = fixture(t, { inspectExistingEngine: async input => { inspections += 1; return listenerIdentity(input, { startTimeTicks: inspections <= 2 ? '123456' : '654321' }); }, }); await runtime.startEngine(); const status = await runtime.status(); assert.equal(status.engine.available, true); assert.equal(status.engine.processOwned, false); assert.equal(status.engine.processOwnership, null); const identity = await runtime.runtimeIdentity(); assert.equal(identity.status, 'unproven'); assert.equal(identity.mutationAllowed, false); }); test('adopted helper failure remains fail-closed and keeps ownership available for retry', async t => { let terminations = 0; const runtime = fixture(t, { terminateProvenProcess: async () => { terminations += 1; return { terminated: false, identityGone: false, reason: 'pidfd-exit-timeout' }; }, }); await runtime.startEngine(); const stopped = await runtime.stopEngine(); assert.deepEqual(stopped, { stopped: false, endpointReleased: false, identityGone: false, reason: 'pidfd-exit-timeout', }); assert.equal(terminations, 1); assert.equal((await runtime.status()).engine.processOwned, true); });