// control-negativ-sidecar.mjs (2026-09-29, revizuirea adversariala, pista B): controlul negativ al verificarilor R, C si N din // proba-sidecar.mjs. Trei stari pe caz: PRINS (proba a ajuns la capat si verificarile numite sunt rosii), SCAPAT, STRICAT (copia nu // s-a incarcat, ancora nu apare exact o data, sau proba nu a ajuns la capat). // V0 sidecar-ul de dinainte, din git (sarit si spus daca revizia nu e in istoric) -> R CONTROL x3, N, N CONTROL, C rosii // P1 lacatul scos (scriitorii nu se mai asteapta) -> C rosu // P2 capul atestat nu se mai compara cu intrarea count-1 -> R CONTROL (istoria rescrisa) rosu // P3 lungimea jurnalului nu se mai compara cu count -> R CONTROL (intrari scoase) rosu // P4 statementHash-ul capului atestat nu se mai reface -> R CONTROL (cap manipulat) rosu // P5 un rand care nu e JSON arunca din nou (cadere) -> N rosu // P6 --attested nu se mai cere digest -> N CONTROL rosu // Copiile stau LANGA original (importul lui proof-kinds e relativ) si se sterg; originalul trebuie sa ramana octet cu octet. // node control-negativ-sidecar.mjs -> 0 toate prinse, 1 una scapata, 2 STRICAT import crypto from 'node:crypto'; import fs from 'node:fs'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const SRC = path.join(AICI, 'sidecar.mjs'); const PROBA = path.join(AICI, 'proba-sidecar.mjs'); const REV = process.env.AERE_SIDECAR_REV_VECHE || 'b2b08a5e'; const sha = (f) => crypto.createHash('sha256').update(fs.readFileSync(f)).digest('hex'); const inainte = sha(SRC); let prinse = 0, stricate = 0, total = 0; const T = { refacut: 'R CONTROL: acelasi lant refacut fata de capul atestat', taiat: 'R CONTROL: jurnal taiat sub capul atestat', capMan: 'R CONTROL: cap atestat manipulat', necitibil: 'N: rand care nu e JSON', digest: 'N CONTROL: --attested care nu e digest', concurent: 'C: doi scriitori concurenti', }; function caz(id, text, tinte) { total++; const copie = path.join(AICI, `.plantat-sidecar-${id}.mjs`); try { fs.writeFileSync(copie, text); const r = spawnSync(process.execPath, [PROBA], { encoding: 'utf8', timeout: 400000, env: { ...process.env, AERE_SIDECAR_MODUL: copie } }); const out = (r.stdout || '') + (r.stderr || ''); if (!/B3 sidecar \(verify layer\): \d+\/\d+ cum trebuia/.test(out) || !out.includes(copie)) { stricate++; console.log(` STRICAT ${id}: proba nu a ajuns la capat pe copie (${out.trim().split('\n').pop()?.slice(0, 140)})`); return; } const rosii = out.split('\n').filter((l) => l.includes('[RAU ]')); const lipsa = tinte.filter((x) => !rosii.some((l) => l.includes(x))); if (r.status === 1 && !lipsa.length) { prinse++; console.log(` PRINS ${id}: ${rosii.length} verificari rosii, intre ele: ${tinte.map((t) => t.split(':')[0]).join(', ')}`); } else console.log(` SCAPAT ${id}: cod ${r.status}, au ramas verzi: ${lipsa.join(' | ') || '-'}`); } finally { fs.rmSync(copie, { force: true }); fs.rmSync(copie + '.lock', { force: true }); } } const planta = (t, a, b) => (t.split(a).length === 2 ? t.replace(a, b) : null); const CALE = `${REV}:tools/aere-verify-layer/sidecar.mjs`; if (spawnSync('git', ['cat-file', '-e', CALE], { cwd: AICI }).status !== 0) console.log(` SARIT V0: revizia ${REV} nu e in istoricul acestui depozit; NEMASURAT aici`); else { const g = spawnSync('git', ['-c', 'core.autocrlf=false', 'show', CALE], { cwd: AICI, encoding: 'utf8' }); if (g.status !== 0 || g.stdout.includes('verificaFataDeCap')) { stricate++; total++; console.log(' STRICAT V0: revizia veche nu se citeste sau are deja reparatia'); } else caz('V0', g.stdout, [T.refacut, T.taiat, T.capMan, T.necitibil, T.digest]); } const nou = fs.readFileSync(SRC, 'utf8'); const NU = "process.env.AERE_PLANTA_NICIODATA === 'da'"; const P = [ ['P1', " try { return fn(); } finally { try { fs.unlinkSync(lacat); } catch { /* deja ridicat */ } }\n}", ` try { return fn(); } finally { try { fs.unlinkSync(lacat); } catch { /* deja ridicat */ } }\n}\nconst cuLacatAdevarat = cuLacat;\ncuLacat = (p, fn) => (${NU} ? cuLacatAdevarat(p, fn) : fn());`, [T.concurent]], ['P2', 'if (h !== st.head.toLowerCase()) return', `if (h !== st.head.toLowerCase() && ${NU}) return`, [T.refacut]], ['P3', 'if (intrari.length < st.count) return', `if (intrari.length < st.count && ${NU}) return`, [T.taiat]], ['P4', "if (!eDigest(cap.statementHash) || sha256(Buffer.from(JSON.stringify(st), 'utf8')) !== cap.statementHash.toLowerCase()) return", `if (!eDigest(cap.statementHash) || (sha256(Buffer.from(JSON.stringify(st), 'utf8')) !== cap.statementHash.toLowerCase() && ${NU})) return`, [T.capMan]], ['P5', "try { return JSON.parse(l); } catch { return { necitibil: true }; }", `try { return JSON.parse(l); } catch (e) { if (${NU}) return { necitibil: true }; throw e; }`, [T.necitibil]], ['P6', 'if (!eDigest(attested)) {', `if (!eDigest(attested) && ${NU}) {`, [T.digest]], ]; for (const [id, a, b, tinte] of P) { let t = planta(nou, a, b); // P1 cere ca `cuLacat` sa poata fi reasignat: declaratia de functie devine o variabila if (t && id === 'P1') t = planta(t, 'function cuLacat(p, fn) {', 'let cuLacat = function (p, fn) {'); if (!t) { stricate++; total++; console.log(` STRICAT ${id}: ancora nu apare exact o data`); continue; } caz(id, t, tinte); } const ramase = fs.readdirSync(AICI).filter((f) => f.startsWith('.plantat-sidecar-')); if (sha(SRC) !== inainte || ramase.length) { stricate++; console.log(' STRICAT originalul s-a schimbat sau au ramas copii: ' + ramase.join(',')); } console.log(`\ncontrolul negativ al sidecar-ului: prinse ${prinse}/${total}, stricate ${stricate}`); process.exitCode = stricate ? 2 : prinse === total ? 0 : 1;