87 lines
4.6 KiB
JavaScript
87 lines
4.6 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
// AERE Quantum Security Control Plane (B1), CLI cap la cap: inventar criptografic + (optional) scanare de pregatire PQ -> plan de
|
|
// migrare prioritizat. Compune uneltele care exista deja - nu reinventeaza: inventarul (crypto-inventory), scanerul (dat ca JSON),
|
|
// planificatorul (plan-migrare.mjs). Ruleaza offline pe un dosar de cod; scanarea unui hostname se da aici cu --scan <fisier.json>.
|
|
// Iesirea e in engleza (forma planului 2, vezi plan-migrare.mjs).
|
|
//
|
|
// node control-plane.mjs --code <dir> [--scan scan.json] [--json]
|
|
// iesire 0 = plan produs (chiar si gol); 2 = nu s-a putut rula.
|
|
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
|
const AICI = path.dirname(fileURLToPath(import.meta.url));
|
|
const RAD = path.resolve(AICI, '..', '..');
|
|
|
|
// inventarul: langa planul de control intr-o copie publica (../crypto-inventory), sau in depozitul de dezvoltare (tools/)
|
|
export function caleaInventarului() {
|
|
const c = [path.join(AICI, '..', 'crypto-inventory', 'inventar.mjs'), path.join(RAD, 'tools', 'crypto-inventory', 'inventar.mjs')];
|
|
return c.find((p) => fs.existsSync(p)) || c[c.length - 1];
|
|
}
|
|
|
|
// scanerul de pregatire PQ: in dosarul readiness/ al unei copii publice, sau langa planul de control (depozitul de dezvoltare)
|
|
export function caleaScanerului() {
|
|
const c = [path.join(AICI, '..', 'readiness', 'readiness-service.mjs'), path.join(AICI, '..', 'readiness-service.mjs')];
|
|
return c.find((p) => fs.existsSync(p)) || c[c.length - 1];
|
|
}
|
|
|
|
// adaptor: findings-ul inventarului e DEJA clasificat (are assetType, name, primitive, quantumVulnerable, certificate in engleza);
|
|
// nu se re-cheama classify. Se adauga doar ref (unic pe fisier:linie) si locatia.
|
|
function laPlanificator(g) {
|
|
return {
|
|
ref: `crypto:${g.assetType || 'algorithm'}:${g.name || g.primitive || 'unknown'}:${g.file || ''}:${g.line || ''}`,
|
|
assetType: g.assetType || 'algorithm',
|
|
name: g.name,
|
|
// primitiva inventarului trece NEATINSA: pentru certificate ea e 'unknown'/'other' (a cheii), iar ce inseamna asta pentru un
|
|
// certificat decide planificatorul (primitivaDe), intr-un singur loc
|
|
primitive: g.primitive,
|
|
quantumVulnerable: g.quantumVulnerable,
|
|
curve: g.curve, parameterSetIdentifier: g.parameterSetIdentifier,
|
|
certificate: g.certificate,
|
|
material: g.material,
|
|
location: g.file ? `${g.file}:${g.line || '?'}` : undefined,
|
|
};
|
|
}
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
const jsonOut = args.includes('--json');
|
|
const codeI = args.indexOf('--code'); const code = codeI >= 0 ? args[codeI + 1] : null;
|
|
const scanI = args.indexOf('--scan'); const scanFile = scanI >= 0 ? args[scanI + 1] : null;
|
|
if (!code) { console.error('usage: node control-plane.mjs --code <dir> [--scan scan.json] [--json]'); process.exit(2); }
|
|
|
|
const inv = await import(pathToFileURL(caleaInventarului()).href);
|
|
const { planeaza } = await import(pathToFileURL(path.join(AICI, 'plan-migrare.mjs')).href);
|
|
|
|
let rez; try { rez = inv.scan(code); } catch (e) { console.error('the inventory could not scan: ' + e.message); process.exit(2); }
|
|
const clasificate = (rez.findings || []).map(laPlanificator);
|
|
|
|
let scan = null;
|
|
if (scanFile) {
|
|
try { scan = JSON.parse(fs.readFileSync(scanFile, 'utf8')); } catch (e) { console.error('cannot read the scan: ' + e.message); process.exit(2); }
|
|
}
|
|
|
|
const plan = planeaza({ inventory: clasificate, scan });
|
|
const iesire = {
|
|
generatedAt: new Date().toISOString(),
|
|
code, scan: scanFile || null,
|
|
inventory: { findings: (rez.findings || []).length, quantumVulnerable: clasificate.filter((c) => c.quantumVulnerable).length },
|
|
...plan,
|
|
};
|
|
|
|
if (jsonOut) { console.log(JSON.stringify(iesire, null, 1)); process.exit(0); }
|
|
console.log(`AERE Control Plane - post-quantum migration plan for ${code}${scanFile ? ' + ' + scanFile : ''}`);
|
|
console.log(` inventory: ${iesire.inventory.findings} uses, ${iesire.inventory.quantumVulnerable} quantum-vulnerable`);
|
|
console.log(` plan: ${plan.summary.total} actions | ${JSON.stringify(plan.summary.byUrgency)} | auto=${plan.summary.autoAere} manual=${plan.summary.manual} blocked=${plan.summary.blocked}`);
|
|
for (const a of plan.actions) {
|
|
console.log(` [${a.urgency.padEnd(8)}] ${a.asset}${a.location ? ' (' + a.location + ')' : ''}`);
|
|
console.log(` ${a.problem} -> ${a.target} [${a.method}${a.product ? ' via ' + a.product : ''}]${a.blocker ? ' BLOCKED BY: ' + a.blocker : ''}`);
|
|
}
|
|
process.exit(0);
|
|
}
|
|
if (import.meta.url === pathToFileURL(process.argv[1] || '').href) {
|
|
main().catch((e) => { console.error('error: ' + (e.stack || e.message)); process.exit(2); });
|
|
}
|