212 lines
21 KiB
JavaScript
212 lines
21 KiB
JavaScript
// Proba executorului B1 (executa-migrare.mjs), pe produse REALE pornite local: un KMS (pq-kms/server.mjs cu cheie-radacina si jeton
|
|
// generate aici, scrise in fisiere 0600, niciodata tiparite), un CA PQ (pq-pki/cli.mjs init + intermediate, parola din mediu), un gateway
|
|
// PQ pornit de executor in fata unui upstream HTTP local, si un certificat clasic de test pentru gateway (openssl). Fara retea externa.
|
|
// Forma 2 a inregistrarilor (2026-09-29, in engleza): records/record, steps/step, before/after, verdict OK|FAILED|DRY-RUN|SKIPPED-no-consent.
|
|
// Cazuri (fiecare cu perechea lui):
|
|
// 1. fara consimtamant + execute=true -> nimic executat: aceleasi chei in KMS, niciun certificat scris, niciun gateway pornit
|
|
// 2. consimtamant 'all' + dry run -> la fel, nimic atins; inregistrarile spun DRY-RUN
|
|
// 3. consimtamant 'all' + execute -> gateway OK (hybrid-only: un client numai-PQ trece, unul numai-CLASIC e refuzat, masurat),
|
|
// KMS OK (cheie hibrida, latest_version 1), PKI OK (ML-DSA-65 pana la radacina); execution.json ok
|
|
// 4. a doua executie -> KMS ROTESTE (latest_version 2), min_decryption_version pastreaza versiunea veche
|
|
// 5. plantare: cheia gateway-ului NU e a certificatului -> actiunea gateway FAILED (gateway-ul refuza sa porneasca), CELELALTE merg
|
|
// 6. plantare: o inregistrare din execution.json schimbata -> verificaExecutie o prinde; nemodificata -> trece (controlul metodei)
|
|
// 7. actiunile 'manual'/'blocked' nu se executa niciodata (notExecutable in sumar)
|
|
// Atacurile revizuirii adversariale (2026-09-27), fiecare reprodus pe codul vechi inainte de reparatie:
|
|
// 8. produs 'constructor'/'toString' (mostenit din prototip) -> FAILED, nu OK fara actiune
|
|
// 9. gateway pe hybrid-preferred -> OK, iar inregistrarea spune ca un client clasic e inca acceptat
|
|
// 10. un camp `key` din plan care numeste o cheie straina existenta -> cheia straina NU e rotita
|
|
// 11. modul uscat scrie tinta efectiva; 12. un cn wildcard -> FAILED, niciun fisier scris
|
|
// Ref-urile REALE ale planificatorului (control-plane.mjs --code pe un dosar de cod generat aici), 2026-09-27:
|
|
// 13. doua actiuni KMS din acelasi fisier lung (liniile 4 si 7) -> DOUA chei distincte; consimtamantul pentru una nu o roteste pe cealalta
|
|
// 14. o actiune PKI fara cn, cu un ref real lung -> CN-ul implicit e un nume de gazda valid si certificatul se emite
|
|
// Numele fisierelor se citesc din INREGISTRARI (ce a raportat executorul), nu se ghicesc.
|
|
// node proba-executa-migrare.mjs iesire 0 = toate cum trebuia
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import http from 'node:http';
|
|
import crypto from 'node:crypto';
|
|
import { spawn } from 'node:child_process';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { executa, verificaExecutie } from './executa-migrare.mjs';
|
|
|
|
const AICI = path.dirname(fileURLToPath(import.meta.url));
|
|
const KMS_SERVER = path.join(AICI, '..', 'pq-kms', 'server.mjs');
|
|
const PKI_CLI = path.join(AICI, '..', 'pq-pki', 'cli.mjs');
|
|
const T = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-b1-exec-'));
|
|
const copii = [];
|
|
let up = null;
|
|
const dormi = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
const rezultate = []; let ok = 0, rau = 0;
|
|
const fisiere = (d) => (fs.existsSync(d) ? fs.readdirSync(d).filter((f) => f !== 'execution.json') : []);
|
|
const pas = (r, cheie) => (r && r.steps ? (r.steps.find((s) => s[cheie]) || {})[cheie] : undefined);
|
|
const inreg = (x) => x.records.map((i) => i.record);
|
|
function cere(cond, ce) { rezultate.push((cond ? 'OK ' : 'RAU ') + ce); if (cond) ok++; else rau++; }
|
|
function alnum(n) { const a = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789'; return Array.from(crypto.randomBytes(n)).map((b) => a[b % a.length]).join(''); }
|
|
function ruleaza(cmd, args, env, ms = 60000) {
|
|
return new Promise((resolve) => {
|
|
const p = spawn(cmd, args, { env: { ...process.env, ...env }, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
let o = '', e = ''; p.stdout.on('data', (b) => { o += b; }); p.stderr.on('data', (b) => { e += b; });
|
|
const t = setTimeout(() => p.kill(), ms);
|
|
p.on('close', (cod) => { clearTimeout(t); resolve({ cod, o, e }); });
|
|
p.on('error', (err) => { clearTimeout(t); resolve({ cod: -1, o, e: String(err.message) }); });
|
|
});
|
|
}
|
|
async function openssl(args) {
|
|
let r = await ruleaza('openssl', args, {});
|
|
if (r.cod === -1 && /ENOENT/.test(r.e)) r = await ruleaza('C:\\Program Files\\Git\\mingw64\\bin\\openssl.exe', args, {});
|
|
if (r.cod !== 0) throw new Error('openssl a cazut: ' + r.e.slice(0, 200));
|
|
}
|
|
async function kmsGet(url, token, cale) { const r = await fetch(url + cale, { headers: { authorization: 'Bearer ' + token } }); let j = null; try { j = await r.json(); } catch {} return { status: r.status, j }; }
|
|
|
|
try {
|
|
// --- KMS local
|
|
const kmsPort = 18420 + crypto.randomInt(1000); const kmsUrl = `http://127.0.0.1:${kmsPort}`;
|
|
const kmsToken = alnum(40); const tokenFile = path.join(T, 'kms.token'); fs.writeFileSync(tokenFile, kmsToken + '\n', { mode: 0o600 });
|
|
fs.mkdirSync(path.join(T, 'kms'), { recursive: true, mode: 0o700 });
|
|
const kms = spawn(process.execPath, [KMS_SERVER], { env: { ...process.env, AERE_KMS_ROOT_KEY: crypto.randomBytes(32).toString('hex'), AERE_KMS_TOKEN: kmsToken, AERE_KMS_PORT: String(kmsPort), AERE_KMS_HOST: '127.0.0.1', AERE_KMS_DATA_DIR: path.join(T, 'kms') }, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
copii.push(kms); let kmsErr = ''; kms.stderr.on('data', (b) => { kmsErr += b; });
|
|
let sus = false; for (let i = 0; i < 100 && !sus; i++) { try { const r = await fetch(kmsUrl + '/v1/health'); sus = r.status < 500; } catch { await dormi(100); } }
|
|
if (!sus) throw new Error('KMS-ul local nu a pornit: ' + kmsErr.slice(0, 200));
|
|
// --- CA PQ local (parola numai in mediul copiilor si in optiuni, niciodata tiparita)
|
|
const parola = alnum(26); const ca = path.join(T, 'ca');
|
|
let r = await ruleaza(process.execPath, [PKI_CLI, 'init', '--dir', ca, '--name', 'root', '--org', 'Proba'], { AERE_PKI_PASSPHRASE: parola });
|
|
if (r.cod !== 0) throw new Error('pki init: ' + (r.e || r.o).slice(0, 200));
|
|
r = await ruleaza(process.execPath, [PKI_CLI, 'intermediate', '--dir', ca, '--ca', 'root', '--name', 'issuing'], { AERE_PKI_PASSPHRASE: parola });
|
|
if (r.cod !== 0) throw new Error('pki intermediate: ' + (r.e || r.o).slice(0, 200));
|
|
// --- certificat clasic de test pentru gateway (ce are clientul azi) + o a doua pereche pentru plantarea "cheia nu e a certificatului"
|
|
await openssl(['req', '-x509', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:prime256v1', '-nodes', '-keyout', path.join(T, 'gw.key'), '-out', path.join(T, 'gw.crt'), '-subj', '/CN=localhost', '-days', '2', '-addext', 'subjectAltName=DNS:localhost']);
|
|
await openssl(['req', '-x509', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:prime256v1', '-nodes', '-keyout', path.join(T, 'alt.key'), '-out', path.join(T, 'alt.crt'), '-subj', '/CN=localhost', '-days', '2']);
|
|
// --- upstream HTTP local
|
|
up = http.createServer((q, s) => s.end('ok')); await new Promise((r2) => up.listen(0, '127.0.0.1', r2)); const upPort = up.address().port;
|
|
// --- planul (forma 2 a lui plan-migrare)
|
|
const plan = { actions: [
|
|
{ ref: 'tls-kex:localhost', asset: 'TLS on localhost', target: 'X25519MLKEM768 (hybrid)', method: 'auto-aere', product: 'gateway', urgency: 'CRITICAL', how: 'PQ Gateway in front' },
|
|
{ ref: 'kem:app-secret', asset: 'the application envelope', target: 'ML-KEM-768 (hybrid with X25519)', method: 'auto-aere', product: 'kms', urgency: 'CRITICAL', how: 'hybrid envelope through the KMS' },
|
|
{ ref: 'sig:svc.internal', asset: 'the service identity', target: 'ML-DSA-65', method: 'auto-aere', product: 'pki', urgency: 'HIGH', cn: 'svc.internal', how: 'PQ certificate' },
|
|
{ ref: 'tls-cert:public.example', asset: 'public certificate', target: 'ML-DSA-65', method: 'blocked', product: null, urgency: 'MEDIUM', blocker: 'public CA without post-quantum' },
|
|
] };
|
|
const gw = (extra = {}) => ({ cert: path.join(T, 'gw.crt'), key: path.join(T, 'gw.key'), upstream: `http://127.0.0.1:${upPort}`, mode: 'hybrid-only', selfSigned: true, servername: 'localhost', keep: false, ...extra });
|
|
const baza = (out, extra = {}) => ({ out: path.join(T, out), gateway: gw(), kms: { url: kmsUrl, token: kmsToken }, pki: { dir: ca, ca: 'issuing', roots: path.join(ca, 'root.crt'), passphrase: parola }, ...extra });
|
|
const chei = async () => { const l = await kmsGet(kmsUrl, kmsToken, '/v1/keys'); return (l.j && l.j.keys ? l.j.keys.length : -1); };
|
|
const chei0 = await chei();
|
|
|
|
// 1. fara consimtamant
|
|
let x = await executa(plan, baza('e1', { consent: [], execute: true }));
|
|
cere(x.summary.skipped === 3 && x.summary.ok === 0 && x.summary.notExecutable === 1, `1. fara consimtamant: 3 sarite, 0 executate, 1 neexecutabila (${JSON.stringify(x.summary)})`);
|
|
cere((await chei()) === chei0 && fisiere(path.join(T, 'e1')).length === 0, `1. fara consimtamant: KMS neatins, niciun fisier scris (${fisiere(path.join(T, 'e1')).join(',') || 'niciunul'})`);
|
|
// 2. uscat
|
|
x = await executa(plan, baza('e2', { consent: 'all', execute: false }));
|
|
cere(x.summary.dryRun === 3 && x.summary.ok === 0, `2. uscat: 3 DRY-RUN, 0 executate (${JSON.stringify(x.summary)})`);
|
|
cere((await chei()) === chei0 && fisiere(path.join(T, 'e2')).length === 0, `2. uscat: KMS neatins, nimic scris (${fisiere(path.join(T, 'e2')).join(',') || 'niciun fisier'})`);
|
|
// 3. executat
|
|
x = await executa(plan, baza('e3', { consent: 'all', execute: true }));
|
|
const rec = (ref) => inreg(x).find((i) => i.ref === ref);
|
|
const g = rec('tls-kex:localhost'), k = rec('kem:app-secret'), p = rec('sig:svc.internal');
|
|
cere(x.summary.ok === 3 && x.summary.failed === 0, `3. executat: 3 OK (${JSON.stringify(x.summary)})`);
|
|
cere(g && g.verdict === 'OK' && g.steps.some((s) => /TLS 1\.3 test/.test(s.step) && s.ok) && pas(g, 'file') && fs.existsSync(pas(g, 'file')), `3. gateway (hybrid-only): un client numai-PQ termina strangerea, configuratie emisa`);
|
|
cere(g && g.after && g.after.classicalAccepted === false, `3. gateway hybrid-only: un client numai-CLASIC e REFUZAT, masurat (${g && g.after ? g.after.guarantee : '?'})`);
|
|
cere(k && k.verdict === 'OK' && k.after && k.after.latest_version === 1 && (await chei()) === chei0 + 1, `3. kms: cheie hibrida creata, latest_version=${k && k.after ? k.after.latest_version : '?'}`);
|
|
cere(p && p.verdict === 'OK' && p.steps.some((s) => /chain verified/.test(s.step) && s.ok) && pas(p, 'cert') && fs.existsSync(pas(p, 'cert')) && fs.existsSync(pas(p, 'key')), `3. pki: certificat ${p && p.after ? p.after.alg : '?'} emis si verificat pana la radacina (${p && p.after ? p.after.chain.join(' <- ') : '?'})`);
|
|
const v3 = verificaExecutie(JSON.parse(fs.readFileSync(x.file, 'utf8')));
|
|
cere(v3.ok && v3.seq === x.records.length, `3. execution.json: lantul de hash-uri se verifica (${v3.seq} inregistrari)`);
|
|
// 4. a doua executie: KMS roteste
|
|
x = await executa(plan, baza('e4', { consent: ['kem:app-secret'], execute: true }));
|
|
const k2 = inreg(x).find((i) => i.ref === 'kem:app-secret');
|
|
cere(k2 && k2.verdict === 'OK' && k2.before && k2.before.exists && k2.after.latest_version === 2 && (await chei()) === chei0 + 1, `4. a doua executie: cheia ROTITA (latest_version=${k2 && k2.after ? k2.after.latest_version : '?'}), nu creata a doua oara`);
|
|
cere(k2 && k2.after && k2.after.min_decryption_version !== null && k2.after.min_decryption_version <= 1, `4. intoarcere: versiunea veche ramane decriptabila (min_decryption_version=${k2 && k2.after ? k2.after.min_decryption_version : '?'})`);
|
|
// 5. plantare: cheia nu e a certificatului -> gateway FAILED, restul OK
|
|
x = await executa(plan, baza('e5', { consent: 'all', execute: true, gateway: gw({ key: path.join(T, 'alt.key') }) }));
|
|
const g5 = inreg(x).find((i) => i.ref === 'tls-kex:localhost');
|
|
cere(g5 && g5.verdict === 'FAILED' && x.summary.failed === 1 && x.summary.ok === 2, `5. plantare (cheia nu e a certificatului): gateway FAILED (${g5 ? g5.error : '?'}), celelalte 2 OK`);
|
|
cere(!fisiere(path.join(T, 'e5')).some((f) => f.endsWith('.gateway.env')) && fisiere(path.join(T, 'e5')).some((f) => f.endsWith('.crt')), '5. plantare: nicio configuratie de gateway emisa pentru actiunea cazuta (certificatul actiunii PKI, da)');
|
|
// 6. tamper pe execution.json
|
|
const dosar = JSON.parse(fs.readFileSync(path.join(T, 'e3', 'execution.json'), 'utf8'));
|
|
cere(verificaExecutie(dosar).ok, '6. controlul metodei: dosarul nemodificat se verifica');
|
|
const t2 = JSON.parse(JSON.stringify(dosar)); const iK = t2.records.findIndex((i) => i.record.ref === 'kem:app-secret'); t2.records[iK].record.verdict = 'OK-fals';
|
|
const vt = verificaExecutie(t2);
|
|
cere(!vt.ok && vt.seq === iK, `6. plantare: o inregistrare schimbata e prinsa la seq ${vt.seq} (${vt.reason})`);
|
|
const t3 = JSON.parse(JSON.stringify(dosar)); t3.records.splice(iK, 1); t3.records.forEach((e, i) => { e.seq = i; });
|
|
cere(!verificaExecutie(t3).ok, '6. plantare: o inregistrare STEARSA e prinsa (lantul nu mai leaga)');
|
|
// 7. neexecutabile
|
|
cere(x.summary.notExecutable === 1 && !x.records.some((i) => i.record.ref === 'tls-cert:public.example'), '7. actiunea blocata (CA public fara PQ) nu e nici macar incercata');
|
|
|
|
// --- atacurile revizuirii adversariale (2026-09-27), fiecare reprodus inainte de reparatie ---
|
|
// 8. produs mostenit din Object.prototype: inainte, `constructor`/`toString` ieseau OK fara nicio actiune
|
|
for (const numeProt of ['constructor', 'toString']) {
|
|
const xp = await executa({ actions: [{ ref: 'prot:' + numeProt, method: 'auto-aere', product: numeProt }] }, baza('e8-' + numeProt, { consent: 'all', execute: true }));
|
|
const rp = inreg(xp).find((i) => i.ref === 'prot:' + numeProt);
|
|
cere(xp.summary.ok === 0 && xp.summary.failed === 1 && rp.verdict === 'FAILED', `8. ATAC: produs '${numeProt}' (mostenit din prototip) -> FAILED, nu OK (${rp.error})`);
|
|
}
|
|
// 9. gateway pe modul implicit hybrid-preferred: OK, dar inregistrarea spune ONEST ca un client clasic e inca acceptat
|
|
x = await executa({ actions: [plan.actions[0]] }, baza('e9', { consent: 'all', execute: true, gateway: gw({ mode: 'hybrid-preferred' }) }));
|
|
const g9 = inreg(x).find((i) => i.ref === 'tls-kex:localhost');
|
|
cere(g9 && g9.verdict === 'OK' && g9.after.classicalAccepted === true && /hybrid-only/.test(g9.after.guarantee), `9. hybrid-preferred: OK, iar inregistrarea spune ca un client clasic e inca acceptat (${g9 && g9.after && g9.after.guarantee ? g9.after.guarantee.slice(0, 70) : '?'})`);
|
|
// 10. un camp `key` din plan care numeste o cheie STRAINA existenta nu o mai roteste (numele vine numai din ref)
|
|
const strain = 'cheie-straina-prod';
|
|
let rs = await fetch(`${kmsUrl}/v1/keys/${strain}`, { method: 'POST', headers: { authorization: 'Bearer ' + kmsToken, 'content-type': 'application/json' }, body: JSON.stringify({ type: 'encrypt' }) });
|
|
if (rs.status === 404 || rs.status === 405) rs = await fetch(`${kmsUrl}/v1/keys`, { method: 'POST', headers: { authorization: 'Bearer ' + kmsToken, 'content-type': 'application/json' }, body: JSON.stringify({ name: strain, type: 'encrypt' }) });
|
|
const vStrain0 = (await kmsGet(kmsUrl, kmsToken, `/v1/keys/${strain}`)).j?.latest_version;
|
|
x = await executa({ actions: [{ ...plan.actions[1], ref: 'kem:alta', key: strain }] }, baza('e10', { consent: 'all', execute: true }));
|
|
const vStrain1 = (await kmsGet(kmsUrl, kmsToken, `/v1/keys/${strain}`)).j?.latest_version;
|
|
const k10 = inreg(x).find((i) => i.ref === 'kem:alta');
|
|
cere(vStrain0 === 1 && vStrain1 === 1 && k10 && k10.after && k10.after.key !== strain && /^mig-kem-alta/.test(k10.after.key), `10. ATAC: cheie straina numita in plan NU e rotita (versiunea ei ${vStrain0} -> ${vStrain1}); s-a lucrat pe ${k10 && k10.after ? k10.after.key : '?'}`);
|
|
// 11. modul uscat arata TINTA efectiva, ca omul sa consimta la ce se atinge de fapt
|
|
x = await executa({ actions: [{ ...plan.actions[1], ref: 'kem:vizibil', key: strain }] }, baza('e11', { consent: 'all', execute: false }));
|
|
const u11 = inreg(x).find((i) => i.ref === 'kem:vizibil');
|
|
cere(u11 && u11.verdict === 'DRY-RUN' && /mig-kem-vizibil/.test(u11.effectiveTarget) && u11.steps.some((s) => /mig-kem-vizibil/.test(s.step)), `11. uscat: tinta efectiva e scrisa (${u11 ? u11.effectiveTarget : '?'})`);
|
|
// 12. PKI: un cn wildcard e refuzat INAINTE de emitere, si nu ramane niciun fisier scris
|
|
x = await executa({ actions: [{ ...plan.actions[2], ref: 'sig:wild', cn: '*.bank.example' }] }, baza('e12', { consent: 'all', execute: true }));
|
|
const p12 = inreg(x).find((i) => i.ref === 'sig:wild');
|
|
cere(p12 && p12.verdict === 'FAILED' && fisiere(path.join(T, 'e12')).length === 0, `12. ATAC: cn wildcard refuzat, niciun fisier scris (${p12 ? p12.error : '?'})`);
|
|
|
|
// --- ref-urile REALE ale planificatorului: control-plane.mjs pe un dosar de cod generat aici ---
|
|
const cod = path.join(T, 'cod');
|
|
fs.mkdirSync(path.join(cod, 'services', 'payments', 'settlement'), { recursive: true });
|
|
fs.mkdirSync(path.join(cod, 'services', 'auth', 'tokens'), { recursive: true });
|
|
fs.writeFileSync(path.join(cod, 'services', 'payments', 'settlement', 'envelope.js'), [
|
|
"const crypto = require('node:crypto');", "const { publicKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 2048 });",
|
|
'function wrap(k) {', ' return crypto.publicEncrypt(publicKey, k);', '}', 'function wrapForAudit(k, auditKey) {',
|
|
' return crypto.publicEncrypt(auditKey, k);', '}', 'module.exports = { wrap, wrapForAudit };', ''].join('\n'));
|
|
fs.writeFileSync(path.join(cod, 'services', 'auth', 'tokens', 'session.js'), [
|
|
"const crypto = require('node:crypto');", "const { privateKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' });",
|
|
'function signSession(data) {', " return crypto.sign('sha256', data, privateKey);", '}', "const h = crypto.createSign('RSA-SHA256');",
|
|
'module.exports = { signSession, h };', ''].join('\n'));
|
|
const cp = await ruleaza(process.execPath, [path.join(AICI, 'control-plane.mjs'), '--code', cod, '--json'], {});
|
|
if (cp.cod !== 0) throw new Error('control-plane.mjs a cazut: ' + (cp.e || cp.o).slice(0, 200));
|
|
const planReal = JSON.parse(cp.o);
|
|
const kmsReal = planReal.actions.filter((a) => a.method === 'auto-aere' && a.product === 'kms' && /envelope\.js:/.test(a.ref));
|
|
const pkiReal = planReal.actions.filter((a) => a.method === 'auto-aere' && a.product === 'pki' && /session\.js:/.test(a.ref) && !a.cn);
|
|
// controlul fixturii: planificatorul REAL chiar a dat cazurile pe care le masuram, altfel 13/14 nu inseamna nimic
|
|
cere(kmsReal.length === 2 && pkiReal.length >= 1, `13/14. controlul fixturii: planificatorul real da ${kmsReal.length} actiuni KMS in envelope.js si ${pkiReal.length} PKI fara cn in session.js (${kmsReal.map((a) => a.ref.split(':').slice(-1)).join(',')})`);
|
|
// 13. doua chei distincte, iar consimtamantul pentru una nu o roteste pe cealalta
|
|
const c13 = await chei();
|
|
x = await executa({ actions: kmsReal }, baza('e13', { consent: 'all', execute: true }));
|
|
const r13 = kmsReal.map((a) => inreg(x).find((i) => i.ref === a.ref));
|
|
const n13 = r13.map((r) => (r && r.after ? r.after.key : null));
|
|
const noi13 = (await chei()) - c13;
|
|
cere(x.summary.ok === 2 && n13[0] && n13[1] && n13[0] !== n13[1] && noi13 === 2, `13. doua ref-uri reale din acelasi fisier -> doua chei DISTINCTE create (${n13.join(' / ')}; chei noi in KMS: ${noi13})`);
|
|
x = await executa({ actions: kmsReal }, baza('e13b', { consent: [kmsReal[0].ref], execute: true }));
|
|
const v13 = [];
|
|
for (const nume of n13) v13.push(nume ? (await kmsGet(kmsUrl, kmsToken, `/v1/keys/${encodeURIComponent(nume)}`)).j?.latest_version : null);
|
|
cere(v13[0] === 2 && v13[1] === 1, `13. consimtamant numai pentru ${kmsReal[0].ref.split(':').slice(-2).join(':')} -> cheia lui rotita (v${v13[0]}), a celuilalt NEATINSA (v${v13[1]})`);
|
|
cere(n13.every((nm) => nm && /^[a-z0-9][a-z0-9_-]{0,63}$/.test(nm)), `13. numele sunt nume KMS valide (${n13.map((nm) => (nm ? nm.length : 0)).join(', ')} caractere)`);
|
|
// 14. PKI fara cn: CN-ul implicit e un nume de gazda valid, certificatul se emite, si fiecare actiune isi scrie fisierele ei
|
|
x = await executa({ actions: pkiReal }, baza('e14', { consent: 'all', execute: true }));
|
|
const r14 = pkiReal.map((a) => inreg(x).find((i) => i.ref === a.ref));
|
|
cere(r14.every((r) => r && r.verdict === 'OK' && r.after && /\.internal$/.test(r.after.cn)), `14. PKI pe ref-uri reale fara cn: ${r14.map((r) => (r ? r.verdict + ' ' + (r.after ? r.after.cn : r.error) : '?')).join(' | ')}`);
|
|
const certs14 = r14.map((r) => pas(r, 'cert'));
|
|
cere(certs14.every(Boolean) && new Set(certs14).size === certs14.length && certs14.every((f) => fs.existsSync(f)), `14. fiecare actiune PKI isi are fisierele ei (${certs14.length} certificate, ${new Set(certs14).size} distincte)`);
|
|
} catch (e) {
|
|
rezultate.push('RAU proba nu a putut rula: ' + String(e.message).replace(/[A-Za-z0-9+/=]{48,}/g, '…').slice(0, 300)); rau++;
|
|
} finally {
|
|
for (const c of copii) { try { c.kill(); } catch {} }
|
|
// upstream-ul local tinea bucla vie: proba tiparea verdictul si nu mai iesea (rularile din fundal nu se terminau niciodata)
|
|
if (up) { try { up.closeAllConnections(); up.close(); } catch {} }
|
|
}
|
|
for (const l of rezultate) console.log(l);
|
|
if (!rau) { try { fs.rmSync(T, { recursive: true, force: true }); } catch {} }
|
|
console.log(`B1 executor: ${ok}/${ok + rau} cum trebuia`);
|
|
if (rau) console.log('dosarul de proba a ramas pentru cercetare: ' + T);
|
|
process.exitCode = rau ? 1 : 0;
|