88 lines
6.0 KiB
JavaScript
88 lines
6.0 KiB
JavaScript
// 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;
|