Every artifact's SHA-256 and size, the SBOM's digest, the git commit and tree of the source, a hybrid signature (classical + ML-DSA, both required) and, when notarized, a first-seen time on Aere Network covered by the validators' post-quantum certificate. verify recomputes everything from the files; --rebuild-from repeats an npm pack build from a clone the verifier chose; the SBOM is re-derived from the committed package-lock.json or, new in 1.4.0, from the committed go.mod and go.sum; --signer requires the signing keys you expect (1.4.0); a developer credential binds the keys to a person, judged against a trust root you choose. The builder's declared date can only accuse, never acquit (1.4.0). Includes the GitHub Action and the hybrid signature library it uses. Laid out as in the development repository (tools/proof-of-software/, sdk-pq-sign/, sdk/) so that nothing is rewritten for publication. Tests and negative controls measured on 2026-09-29 are listed in README.md.
43 lines
2.9 KiB
JavaScript
43 lines
2.9 KiB
JavaScript
// Controlul negativ al probelor de proveninta a modelelor (model.test.mjs): fiecare paznic se strica pe rand IN pos.mjs (importurile
|
|
// relative ale lui pos.mjs nu permit o copie in alt dosar), proba tinta TREBUIE sa pice, iar fisierul se pune la loc in `finally` si
|
|
// se compara octet cu octet cu originalul. O plantare care nu se aplica e STRICAT, nu rosu.
|
|
// node aerenew/tools/proof-of-software/test/model-control-negativ.mjs
|
|
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 POS = path.join(AICI, '..', 'pos.mjs');
|
|
const original = fs.readFileSync(POS);
|
|
const text = original.toString('utf8');
|
|
|
|
const PLANTARI = [
|
|
['fluxul pierde ultima bucata partiala', 'h.update(n === buf.length ? buf : buf.subarray(0, n))', 'if (n === buf.length) h.update(buf)', 'hash in flux'],
|
|
['dosarele ascunse intra in model', "if (e.name.startsWith('.')) continue;", "if (e.name.startsWith('.') && false) continue;", 'ML-BOM CycloneDX 1.6'],
|
|
['manifestul fara marimi', "randuri.map((r) => `${r.rel}\\t${r.sha}\\t${r.bytes}\\n`)", "randuri.map((r) => `${r.rel}\\t${r.sha}\\n`)", 'digestul manifestului'],
|
|
['verificarea fara --base nu mai cere --base', "if (relativ && !base) ok('artifact names', false,", "if (relativ && !base && false) ok('artifact names', false,", 'FARA --base'],
|
|
];
|
|
|
|
let rele = 0;
|
|
try {
|
|
for (const [nume, vechi, nou, tinta] of PLANTARI) {
|
|
if (text.split(vechi).length !== 2) { console.log(` STRICAT ${nume}: ancora apare de ${text.split(vechi).length - 1} ori`); rele++; continue; }
|
|
fs.writeFileSync(POS, text.replace(vechi, nou));
|
|
const r = spawnSync(process.execPath, [path.join(AICI, 'model.test.mjs')], { encoding: 'utf8' });
|
|
const out = (r.stdout || '') + (r.stderr || '');
|
|
const rulate = (out.match(/^ (OK|ESEC) /gm) || []).length;
|
|
if (rulate < 8) { console.log(` STRICAT ${nume}: au rulat ${rulate} probe din 8`); rele++; continue; }
|
|
const picate = out.split('\n').filter((l) => l.startsWith(' ESEC '));
|
|
if (picate.some((l) => l.includes(tinta))) console.log(` ROSU cum trebuia ${nume} (${picate.length} esec, intre ele '${tinta}')`);
|
|
else { console.log(` CONTROL CAZUT ${nume}: proba '${tinta}' a ramas verde`); rele++; }
|
|
}
|
|
} finally {
|
|
fs.writeFileSync(POS, original);
|
|
}
|
|
if (!fs.readFileSync(POS).equals(original)) { console.log(' pos.mjs NU a fost pus la loc octet cu octet'); rele++; }
|
|
const m = spawnSync(process.execPath, [path.join(AICI, 'model.test.mjs')], { encoding: 'utf8' });
|
|
if (!/8 treceri, 0 esecuri/.test(m.stdout || '')) { console.log(' MARTORUL nu e verde'); rele++; } else console.log(' martor: pos.mjs neatins, 8/8 verde');
|
|
console.log(rele ? `CONTROL NEGATIV: ${rele} probleme` : `CONTROL NEGATIV TRECUT (${PLANTARI.length} din ${PLANTARI.length} rosii, pos.mjs pus la loc, martorul verde)`);
|
|
process.exitCode = rele ? 1 : 0;
|