aere-quantum/control-plane/control-negativ-remediere.mjs

55 lines
4.6 KiB
JavaScript

// Controlul negativ al probei remedierii: fiecare paznic din remediere.mjs e stricat intr-o COPIE a arborelui, si proba trebuie sa
// iasa ROSIE pe copia stricata (cu probele chiar rulate: se cere cel putin un rand RAU, nu doar codul de iesire), iar pe copia
// neatinsa VERDE. O plantare care nu se potriveste cu sursa (tiparul nu mai exista) e un ESEC al controlului, nu o linie informativa.
// node control-negativ-remediere.mjs iesire 0 = copia neatinsa verde si toate plantarile rosii
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
const AICI = path.dirname(fileURLToPath(import.meta.url));
// dosarul scanerului: readiness/ intr-o copie publica, cloud-gateway/ in depozitul de dezvoltare (aceeasi regula ca in control-plane.mjs)
const { caleaScanerului } = await import('./control-plane.mjs');
const CG = path.dirname(caleaScanerului());
const PLANTARI = [
{ nume: 'judecata fara proprietatea pozitiva ("defect absent" = rezolvat)', din: 'if (inca || poz === false)', in: 'if (inca)' },
{ nume: 'reteta node fara grupul hibrid', din: 'if (s.groups) opt.ecdhCurve = grup(s.groups);', in: 'if (false) opt.ecdhCurve = grup(s.groups);' },
{ nume: 'scanarea de dinainte de aplicare acceptata', din: 'else if (!(Date.parse(scan.measuredAt) > Date.parse(limita)))', in: 'else if (false)' },
// 2026-09-29, R1 si R2 (revizuirea adversariala inainte de publicare); R2 pune inapoi FORMA VECHE intreaga (fara margine = se judeca)
{ nume: 'R1: domeniul din ref folosit fara verificare in comenzi', din: 'if (d && Object.hasOwn(REMEDIERI, d.id) && !domeniuValid(d.domain))', in: 'if (d && Object.hasOwn(REMEDIERI, d.id) && !domeniuValid(d.domain) && process.env.AERE_PLANTA_NICIODATA)' },
{ nume: 'R2: fara margine de timp se judeca pe orice scanare', perechi: [
['const limita = o.appliedAt || plan.generatedAt || null;', 'const limita = o.appliedAt || null;'],
["else if (!limita || !Number.isFinite(Date.parse(limita)))", 'else if (false)'],
['else if (!(Date.parse(scan.measuredAt) > Date.parse(limita)))', 'else if (limita && !(Date.parse(scan.measuredAt) > Date.parse(limita)))'] ] },
{ nume: 'alta gazda acceptata', din: 'else if (scan.domain !== d.domain)', in: 'else if (false)' },
{ nume: 'versiunea minima scapata din unire', din: "if (x.tlsMin) s.tlsMin = s.tlsMin === '1.3' || x.tlsMin === '1.3' ? '1.3' : '1.2';", in: "if (x.tlsMin) s.tlsMin = '1.2';" },
];
function copie() {
const t = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-b1-rem-cn-'));
fs.mkdirSync(path.join(t, 'control-plane'));
for (const f of ['readiness-service.mjs', 'adrese-private.mjs']) fs.copyFileSync(path.join(CG, f), path.join(t, f));
for (const f of ['remediere.mjs', 'proba-remediere.mjs', 'plan-migrare.mjs', 'executa-migrare.mjs', 'control-plane.mjs']) fs.copyFileSync(path.join(AICI, f), path.join(t, 'control-plane', f));
return t;
}
function ruleaza(t) {
const r = spawnSync(process.execPath, [path.join(t, 'control-plane', 'proba-remediere.mjs')], { encoding: 'utf8', timeout: 240000 });
const out = (r.stdout || '') + (r.stderr || '');
return { cod: r.status, rele: (out.match(/^\s+RAU\s/gm) || []).length, bune: (out.match(/^\s+OK\s/gm) || []).length, out };
}
let esecuri = 0;
const t0 = copie(); const r0 = ruleaza(t0); fs.rmSync(t0, { recursive: true, force: true });
if (r0.cod === 0 && r0.rele === 0 && r0.bune > 0) console.log(` OK copia neatinsa: verde (${r0.bune} treceri)`);
else { esecuri++; console.log(` RAU copia neatinsa nu e verde (cod ${r0.cod}, ${r0.rele} RAU)`); }
for (const p of PLANTARI) {
const t = copie(); const f = path.join(t, 'control-plane', 'remediere.mjs'); const src = fs.readFileSync(f, 'utf8');
const perechi = p.perechi || [[p.din, p.in]];
if (perechi.some(([a]) => src.split(a).length !== 2)) { esecuri++; console.log(` RAU ${p.nume}: tiparul nu apare exact o data in sursa (plantarea nu s-a putut pune)`); fs.rmSync(t, { recursive: true, force: true }); continue; }
fs.writeFileSync(f, perechi.reduce((s, [a, b]) => s.replace(a, b), src));
const r = ruleaza(t); fs.rmSync(t, { recursive: true, force: true });
if (r.cod !== 0 && r.rele > 0 && r.bune > 0) console.log(` OK ${p.nume}: proba ROSIE (${r.rele} RAU)`);
else { esecuri++; console.log(` RAU ${p.nume}: proba nu a iesit rosie din motivul plantat (cod ${r.cod}, ${r.rele} RAU, ${r.bune} OK)`); }
}
console.log(esecuri ? `RAU: ${esecuri} esecuri ale controlului` : `DOVEDIT: copia neatinsa verde, ${PLANTARI.length} din ${PLANTARI.length} plantari rosii`);
process.exitCode = esecuri ? 1 : 0;