'use strict'; const test = require('node:test'); const assert = require('node:assert/strict'); const crypto = require('crypto'); const fs = require('fs'); const os = require('os'); const path = require('path'); const { SettingsStore } = require('../../src/persistence/settings-store'); const { createEcosystemIntelligenceService, repoSlug, sameVersion, compareVersionish, versionFromFilename, componentForPayload } = require('../../src/services/ecosystem-intelligence-service'); function fixture({ withWebhook = false, payloadManager = null } = {}) { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-ecosystem-intelligence-')); const paths = Object.fromEntries(['backups', 'cache', 'tmp'].map(name => [name, path.join(root, name)])); for (const directory of Object.values(paths)) fs.mkdirSync(directory, { recursive: true }); const settings = new SettingsStore(path.join(root, 'config', 'settings.json')); settings.set('ftp.host', '127.0.0.1'); settings.set('ecosystem.componentVersions', { elfldr: 'v1.0.0', websrv: 'v1.0.0' }); const secretValues = new Map(withWebhook ? [['discord.webhookUrl', 'https://discord.com/api/webhooks/1/test']] : []); const secrets = { has: name => secretValues.has(name), get: name => secretValues.get(name) || '', }; const components = [ { id: 'elfldr', name: 'ELF Loader', kind: 'daemon', platform: 'ps5', repo: 'ps5-payload-dev/elfldr', trust: 'official', risk: 'normal', dependencies: [], release: { tag: 'v1.0.0' }, compatibility: { status: 'compatible', reason: 'Testprofiel.' } }, { id: 'websrv', name: 'PS5 websrv', kind: 'daemon', platform: 'ps5', repo: 'ps5-payload-dev/websrv', trust: 'official', risk: 'normal', dependencies: ['elfldr'], release: { tag: 'v2.0.0' }, compatibility: { status: 'compatible', reason: 'Testprofiel.' } }, ]; const catalog = { sources: [ { id: 1, name: 'ELF Loader', github_url: 'https://github.com/ps5-payload-dev/elfldr', latest_tag: 'v1.0.0', category: 'loader', description: 'ELF loader', enabled: 1 }, { id: 2, name: 'Web Server', github_url: 'https://github.com/ps5-payload-dev/websrv', latest_tag: 'v2.0.0', category: 'network', description: 'PS5 web server', enabled: 1 }, ], files: [ { id: 10, source_id: 1, asset_name: 'elfldr.elf', asset_url: 'https://github.com/ps5-payload-dev/elfldr/releases/download/v1/elfldr.elf', asset_size: 100, version: 'v1.0.0', remote_hash: 'a'.repeat(64), local_path: null }, { id: 20, source_id: 2, asset_name: 'websrv.elf', asset_url: 'https://github.com/ps5-payload-dev/websrv/releases/download/v2/websrv.elf', asset_size: 200, version: 'v2.0.0', remote_hash: 'b'.repeat(64), local_path: null }, ], stats: { updates: 1 }, }; const downloads = []; let refreshes = 0; let syncs = 0; const base = { listComponents: () => ({ checkedAt: Date.now(), components }), refreshComponents: async () => { refreshes += 1; return { checkedAt: Date.now(), components }; }, serviceStatus: async () => ({ host: '127.0.0.1', services: [{ port: 9021, label: 'ELF loader', reachable: true }, { port: 8080, label: 'websrv', reachable: true }] }), listPlugins: () => ({ items: [] }), cheatIndex: () => ({ syncedAt: Date.now(), items: [], total: 0 }), listSaveVault: () => [], }; const db = { getPayloadCatalog: () => catalog, listGames: () => [{ game_id: 'PPSA00001', title: 'PPSA00001', prospero_name: null, prospero_icon_url: null }], listBackups: () => [], }; const payloadCatalog = { sync: async () => { syncs += 1; return []; }, download: async input => { downloads.push(input); catalog.files.find(file => file.source_id === input.source_id && file.asset_name === input.asset_name).local_path = path.join(root, input.asset_name); return { localPath: path.join(root, input.asset_name), local_hash: 'b'.repeat(64), verified: true }; }, }; const service = createEcosystemIntelligenceService({ base, db, ftp: {}, settings, secrets, paths, payloadCatalog, payloadManager, capabilities: { features: { https: { configured: true } } }, logger: { info() {}, warn() {}, error() {} }, }); return { root, paths, settings, service, components, catalog, downloads, counts: () => ({ refreshes, syncs }) }; } test('repository and version normalization only accepts GitHub repositories', () => { assert.equal(repoSlug('https://github.com/etaHEN/etaHEN/releases/latest'), 'etahen/etahen'); assert.equal(repoSlug('https://github.com/etaHEN/etaHEN.git'), 'etahen/etahen'); assert.equal(repoSlug('https://example.test/etaHEN/etaHEN'), ''); assert.equal(sameVersion('Release-v2.5B', '2.5b'), true); assert.equal(sameVersion('1.0', '1.0.1'), false); assert.equal(compareVersionish('2.6B', '2.5B'), 1); assert.equal(compareVersionish('v0.23', '0.23'), 0); assert.equal(compareVersionish('1.6beta16', '1.6beta17'), -1); assert.equal(compareVersionish('1.0.0-beta1', '1.0.0'), null); assert.equal(versionFromFilename('websrv_v0.33.elf'), '0.33'); assert.equal(componentForPayload('SystemStateManager.elf'), 'system-state'); }); test('health is unscored until a PS5 profile is configured', async () => { const f = fixture(); try { f.settings.set('ftp.host', ''); const report = await f.service.runHealth({ persist: true, notify: true }); assert.equal(report.hostConfigured, false); assert.equal(report.score, null); assert.equal(report.grade, 'not-configured'); assert.equal(report.notification.reason, 'not-configured'); assert.equal(report.alerts.find(item => item.id === 'ps5-host').severity, 'info'); assert.equal(f.service.healthHistory()[0].score, null); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('update planner detects newer console payloads and blocks downgrades', () => { const f = fixture(); try { f.settings.set('ecosystem.componentVersions', { ...f.settings.get('ecosystem.componentVersions', {}), etahen: '2.6B' }); f.components.push({ id: 'etahen', name: 'etaHEN', kind: 'hen', platform: 'ps5', repo: 'etaHEN/etaHEN', trust: 'official', risk: 'normal', dependencies: [], release: { tag: '2.5B' }, compatibility: { status: 'compatible', reason: 'Testprofiel.' } }); f.catalog.sources.push({ id: 3, name: 'etaHEN', github_url: 'https://github.com/etaHEN/etaHEN', latest_tag: '2.5B', category: 'homebrew', enabled: 1 }); f.catalog.files.push({ id: 30, source_id: 3, asset_name: 'etaHEN-2.5B.bin', asset_url: 'https://github.com/etaHEN/etaHEN/releases/download/2.5B/etaHEN-2.5B.bin', version: '2.5B', remote_hash: 'c'.repeat(64) }); const inventory = f.service.componentInventory(); assert.equal(inventory.stats.ahead, 1); assert.equal(inventory.components.find(item => item.id === 'etahen').state, 'ahead'); const plan = f.service.updatePlan({ selected: ['etahen'] }); assert.equal(plan.steps[0].stageable, false); assert.match(plan.steps[0].blockers.join(' '), /downgrade/); assert.throws(() => f.service.selectUpdateAsset({ componentId: 'etahen' }), /downgrade/); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('Payload Manager inventory automatically supplies installed component versions', async () => { const payloadManager = { probe: async () => ({ version: '0.3.1', autoload: { list: 'SystemStateManager.elf' }, inventory: { payloads: [{ filename: 'SystemStateManager.elf', path: '/data/pldmgr/payloads/SystemStateManager/SystemStateManager.elf', version: '1.0', checksumVerified: true }] }, sources: { items: [{ id: 'default', name: 'Official Repository', url: 'https://example.test/payloads.json' }] }, repository: { total: 20 }, }), }; const f = fixture({ payloadManager }); try { f.components.push({ id: 'system-state', name: 'System State Manager', kind: 'daemon', platform: 'ps5', repo: 'StonedModder/PS5-SystemStateManager', trust: 'official', risk: 'advanced', dependencies: ['elfldr'], release: { tag: 'v1.0' }, compatibility: { status: 'compatible', reason: 'Testprofiel.' } }); const snapshot = await f.service.refreshConsolePayloads(); assert.equal(snapshot.online, true); assert.equal(snapshot.payloads[0].componentId, 'system-state'); const component = f.service.componentInventory().components.find(item => item.id === 'system-state'); assert.equal(component.installedVersion, '1.0'); assert.equal(component.installedSource, 'payload-manager'); assert.equal(component.state, 'current'); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('runtime evidence beats manual fallback and clears stale masking', async () => { const payloadManager = { probe: async () => ({ version: '0.4.0', autoload: { list: 'websrv.elf' }, inventory: { payloads: [{ filename: 'websrv.elf', path: '/data/pldmgr/payloads/PS5-Plugins/websrv/websrv.elf', version: '2.0.0', checksumVerified: true }] }, sources: { items: [{ id: 'default', name: 'Official Repository', url: 'https://example.test/payloads.json' }] }, repository: { total: 20 }, }), }; const f = fixture({ payloadManager }); try { f.settings.set('ecosystem.componentVersions', { websrv: '1.0.0' }); await f.service.refreshConsolePayloads(); const component = f.service.componentInventory().components.find(item => item.id === 'websrv'); assert.equal(component.installedVersion, '2.0.0'); assert.equal(component.installedSource, 'payload-manager'); assert.equal(component.installedSourceConfidence, 'high'); assert.equal(component.installedVersionConflicts.length, 0); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('manual override is explicitly stored with manual source and used as fallback', () => { const f = fixture(); try { const updated = f.service.setComponentVersion({ id: 'websrv', version: '2.0.0' }); const component = updated.components.find(item => item.id === 'websrv'); assert.equal(component.installedSource, 'manual'); assert.equal(component.installedSourceConfidence, 'manual'); assert.equal(component.installedVersion, '2.0.0'); assert.ok(Number.isFinite(component.installedSourceSeenAt) && component.installedSourceSeenAt > 0); const stored = f.settings.get('ecosystem.componentVersions', {}); assert.equal(stored.websrv.version, '2.0.0'); assert.equal(stored.websrv.source, 'manual'); assert.equal(stored.websrv.confidence, 'manual'); assert.equal(stored.websrv.mode, 'override'); assert.ok(Number.isFinite(stored.websrv.seenAt) && stored.websrv.seenAt > 0); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('explicit manual override exposes conflicts and follow automatic restores runtime priority', async () => { const payloadManager = { probe: async () => ({ version: '0.4.0', autoload: { list: 'websrv.elf' }, inventory: { payloads: [{ filename: 'websrv.elf', path: '/data/pldmgr/payloads/websrv.elf', version: '2.0.0', checksumVerified: true }] }, sources: { items: [] }, repository: { total: 1 }, }) }; const f = fixture({ payloadManager }); try { await f.service.refreshConsolePayloads(); f.service.setComponentVersion({ id: 'websrv', version: '1.5.0' }); let component = f.service.componentInventory().components.find(item => item.id === 'websrv'); assert.equal(component.installedVersion, '1.5.0'); assert.equal(component.trackingMode, 'manual-override'); assert.equal(component.evidenceState, 'conflict'); assert.ok(component.installedVersionConflicts.some(item => item.version === '2.0.0')); f.service.followAutomatic({ id: 'websrv' }); component = f.service.componentInventory().components.find(item => item.id === 'websrv'); assert.equal(component.installedVersion, '2.0.0'); assert.equal(component.installedSource, 'payload-manager'); assert.equal(component.trackingMode, 'automatic'); assert.equal(component.manualEvidence, null); assert.equal(f.settings.get('ecosystem.componentVersions', {}).websrv, undefined); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('conflict and unknown evidence states are visible', () => { const f = fixture(); try { const websrvAsset = f.catalog.files.find(file => file.id === 20); websrvAsset.local_path = path.join(f.root, 'websrv-local.elf'); websrvAsset.version = '1.0.0'; websrvAsset.asset_name = 'websrv_v1.1.elf'; fs.writeFileSync(websrvAsset.local_path, Buffer.from('websrv-payload')); const component = f.service.componentInventory().components.find(entry => entry.id === 'websrv'); assert.equal(component.installedVersion, '1.0.0'); assert.equal(component.installedSource, 'file-hash'); assert.ok(component.installedVersionConflicts.length >= 1); f.components.push({ id: 'ghost', name: 'Ghost payload', kind: 'daemon', platform: 'ps5', repo: 'invalid/ghost', trust: 'official', risk: 'normal', dependencies: [], release: {}, compatibility: { status: 'compatible', reason: 'Testprofiel.' } }); const ghost = f.service.componentInventory().components.find(entry => entry.id === 'ghost'); assert.equal(ghost.installedSource, null); assert.equal(ghost.state, 'not-tracked'); assert.equal(ghost.installedVersion, ''); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('update planner orders dependencies and never declares automatic execution', async () => { const f = fixture(); try { const inventory = f.service.componentInventory(); assert.equal(inventory.stats.updates, 1); assert.equal(inventory.components.find(item => item.id === 'websrv').state, 'update-available'); const plan = f.service.updatePlan(); assert.deepEqual(plan.steps.map(step => step.component.id), ['elfldr', 'websrv']); assert.equal(plan.steps[0].dependencyOnly, true); assert.equal(plan.steps[1].stageable, true); assert.equal(plan.safety.autoExecute, false); const refreshed = await f.service.refreshUpdates(); assert.equal(refreshed.safety.autoExecute, false); assert.deepEqual(f.counts(), { refreshes: 1, syncs: 1 }); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('preparing an update only stages the selected catalog asset and records it', async () => { const f = fixture(); try { const result = await f.service.prepareUpdate({ componentId: 'websrv', assetName: 'websrv.elf' }); assert.equal(result.ok, true); assert.equal(result.file.name, 'websrv.elf'); assert.equal(result.file.verified, true); assert.deepEqual(f.downloads, [{ source_id: 2, asset_name: 'websrv.elf' }]); assert.match(result.nextStep, /bewust/); assert.equal(f.service.activityHistory()[0].type, 'updates'); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('Payload Manager repository exports only public upstream metadata and checksums', () => { const f = fixture(); try { const repository = f.service.payloadManagerRepository(); assert.equal(repository.name, 'Chimera Verified Payloads'); assert.equal(repository.payloads.length, 2); assert.deepEqual(Object.keys(repository), ['name', 'payloads']); const websrv = repository.payloads.find(item => item.filename === 'websrv.elf'); assert.equal(websrv.version, 'v2.0.0'); assert.equal(websrv.category, 'network'); assert.equal(websrv.checksum, 'b'.repeat(64)); assert.equal(Object.prototype.hasOwnProperty.call(websrv, 'localPath'), false); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('Payload Supply-Chain Vault rehashes staged assets and blocks mismatches', async () => { const f = fixture(); try { const vault = path.join(f.root, 'payloads'); fs.mkdirSync(vault, { recursive: true }); f.settings.set('payload.localPath', vault); const content = Buffer.from('trusted payload bytes'); const localPath = path.join(vault, 'websrv.elf'); fs.writeFileSync(localPath, content); const asset = f.catalog.files.find(file => file.asset_name === 'websrv.elf'); const source = f.catalog.sources.find(item => item.id === asset.source_id); source.trust = 'official'; asset.local_path = localPath; asset.local_hash = crypto.createHash('sha256').update(content).digest('hex'); asset.remote_hash = asset.local_hash; let report = await f.service.supplyChainAudit(); assert.equal(report.stats.verified, 1); assert.equal(report.stats.blocked, 0); fs.appendFileSync(localPath, 'tamper'); report = await f.service.supplyChainAudit(); assert.equal(report.stats.verified, 0); assert.equal(report.stats.blocked, 1); assert.match(report.assets.find(item => item.name === 'websrv.elf').issues.join(' '), /wijkt af/); assert.equal(report.policy.automaticExecution, false); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('console health persists actionable alerts, history and acknowledgements', async () => { const f = fixture(); try { const report = await f.service.runHealth({ persist: true, notify: false }); assert.ok(report.score < 100); assert.ok(report.alerts.some(alert => alert.id === 'game-metadata')); assert.ok(report.alerts.some(alert => alert.id === 'backup-coverage' && alert.severity === 'critical')); assert.equal(f.service.healthHistory().length, 1); const acknowledged = f.service.acknowledgeAlert({ id: 'game-metadata' }); assert.equal(acknowledged.alerts.find(alert => alert.id === 'game-metadata').acknowledged, true); assert.equal(f.service.latestHealth().alerts.find(alert => alert.id === 'game-metadata').acknowledged, true); assert.ok(f.service.activityHistory().some(item => item.type === 'health')); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } }); test('health notifications cannot be enabled without an encrypted webhook', () => { const f = fixture(); try { assert.throws(() => f.service.setHealthOptions({ notificationsEnabled: true }), /Discord-webhook/); assert.equal(f.service.setHealthOptions({ notificationsEnabled: false }).notificationsEnabled, false); } finally { fs.rmSync(f.root, { recursive: true, force: true }); } });