// fixturi-organizatie.mjs: artefactele pe care se masoara judecata organizatiei (organizatie.mjs), DERIVATE din producatori, niciunul scris de // mana in forma pe care o presupune consumatorul: // - pentru cele 23 de feluri ale suitei de conformitate: vectorii ei (tools/aere-conformance/vectori, publicati in aere-quantum/conformance), // pe care generatorul lor ii deriva din producatori si ii verifica octet cu octet; fiecare vector folosit aici se cere egal cu amprenta lui din // INDEX.json. Un vector `{ artifact, input }` se IMPARTE dupa clasele din organizatie.mjs: artefactul si ce e semnat de un tert merg in pachet, // intrarile verificatorului (ceasul, increderea, provocarea, citirile lui) in contextul celui care verifica; // - pentru felurile planului de control: starea Shield facuta acum de sidecar-ul real (doua inregistrari, un buraf), planificatorul real si // executorul real (uscat), iar raportul de conformitate PQ facut de raport-conformitate.mjs pe planul acela. // Fiecare fel are un artefact BUN si un frate STRICAT, refuzat de verificatorul lui pentru o regula numita. import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import crypto from 'node:crypto'; import { execFileSync } from 'node:child_process'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { INTRARI, PACK_KIND, CONTEXT_KIND, FELURI_PROPRII } from './organizatie.mjs'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const RAD = path.resolve(AICI, '..', '..'); const sha = (b) => '0x' + crypto.createHash('sha256').update(b).digest('hex'); export function dosarulSuitei() { const c = [path.join(AICI, '..', 'conformance'), path.join(RAD, 'tools', 'aere-conformance')]; return c.find((d) => fs.existsSync(path.join(d, 'vectori', 'INDEX.json'))) || null; } let INDEX = null; export function indexul() { if (INDEX) return INDEX; const d = dosarulSuitei(); if (!d) throw new Error('the conformance vectors are not beside the control plane (../conformance/vectori) nor in tools/aere-conformance'); INDEX = { dir: path.join(d, 'vectori'), j: JSON.parse(fs.readFileSync(path.join(d, 'vectori', 'INDEX.json'), 'utf8')) }; return INDEX; } /** Un vector, cerut egal octet cu octet cu amprenta lui din INDEX.json (deci chiar cel scris de generator). */ export function vectorul(id) { const { dir, j } = indexul(); const e = j.vectors.find((v) => v.id === id); if (!e) throw new Error('no vector ' + id + ' in INDEX.json'); const b = fs.readFileSync(path.join(dir, ...id.split('/')) + '.json'); if (sha(b) !== e.sha256) throw new Error(`vector ${id}: sha256 ${sha(b).slice(0, 14)} is not the one in INDEX.json (${e.sha256.slice(0, 14)})`); return JSON.parse(b.toString('utf8')); } /** inputul unui vector -> partea pachetului (artefactul, ce e semnat de un tert) si partea contextului (verificatorul, ceasul) */ export function imparte(fel, input) { const cls = INTRARI[fel]; const pack = {}, context = {}; for (const [k, v] of Object.entries(input)) { // '*': o cheie pe care modulul nu o citeste pe nume, la un fel citit intreg (un membru in plus): a artefactului, ca in organizatie.mjs const c = Object.hasOwn(cls, k) ? cls[k] : cls['*']; if (c === undefined) throw new Error(`${fel}: the vector has an input ${k} that organizatie.mjs does not classify`); if (c === 'artifact' || c === 'stapled') pack[k] = v; else context[k] = v; } return { pack, context }; } const egal = (a, b) => JSON.stringify(a) === JSON.stringify(b); /** Pentru fiecare fel al suitei: un vector bun (nu INVALID, fara retea; VALID cand exista) si un frate stricat: INVALID, fara retea, facut din * vectorul bun, cu ACELASI context si alt artefact (deci artefactul e stricat, nu increderea celui care verifica), o singura regula cand se poate. */ export function alegeVectorii() { const { j } = indexul(); const feluri = Object.keys(j.artifacts); const ales = {}; for (const fel of feluri) { const ale = j.vectors.filter((v) => v.artifact === fel && !v.requires.length); const bun = ale.find((v) => v.verdict === 'VALID') || ale.find((v) => v.verdict === 'PARTIAL'); if (!bun) throw new Error(`${fel}: no vector that is not INVALID and needs no network`); const vb = vectorul(bun.id); const ib = imparte(fel, vb.input); const candidati = ale.filter((v) => v.verdict === 'INVALID').map((v) => vectorul(v.id)) .filter((x) => x.base === bun.id).map((x) => ({ x, i: imparte(fel, x.input) })) .filter(({ i }) => egal(i.context, ib.context) && !egal(i.pack, ib.pack)); // o singura regula, si nu una de forma (un artefact care nu se poate citi deloc spune putin despre compunere), cand se poate const deForma = (r) => /[.-]form$/.test(r); const rau = candidati.find(({ x }) => x.expected.failed.length === 1 && !deForma(x.expected.failed[0])) || candidati.find(({ x }) => x.expected.failed.length === 1) || candidati[0]; if (!rau) throw new Error(`${fel}: no INVALID vector made from ${bun.id} with the same verifier inputs and another artifact`); ales[fel] = { bun: { id: bun.id, v: vb, ...ib }, rau: { id: rau.x.id, v: rau.x, ...rau.i } }; } return ales; } /** Starea Shield, facuta de uneltele reale: un jurnal al sidecar-ului (doua inregistrari), burafu lui, planul planificatorului pe un inventar * cu un schimb de cheie si o semnatura clasice si o scanare cu expunere HNDL, si executia lui uscata. Fratele stricat: o inregistrare a executiei * schimbata dupa scriere (lantul executiei rupt, nimic altceva). */ export async function stareaShield() { const T = fs.mkdtempSync(path.join(os.tmpdir(), 'org-shield-')); try { const { caleaSidecarului } = await import(pathToFileURL(path.join(AICI, 'consola.mjs')).href); const SIDE = caleaSidecarului(); const side = (args) => execFileSync(process.execPath, [SIDE, ...args], { encoding: 'utf8', stdio: 'pipe' }); const log = path.join(T, 'audit.log'); const bin = path.join(T, 'node'); fs.writeFileSync(bin, 'BIN'); side(['record', '--kind', 'runtime', '--artifact', bin, '--attested', sha(fs.readFileSync(bin)), '--host', 'org-prod-1', '--log', log, '--at', '2026-10-20T08:00:00Z']); side(['record', '--kind', 'deployment', '--name', 'checkout-api', '--version', '4.2.1', '--content-file', bin, '--log', log, '--at', '2026-10-20T08:05:00Z']); const bf = path.join(T, 'b.json'); side(['bundle', '--log', log, '--out', bf, '--host', 'org-prod-1', '--at', '2026-10-20T08:10:00Z']); const bundle = JSON.parse(fs.readFileSync(bf, 'utf8')); const { planeaza } = await import(pathToFileURL(path.join(AICI, 'plan-migrare.mjs')).href); const plan = planeaza({ inventory: [ { assetType: 'algorithm', name: 'ECDH', primitive: 'key-agree', quantumVulnerable: true, ref: 'a:1' }, { assetType: 'algorithm', name: 'RSA-2048', primitive: 'signature', quantumVulnerable: true, ref: 'a:2' }, { assetType: 'algorithm', name: 'ML-KEM-768', primitive: 'kem', quantumVulnerable: false, ref: 'a:3' }, ], scan: { domain: 'exemplu.test', findings: [{ id: 'hndl-exposed', severity: 'high', title: 'No post-quantum key exchange' }] } }); const { executa } = await import(pathToFileURL(path.join(AICI, 'executa-migrare.mjs')).href); const x = await executa(plan, { consent: 'all', execute: false, out: path.join(T, 'exec') }); const execution = JSON.parse(fs.readFileSync(x.file, 'utf8')); if (!(Array.isArray(execution.records) && execution.records.length >= 2)) throw new Error('the dry execution wrote fewer than two records'); const stricata = JSON.parse(JSON.stringify(execution)); stricata.records[1].record.verdict = 'OK'; return { bun: { bundle, plan, execution }, rau: { bundle, plan, execution: stricata }, rauRegula: 'shield.execution-chain', plan }; } finally { fs.rmSync(T, { recursive: true, force: true }); } } /** Raportul de conformitate PQ pe planul real, legat de plicul lui AIP-23; fratele stricat: raportul schimbat dupa legare. */ export async function raportulPQ(plan) { const { raportConformitate } = await import(pathToFileURL(path.join(AICI, 'raport-conformitate.mjs')).href); const { report, envelope } = raportConformitate({ plan, organization: 'Example Organization', risk: 'high', date: '2026-10-20' }); const schimbat = JSON.parse(JSON.stringify(report)); schimbat.organization = 'Another Organization'; return { bun: { report, envelope }, rau: { report: schimbat, envelope }, rauRegula: 'pqreport.binding' }; } /** * Pachetul bun al unei organizatii cu un artefact din fiecare fel (23 ale suitei + 2 ale planului de control), contextul derivat al celui care * verifica, si ce se asteapta pentru fiecare (verdictul, regulile, starile nivelurilor din vector). `stricate[fel]` e fratele stricat al fiecaruia. */ export async function pachetulBun() { const ales = alegeVectorii(); const artifacts = [], byArtifact = {}, asteptat = {}, stricate = {}; const idDe = (fel) => fel + '-1'; for (const [fel, { bun, rau }] of Object.entries(ales)) { const id = idDe(fel); artifacts.push({ id, artifact: fel, input: bun.pack }); if (Object.keys(bun.context).length) byArtifact[id] = bun.context; asteptat[id] = { verdict: bun.v.expected.verdict, failed: bun.v.expected.failed, levels: bun.v.expected.levels, vector: bun.id }; stricate[fel] = { id, artifact: { id, artifact: fel, input: rau.pack }, failed: rau.v.expected.failed, levels: rau.v.expected.levels, vector: rau.id }; } const sh = await stareaShield(); const pq = await raportulPQ(sh.plan); artifacts.unshift({ id: 'shield-console-1', artifact: 'shield-console', input: sh.bun }); stricate['shield-console'] = { id: 'shield-console-1', artifact: { id: 'shield-console-1', artifact: 'shield-console', input: sh.rau }, failed: [sh.rauRegula], vector: null }; asteptat['shield-console-1'] = { verdict: 'VALID', failed: [] }; artifacts.push({ id: 'pq-compliance-report-1', artifact: 'pq-compliance-report', input: pq.bun }); stricate['pq-compliance-report'] = { id: 'pq-compliance-report-1', artifact: { id: 'pq-compliance-report-1', artifact: 'pq-compliance-report', input: pq.rau }, failed: [pq.rauRegula], vector: null }; asteptat['pq-compliance-report-1'] = { verdict: 'VALID', failed: [] }; for (const f of FELURI_PROPRII) if (!stricate[f]) throw new Error('no broken sibling for ' + f); return { pack: { v: 1, kind: PACK_KIND, organization: 'Example Organization', createdAt: '2026-10-20T09:00:00Z', artifacts }, context: { v: 1, kind: CONTEXT_KIND, byArtifact }, asteptat, stricate, ales, }; } /** pachetul cu artefactul `id` inlocuit (sau scos, cu null) */ export function inlocuieste(pack, id, artefact) { const p = JSON.parse(JSON.stringify(pack)); const i = p.artifacts.findIndex((a) => a.id === id); if (i < 0) throw new Error('no artifact ' + id); if (artefact === null) p.artifacts.splice(i, 1); else p.artifacts[i] = JSON.parse(JSON.stringify(artefact)); return p; }