'use strict'; // Proba consolei (B1 m3): un buraf bun -> verdict OK; si controale NEGATIVE care arata ca CONSOLA NU SE INCREDE in buraf: // (1) buraf care declara chainOk:true peste un jurnal manipulat -> consola prinde minciuna (lant RUPT + autoRaportSuspect); // (2) buraf cu lant INTERN COERENT (hash-uri refacute) dar cu un plic al carui statementHash minte -> consola prinde plicul. // plus: planul de migrare se pliaza in stare. // node proba-consola.mjs -> 0 toate cum trebuia, 1 altfel import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import crypto from 'node:crypto'; import { execFileSync } from 'node:child_process'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { evalueaza, caleaSidecarului } from './consola.mjs'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const RAD = path.resolve(AICI, '..', '..'); const SIDE = caleaSidecarului(); const T = fs.mkdtempSync(path.join(os.tmpdir(), 'cons-')); let rele = 0; const cer = (n, c) => { console.log(` [${c ? 'OK ' : 'RAU '}] ${n}`); if (!c) rele++; }; const side = (args) => { try { execFileSync(process.execPath, [SIDE, ...args], { encoding: 'utf8' }); return 0; } catch (e) { return e.status ?? 1; } }; try { const { hashIntrare } = await import(pathToFileURL(SIDE).href); const log = path.join(T, 'audit.log'); const bin = path.join(T, 'node'); fs.writeFileSync(bin, 'BIN'); const sh = '0x' + crypto.createHash('sha256').update(fs.readFileSync(bin)).digest('hex'); side(['record', '--kind', 'runtime', '--artifact', bin, '--attested', sh, '--host', 'h1', '--log', log, '--at', '2026-09-26T09:00:00Z']); side(['record', '--kind', 'deployment', '--name', 'app', '--version', '1.0', '--content-file', bin, '--log', log, '--at', '2026-09-26T09:01:00Z']); const bf = path.join(T, 'b.json'); side(['bundle', '--log', log, '--out', bf, '--host', 'h1', '--at', '2026-09-26T09:02:00Z']); const bundle = JSON.parse(fs.readFileSync(bf, 'utf8')); const okSt = await evalueaza({ bundle }); cer('buraf bun -> verdict OK', okSt.verdict === 'OK' && okSt.auditChain.ok && okSt.envelopes.intact === okSt.envelopes.total); // CONTROL 1: minciuna auto-raportata + jurnal manipulat (hash stale) const b1 = JSON.parse(JSON.stringify(bundle)); b1.entries[0].proof.statement.host = 'ATACATOR'; b1.chainOk = true; const st1 = await evalueaza({ bundle: b1 }); cer('CONTROL 1: chainOk:true peste jurnal manipulat -> STRICAT (lant rupt)', st1.verdict === 'BROKEN' && st1.auditChain.ok === false); cer('CONTROL 1: consola marcheaza minciuna auto-raportata', !!st1.selfReportSuspect); // CONTROL 2: lant INTERN COERENT (hash-uri refacute) dar plic cu statementHash mincinos const b2 = JSON.parse(JSON.stringify(bundle)); b2.entries[0].proof.statement.host = 'ATACATOR'; // statementHash ramane cel vechi -> minte // refac lantul ca sa fie intern coerent (asa cum ar face un host rau destept) let prev = '0x' + '00'.repeat(32); for (const e of b2.entries) { e.prev = prev; e.hash = hashIntrare(e.seq, e.prev, e.proof); prev = e.hash; } b2.chainOk = true; b2.head = prev; const st2 = await evalueaza({ bundle: b2 }); cer('CONTROL 2: lant coerent dar plic mincinos -> lantul trece, PLICUL cade', st2.auditChain.ok === true && st2.envelopes.bad.length === 1 && st2.verdict === 'BROKEN'); // planul de migrare se pliaza. 2026-09-27: planul vine din PLANIFICATORUL real, nu dintr-o fixtura scrisa de mana; fixtura veche // (`items`/`mod`) era chiar forma presupusa de consola, deci proba masura presupunerea, iar pe un plan real consola afisa 0 actiuni. const { planeaza } = await import(pathToFileURL(path.join(AICI, 'plan-migrare.mjs')).href); const inv = [ { assetType: 'algorithm', name: 'ECDH', primitive: 'key-agree', quantumVulnerable: true, ref: 'a:1' }, { assetType: 'algorithm', name: 'RSA-2048', primitive: 'signature', quantumVulnerable: true, ref: 'a:2' }, { assetType: 'algorithm', name: 'ML-KEM-768', primitive: 'kem', quantumVulnerable: false, ref: 'a:3' }, ]; const plan = planeaza({ inventory: inv, scan: { domain: 'exemplu.test', findings: [{ id: 'hndl-exposed', severity: 'high', title: 'No post-quantum key exchange' }] } }); const nAuto = plan.actions.filter((a) => a.method === 'auto-aere').length; const nCrit = plan.actions.filter((a) => a.urgency === 'CRITICAL').length; const st3 = await evalueaza({ bundle, plan }); cer(`planul REAL al planificatorului se pliaza in stare (${plan.actions.length} actiuni, ${nCrit} critice, ${nAuto} auto)`, st3.migration && st3.migration.total === plan.actions.length && plan.actions.length > 0 && st3.migration.auto === nAuto && st3.migration.critical === nCrit && nAuto > 0 && nCrit > 0); // CONTROL 3: un plan fara nicio lista recunoscuta nu e "plan gol cu 0 actiuni": consola o spune si verdictul e STRICAT const st4 = await evalueaza({ bundle, plan: { ceva: [1, 2] } }); cer('CONTROL 3: plan fara lista recunoscuta -> nu "0 actiuni", ci eroare numita si STRICAT', st4.migration && st4.migration.total === null && st4.verdict === 'BROKEN'); // executia migrarii: consola re-verifica lantul executie.json al executorului (aici in mod USCAT, fara produse) const { executa } = await import(pathToFileURL(path.join(AICI, 'executa-migrare.mjs')).href); const outX = path.join(T, 'exec'); const x = await executa(plan, { consent: 'all', execute: false, out: outX }); const execution = JSON.parse(fs.readFileSync(x.file, 'utf8')); const st5 = await evalueaza({ bundle, plan, execution }); cer(`executia (uscata) se pliaza: lant intreg, ${st5.execution && st5.execution.actions} actiuni`, st5.execution && st5.execution.chainOk && st5.execution.actions === nAuto && st5.verdict === 'OK'); // CONTROL 4: o inregistrare de executie schimbata -> consola o prinde si verdictul e STRICAT const ex2 = JSON.parse(JSON.stringify(execution)); ex2.records[1].record.verdict = 'OK-fals'; const st6 = await evalueaza({ bundle, plan, execution: ex2 }); cer('CONTROL 4: inregistrare de executie schimbata -> lant RUPT, STRICAT', st6.execution && !st6.execution.chainOk && st6.execution.brokenAtSeq === 1 && st6.verdict === 'BROKEN'); } finally { fs.rmSync(T, { recursive: true, force: true }); } const total = 8; console.log(`\nB1 m3 consola: ${total - rele}/${total} cum trebuia (buraf bun + 4 controale negative + plan real + executie)`); process.exitCode = rele ? 1 : 0;