'use strict'; // Proba CLI-ului Control Plane cap la cap (B1 milestone 2), cu CONTROL NEGATIV: un dosar cu cod vulnerabil produce actiunile // corecte; un dosar tot-PQ produce plan gol. Isi face singura fixturile intr-un temp si le sterge. // node proba-control-plane.mjs -> 0 toate cum trebuia, 1 altfel import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const CLI = path.join(AICI, 'control-plane.mjs'); const T = fs.mkdtempSync(path.join(os.tmpdir(), 'cp-proba-')); let rele = 0; const cer = (n, c) => { console.log(` [${c ? 'OK ' : 'RAU '}] ${n}`); if (!c) rele++; }; function ruleaza(dir, scanFile) { const args = [CLI, '--code', dir, '--json']; if (scanFile) args.push('--scan', scanFile); return JSON.parse(execFileSync(process.execPath, args, { encoding: 'utf8' })); } try { // fixtura vulnerabila const v = path.join(T, 'vuln'); fs.mkdirSync(v); fs.writeFileSync(path.join(v, 'a.js'), "const c=require('crypto');\nc.createECDH('prime256v1');\nc.createSign('RSA-SHA256');\n"); // fixtura PQ const pq = path.join(T, 'pq'); fs.mkdirSync(pq); fs.writeFileSync(path.join(pq, 'b.js'), "// ML-KEM-768 si ML-DSA-65, doar nume\nconst a='ML-KEM-768', s='ML-DSA-65';\n"); // scanare de proba (readiness): un schimb de cheie clasic pe un host const scanF = path.join(T, 'scan.json'); fs.writeFileSync(scanF, JSON.stringify({ domain: 'client.test', findings: [{ id: 'hndl-exposed', severity: 'high', title: 'No post-quantum key exchange: harvest-now-decrypt-later exposure' }] })); const pv = ruleaza(v); const byRef = Object.fromEntries(pv.actions.map((a) => [a.ref.split(':').slice(0, 3).join(':'), a])); cer('dosar vulnerabil: 2 folosiri vulnerabile', pv.inventory.quantumVulnerable === 2); cer('dosar vulnerabil: 2 actiuni in plan', pv.summary.total === 2); const ecdh = pv.actions.find((a) => /ECDH/i.test(a.name || a.asset)); const rsa = pv.actions.find((a) => /RSA/i.test(a.name || a.asset)); cer('ECDH -> gateway (schimb de cheie, auto)', ecdh && ecdh.product === 'gateway' && ecdh.method === 'auto-aere'); cer('RSA -> pki (semnatura, auto)', rsa && rsa.product === 'pki'); cer('HNDL: ECDH mai urgent decat RSA', ecdh && rsa && ({ CRITICAL: 0, HIGH: 1, MEDIUM: 2 }[ecdh.urgency] < { CRITICAL: 0, HIGH: 1, MEDIUM: 2 }[rsa.urgency])); cer('fiecare actiune are locatia (fisier:linie)', pv.actions.every((a) => a.location && /\.js:\d/.test(a.location))); // cu scanare: apare si actiunea de schimb de cheie TLS (gateway, CRITICA) const pvs = ruleaza(v, scanF); const kex = pvs.actions.find((a) => /tls-kex/.test(a.ref)); cer('cu scanare: schimbul de cheie TLS e in plan, gateway CRITICA', kex && kex.product === 'gateway' && kex.urgency === 'CRITICAL'); // CONTROL NEGATIV: dosar tot-PQ -> 0 vulnerabile, plan gol const ppq = ruleaza(pq); cer('CONTROL: dosar tot-PQ -> 0 vulnerabile', ppq.inventory.quantumVulnerable === 0); cer('CONTROL: dosar tot-PQ -> plan gol', ppq.summary.total === 0); } finally { fs.rmSync(T, { recursive: true, force: true }); } console.log(`\nB1 control-plane CLI: ${9 - rele}/9 cum trebuia`); process.exit(rele ? 1 : 0);