aere-quantum/crypto-inventory/test/echivalenta-0.1.0.mjs

88 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Echivalenta formelor liniare din 0.2.0 cu formele din 0.1.0 (2026-09-29, revizuirea adversariala): aceleasi gasiri si biblioteci
// pe arbori reali, si aceleasi rezultate ale lexerului si ale cautarii PEM pe texte generate din jetoanele care conteaza.
// 0.1.0 se ia din git (revizia AERE_INV_REV_VECHE, implicit db9d9543), in forma comisa; intr-o copie fara istoric iese SARIT.
// node test/echivalenta-0.1.0.mjs [--iteratii N] [dosar...] (implicit: fixturile si dosarul uneltei)
// -> 0 identic, 1 o diferenta (tiparita), 2 NEMASURAT (revizia veche lipseste sau nimic comparat)
// Singura diferenta asteptata e textul motivului pentru "unknown" (spune acum si plafonul de variabile); se normalizeaza.
import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { spawnSync } from 'node:child_process';
import { tmpdir } from 'node:os';
const AICI = dirname(fileURLToPath(import.meta.url));
const RAD = join(AICI, '..');
const REV = process.env.AERE_INV_REV_VECHE || 'db9d9543';
let ITER = 20000;
const dosare = [];
for (let k = 2; k < process.argv.length; k++) {
if (process.argv[k] === '--iteratii') ITER = Number(process.argv[++k]);
else dosare.push(process.argv[k]);
}
const DOSARE = dosare.length ? dosare : [join(AICI, 'fixturi'), RAD];
const git = (...a) => spawnSync('git', ['-c', 'core.autocrlf=false', ...a], { cwd: RAD, encoding: 'buffer', maxBuffer: 64 << 20 });
const ls = git('ls-tree', '-r', '--name-only', '--full-tree', REV, 'tools/crypto-inventory/inventar.mjs', 'tools/crypto-inventory/lib');
const fis = ls.status === 0 ? ls.stdout.toString().split('\n').filter(Boolean) : [];
if (!fis.length) { console.log(`SARIT: revizia ${REV} nu e in istoricul acestui depozit; NEMASURAT aici`); process.exit(2); }
const vechi = mkdtempSync(join(tmpdir(), 'ci-v010-'));
let dif = 0, comparate = 0;
try {
for (const f of fis) {
const b = git('show', `${REV}:${f}`);
if (b.status !== 0) { console.log(`NEMASURAT: git show ${f}`); process.exit(2); }
const t = join(vechi, f.slice('tools/crypto-inventory/'.length));
mkdirSync(dirname(t), { recursive: true });
writeFileSync(t, b.stdout);
}
const imp = (r, m) => import(pathToFileURL(join(r, 'lib', m)).href);
const [SV, SN, LV, LN, PN] = await Promise.all([imp(vechi, 'scan.mjs'), imp(RAD, 'scan.mjs'), imp(vechi, 'lexer.mjs'), imp(RAD, 'lexer.mjs'), imp(RAD, 'pem.mjs')]);
if (SV.VERSIUNE !== '0.1.0') { console.log(`NEMASURAT: revizia ${REV} are versiunea ${SV.VERSIUNE}, nu 0.1.0`); process.exit(2); }
// 1. arbori reali
const norm = (g) => JSON.stringify({ ...g, reason: String(g.reason).replace(/, which (cannot be resolved statically|this tool does not resolve statically).*$/, ', which [motiv]') });
for (const d of DOSARE) {
const a = SV.scaneaza(d), b = SN.scaneaza(d);
const ka = a.findings.map(norm), kb = b.findings.map(norm);
const sa = new Set(ka), sb = new Set(kb);
const doarV = ka.filter((x) => !sb.has(x)), doarN = kb.filter((x) => !sa.has(x));
const ok = !doarV.length && !doarN.length && ka.length === kb.length && JSON.stringify(a.libraries) === JSON.stringify(b.libraries);
comparate += ka.length;
if (!ok) dif++;
console.log(`${ok ? 'IDENTIC ' : 'DIFERIT '} ${d}: ${a.stats.filesSeen} fisiere, gasiri ${ka.length}/${kb.length}, biblioteci ${a.libraries.length}/${b.libraries.length}`);
for (const x of [...doarV.slice(0, 3).map((x) => 'numai 0.1.0: ' + x), ...doarN.slice(0, 3).map((x) => 'numai 0.2.0: ' + x)]) console.log(' ' + x.slice(0, 260));
}
// 2. texte generate: lexerul pe patru limbaje si cautarea PEM (fata de regexul din 0.1.0)
const RE_010 = /-----BEGIN ((?:RSA |EC |DSA |OPENSSH |ENCRYPTED )?PRIVATE KEY|PUBLIC KEY|RSA PUBLIC KEY|CERTIFICATE)-----([A-Za-z0-9+/=\s:,\-\r\n]*?)-----END \1-----/g;
let seed = 12345;
const rnd = (n) => { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed % n; };
const gen = (jet, max) => { let s = ''; const L = rnd(max); for (let i = 0; i < L; i++) s += jet[rnd(jet.length)]; return s; };
const JET = {
python: ['"', "'", '"""', "'''", '\\', '\n', ' ', '\t', 'r', 'b', 'f', 'u', 'x', '#', '=', '(', ')', 'rb', '\r\n', 'a1'],
javascript: ['=/[', '=/', ' x/', '"', "'", '`', '${', '}', '{', '/', '//', '/*', '*/', '[', ']', '\\', '\n', ' ', '=', '(', ')', 'return', 'x', '1', '.', ',', 'typeof'],
java: ['"', "'", '"""', '\\', '\n', ' ', '/', '//', '/*', '*/', 'x', '=', '(', ')'],
go: ['"', "'", '`', '\\', '\n', ' ', '/', '//', '/*', '*/', 'x', '=', '(', ')'],
};
const JET_PEM = ['-----BEGIN CERTIFICATE-----', '-----END CERTIFICATE-----', '-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----',
'-----BEGIN RSA PRIVATE KEY-----', '-----END RSA PRIVATE KEY-----', '-----BEGIN PUBLIC KEY-----', '-----END PUBLIC KEY-----',
'BEGIN CERTIFICATE-----', 'BEGIN PRIVATE KEY-----', 'AAAA', 'QUJD', '\n', ' ', '.', '-', '--', '-----', '"', 'BEGIN', '=', ':', ' ', '\r\n'];
const cat = {};
for (let k = 0; k < ITER; k++) {
for (const [limbaj, jet] of Object.entries(JET)) {
const t = gen(jet, 40);
const a = LV.curata(t, limbaj), b = LN.curata(t, limbaj);
comparate++;
if (a.code !== b.code || JSON.stringify(a.siruri) !== JSON.stringify(b.siruri)) { cat[limbaj] = (cat[limbaj] || 0) + 1; if (dif++ < 5) console.log(`DIFERIT lexer ${limbaj}: ${JSON.stringify(t)}`); }
}
const t = gen(JET_PEM, 30);
const a = [...t.matchAll(RE_010)].map((m) => [m.index, m[1], m[2]]);
const b = [...PN.blocuriPem(t)].map((x) => [x.index, x.tip, x.corp]);
comparate++;
if (JSON.stringify(a) !== JSON.stringify(b)) { cat.pem = (cat.pem || 0) + 1; if (dif++ < 5) console.log(`DIFERIT pem: ${JSON.stringify(t)}`); }
}
console.log(`texte generate: ${ITER} runde (lexer x4 + PEM), diferente ${JSON.stringify(cat)}`);
} finally { rmSync(vechi, { recursive: true, force: true }); }
console.log(`\n${dif ? 'DIFERIT' : 'IDENTIC'}: ${dif} diferente in ${comparate} comparatii (0.1.0 din ${REV} fata de 0.2.0)`);
process.exitCode = dif ? 1 : comparate ? 0 : 2;