Zero dependencies, no account, no API. Every command takes --rpc, so it runs against a node you operate and never needs ours. That is the point: an exposure measurement you cannot re-run is an opinion with a logo on it. Ships with two self-checks meant to be run by you, not just by us. The second, proba-vocabular.mjs, exists because of a real defect found on 2026-08-16: the scanner emits RED / YELLOW / GREEN, two downstream files each wrote their own copy of that list, and both wrote AMBER, so a hybrid contract, exactly a client who has already started migrating, was reported as unmeasurable. Both sides were self-consistent, so nothing we had could see it. The vocabulary now has one exported source, and the test walks the whole path with a negative control that makes it able to fail. The same scanner returns RED about our own contracts. See VERIFY-US.md.
96 lines
5.5 KiB
JavaScript
96 lines
5.5 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
/*
|
|
* proba-vocabular.mjs - proves that every verdict the scanner can emit survives the whole way
|
|
* to the client, and that a genuinely unmeasurable input still comes out as NOT MEASURED.
|
|
*
|
|
* WHY IT EXISTS. The scanner emitted RED / YELLOW / GREEN. Two downstream files each wrote their
|
|
* own list, and both wrote AMBER. So a hybrid contract, which is exactly the client who has
|
|
* already started migrating and is the most likely to pay, was reported as "we could not measure
|
|
* this address" in the free scan and as NOT MEASURED in the paid report. Measured 2026-08-16.
|
|
*
|
|
* The defect was invisible to every test we had, because each side was self-consistent. Only a
|
|
* test that walks the WHOLE path, scanner output to client wording, can see it. That is this file.
|
|
*
|
|
* CONTROL POZITIV: each of the three verdicts must survive end to end.
|
|
* CONTROL NEGATIV: an input that carries no verdict at all must still degrade to NOT MEASURED,
|
|
* otherwise this test would pass even if the reader returned a constant, and would prove nothing.
|
|
*
|
|
* node proba-vocabular.mjs exit 0 all good, 1 something drifted
|
|
*/
|
|
import { execFileSync } from 'node:child_process';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { VERDICTE, citesteVerdict } from './lib/bytecode.js';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const linii = [];
|
|
const spune = (ok, ce, obs) => { linii.push({ ok, ce, obs }); console.log(' ' + (ok ? 'PASS' : 'FAIL') + ' ' + ce + (obs ? ' ' + obs : '')); };
|
|
|
|
// Bytecode fixtures chosen so the scanner reaches each of its three branches offline, with no RPC.
|
|
// hibrid : uses a PQ precompile AND a classical one -> YELLOW
|
|
// doar PQ : uses only a PQ precompile -> GREEN
|
|
// clasic : uses only ecrecover -> RED
|
|
// Nota platita la prima rulare a acestei probe: fixtura pentru GREEN continea PUSH1 0x01 ca
|
|
// argument de CALL, iar scanerul l-a citit, corect, ca adresa lui ecrecover, deci fixtura iesea
|
|
// YELLOW si verdictul GREEN nu era atins de nimic. Proba a semnalat-o singura, si de aia are linia
|
|
// care cere ca FIECARE verdict din vocabular sa fie atins de cel putin o fixtura.
|
|
const FIXTURI = {
|
|
YELLOW: '0x602060006080600060006001610ae1f150600160006080600060006001610001f15000',
|
|
GREEN: '0x60206000602060006000610ae1611388f15000',
|
|
RED: '0x602060006080600060006001610001f15000',
|
|
};
|
|
|
|
function scan(bytecode) {
|
|
try {
|
|
return execFileSync(process.execPath,
|
|
['scan.js', '0x1111111111111111111111111111111111111111', '--bytecode', bytecode],
|
|
{ cwd: __dirname, encoding: 'utf8', timeout: 60000 }).trim();
|
|
} catch (e) { return String((e.stdout || '') + (e.stderr || e.message)).trim(); }
|
|
}
|
|
|
|
console.log('proba de vocabular: fiecare verdict al scanerului ajunge intreg la client\n');
|
|
console.log('vocabularul, din singura lui sursa: ' + VERDICTE.join(', ') + '\n');
|
|
|
|
// ── control pozitiv: fiecare verdict produs de scaner e citit ca atare ───────────────────────
|
|
console.log('CONTROL POZITIV, fiecare verdict pe tot drumul:');
|
|
const vazute = new Set();
|
|
for (const [asteptat, bytecode] of Object.entries(FIXTURI)) {
|
|
const text = scan(bytecode);
|
|
const emis = (text.match(/^\s*([A-Z]{3,14})\b/m) || [, '(niciunul)'])[1];
|
|
const citit = citesteVerdict(text) || 'NOT MEASURED';
|
|
vazute.add(emis);
|
|
spune(citit === emis && citit !== 'NOT MEASURED',
|
|
'scanerul emite ' + emis + ', consumatorul citeste ' + citit,
|
|
emis === asteptat ? '' : '(fixtura viza ' + asteptat + ', dar ce conteaza e ca ce s-a emis a fost citit)');
|
|
}
|
|
|
|
// Every verdict the vocabulary declares must actually be reachable by some fixture, otherwise a
|
|
// branch could rot unnoticed exactly the way YELLOW did.
|
|
for (const v of VERDICTE) {
|
|
spune(vazute.has(v), 'verdictul ' + v + ' e atins de cel putin o fixtura', vazute.has(v) ? '' : 'nicio fixtura nu il produce, deci nimeni nu l-ar fi prins daca se strica');
|
|
}
|
|
|
|
// ── control negativ: fara el, proba de mai sus ar trece si daca cititorul minte ──────────────
|
|
console.log('\nCONTROL NEGATIV, ca proba de mai sus sa insemne ceva:');
|
|
const fara = citesteVerdict('acest text nu poarta niciun verdict\nnicio linie nu incepe cu unul\n');
|
|
spune(fara === null, 'un text fara verdict da null, deci NOT MEASURED la consumator', 'a dat ' + (fara === null ? 'null' : fara));
|
|
|
|
const gol = citesteVerdict('');
|
|
spune(gol === null, 'textul gol da null', 'a dat ' + (gol === null ? 'null' : gol));
|
|
|
|
// A word that merely CONTAINS a verdict must not be mistaken for one.
|
|
const aproape = citesteVerdict(' GREENISH pasture\n REDACTED line\n');
|
|
spune(aproape === null, 'un cuvant care doar contine un verdict nu e luat drept verdict', 'a dat ' + (aproape === null ? 'null' : aproape));
|
|
|
|
// ── verdict ─────────────────────────────────────────────────────────────────────────────────
|
|
const rele = linii.filter((l) => !l.ok).length;
|
|
console.log('\n' + (linii.length - rele) + ' din ' + linii.length + ' verificari trec');
|
|
if (rele) {
|
|
console.log('VERDICT: vocabularul a divergat undeva pe drum. Verdictele nu ajung intregi la client.');
|
|
process.exitCode = 1;
|
|
} else {
|
|
console.log('VERDICT: fiecare verdict al scanerului ajunge intreg la client, si un text fara verdict');
|
|
console.log('ramane NOT MEASURED. Proba poate deveni rosie, deci verdele ei inseamna ceva.');
|
|
}
|