// Proba liniei de comanda a agentilor (agent-cli.mjs), rulata ca un strain: numai fisiere si procese, fara importul modulelor. Fiecare // drum are perechea lui negativa. Offline; chei ML-DSA-65 reale, generate aici si sterse la sfarsit. // node proba-agent-cli.mjs iesire 0 = toate cum trebuia import fs from 'node:fs'; import os from 'node:os'; 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 CLI = path.join(AICI, 'agent-cli.mjs'); const T = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-agent-cli-')); const f = (n) => path.join(T, n); let ok = 0, rau = 0; const cer = (c, ce) => { console.log((c ? ' OK ' : ' RAU ') + ce); c ? ok++ : rau++; }; const run = (...a) => { const r = spawnSync(process.execPath, [CLI, ...a], { encoding: 'utf8', timeout: 60000 }); return { cod: r.status, out: (r.stdout || '').trim(), err: (r.stderr || '').trim() }; }; const scrie = (n, o) => { fs.writeFileSync(f(n), JSON.stringify(o)); return f(n); }; // iesirea unei comenzi citita ca JSON; o comanda cazuta (iesire goala) da {} si proba iese ROSIE, nu se opreste (STRICAT) const J = (s) => { try { return JSON.parse(s); } catch { return {}; } }; try { // identitati const ra = run('id', '--out', f('agent')); const [h1, h2, h3, own] = ['h1', 'h2', 'h3', 'own'].map((n) => run('human', '--out', f(n))); cer(ra.cod === 0 && /^aere-agent:[0-9a-f]{40}$/.test(ra.out) && [h1, h2, h3, own].every((r) => r.cod === 0 && /^aere-human:[0-9a-f]{40}$/.test(r.out)), '1. id si human scriu cheile si tiparesc numai id-ul'); cer(![ra, h1].some((r) => /PRIVATE KEY/.test(r.out + r.err)), '1. nicio cheie privata pe iesire'); cer(run('id', '--out', f('agent')).cod === 2, '1. CONTROL: o cheie existenta nu se suprascrie (cod 2)'); if (process.platform !== 'win32') cer((fs.statSync(f('agent/agent.key.pem')).mode & 0o777) === 0o600, '1. cheia privata are drepturile 0600'); // politica: 1000 pe ora, aprobare 2 din 3 peste 100, proprietar const spec = scrie('spec.json', { agentId: ra.out, spend: { amount: '1000', windowSeconds: 3600 }, recipients: ['0xbbbb'], approval: { approvers: [h1.out, h2.out, h3.out], threshold: 2, above: '100' }, owner: own.out }); const rp = run('policy', '--spec', spec, '--out', f('p.json')); const P = JSON.parse(fs.readFileSync(f('p.json'), 'utf8')); cer(rp.cod === 0 && rp.out === P.policyHash && /^0x[0-9a-f]{64}$/.test(P.policyHash), '2. policy scrie politica normala si hash-ul ei'); // check const a50 = scrie('a50.json', { kind: 'payment', to: '0xbbbb', amount: '50' }); const a500 = scrie('a500.json', { kind: 'payment', to: '0xbbbb', amount: '500' }); cer(run('check', '--policy', f('p.json'), '--action', a50).cod === 0, '3. check: 50 -> permis (0)'); cer(run('check', '--policy', f('p.json'), '--action', scrie('a2000.json', { kind: 'payment', to: '0xbbbb', amount: '2000' })).cod === 3, '3. CONTROL: check 2000 peste limita -> refuzat (3)'); // record, cu reluarea registrului din fisier const L = f('ledger.json'); const r1 = run('record', '--key', f('agent/agent.key.pem'), '--policy', f('p.json'), '--ledger', L, '--action', a50); cer(r1.cod === 0 && fs.existsSync(L) && J(r1.out).seq === 0, '4. record 50 -> permis, registrul creat (seq 0)'); const r2 = run('record', '--key', f('agent/agent.key.pem'), '--policy', f('p.json'), '--ledger', L, '--action', a500); cer(r2.cod === 3 && /0 of 2/.test(J(r2.out).reason) && J(r2.out).seq === 1, '4. CONTROL: record 500 fara aprobari -> refuzat (3), scris ca refuz la seq 1'); // aprobari const ap1 = run('approve', '--key', f('h1/human.key.pem'), '--policy', f('p.json'), '--action', a500, '--out', f('ap1.json')); const ap2 = run('approve', '--key', f('h2/human.key.pem'), '--policy', f('p.json'), '--action', a500, '--out', f('ap2.json')); cer(ap1.cod === 0 && ap2.cod === 0, '5. doi aprobatori numiti semneaza aprobarea pentru 500'); cer(run('approve', '--key', f('own/human.key.pem'), '--policy', f('p.json'), '--action', a500, '--out', f('ap-own.json')).cod === 1, '5. CONTROL: proprietarul, care nu e aprobator, nu poate aproba (1)'); const r3 = run('record', '--key', f('agent/agent.key.pem'), '--policy', f('p.json'), '--ledger', L, '--action', a500, '--approvals', `${f('ap1.json')},${f('ap2.json')}`); cer(r3.cod === 0 && /approved by 2 of 2/.test(J(r3.out).reason), '5. record 500 cu cele doua aprobari -> permis'); const r4 = run('record', '--key', f('agent/agent.key.pem'), '--policy', f('p.json'), '--ledger', L, '--action', a500, '--approvals', `${f('ap1.json')},${f('ap2.json')}`); cer(r4.cod === 3 && (J(r4.out).rejectedApprovals || [0]).every((m) => /nonce already used/.test(m)), '5. CONTROL: aceleasi aprobari a doua oara (registrul reluat din fisier) -> respinse'); const a600 = scrie('a600.json', { kind: 'payment', to: '0xbbbb', amount: '600' }); const ap3 = run('approve', '--key', f('h1/human.key.pem'), '--policy', f('p.json'), '--action', a600, '--out', f('ap3.json')); const ap4 = run('approve', '--key', f('h3/human.key.pem'), '--policy', f('p.json'), '--action', a600, '--out', f('ap4.json')); const r5 = run('record', '--key', f('agent/agent.key.pem'), '--policy', f('p.json'), '--ledger', L, '--action', a600, '--approvals', `${f('ap3.json')},${f('ap4.json')}`); cer(ap3.cod === 0 && ap4.cod === 0 && r5.cod === 3 && /over the limit/.test(J(r5.out).reason), '5. aprobarea nu scuteste de limita, si cheltuiala se tine peste reluari: 50+500+600 > 1000 -> refuzat'); // verificarea ca un strain const v = run('verify', '--ledger', L, '--policy', f('p.json')); cer(v.cod === 0 && J(v.out).spent === '550' && J(v.out).humanApproved === 1, '6. verify: registrul verifica, cheltuit 550, o actiune aprobata de oameni'); const atins = JSON.parse(fs.readFileSync(L, 'utf8')); atins.entries[0].body.action.amount = '1'; cer(run('verify', '--ledger', scrie('atins.json', atins), '--policy', f('p.json')).cod === 1, '6. CONTROL: un registru atins -> 1'); const lax = { policy: { ...P.policy, spend: { ...P.policy.spend, amount: '1000000' } }, policyHash: P.policyHash }; const vl = run('verify', '--ledger', L, '--policy', scrie('lax.json', lax)); cer(vl.cod === 1 && /does not hash to the pinned policyHash/.test(vl.out), '6. CONTROL: o politica laxa purtand hash-ul celei reale -> 1'); // revocarea const t0 = Math.floor(Date.now() / 1000) - 3000; const rv = run('revoke', '--key', f('own/human.key.pem'), '--policy', f('p.json'), '--at', String(t0), '--reason', 'test', '--out', f('rv.json')); cer(rv.cod === 0 && fs.existsSync(f('rv.json')), '7. revoke de catre proprietar -> revocare scrisa'); cer(run('revoke', '--key', f('h1/human.key.pem'), '--policy', f('p.json'), '--out', f('rv-rau.json')).cod === 1, '7. CONTROL: revoke cu cheia unui aprobator -> 1'); const vr = run('verify', '--ledger', L, '--policy', f('p.json'), '--revocations', f('rv.json')); cer(vr.cod === 1 && /revoked/.test(vr.out), '7. verify cu revocarea proprietarului (de dinaintea platilor) -> 1'); // echivocarea: doua continuari diferite ale aceluiasi registru const A = f('ramura-a.json'), B = f('ramura-b.json'); fs.copyFileSync(L, A); fs.copyFileSync(L, B); const a10 = scrie('a10.json', { kind: 'payment', to: '0xbbbb', amount: '10' }), a20 = scrie('a20.json', { kind: 'payment', to: '0xbbbb', amount: '20' }); run('record', '--key', f('agent/agent.key.pem'), '--policy', f('p.json'), '--ledger', A, '--action', a10); run('record', '--key', f('agent/agent.key.pem'), '--policy', f('p.json'), '--ledger', B, '--action', a20); const e = run('equivocation', '--a', A, '--b', B, '--out', f('dovada.json')); cer(e.cod === 0 && J(e.out).found === true && run('verify-equivocation', '--proof', f('dovada.json')).cod === 0, '8. doua ramuri ale aceluiasi registru -> dovada de echivocare, verificata'); cer(run('equivocation', '--a', A, '--b', L).cod === 1, '8. CONTROL: un registru si prefixul lui nu sunt echivocare (1)'); const d = JSON.parse(fs.readFileSync(f('dovada.json'), 'utf8')); d.b.body.action.amount = '21'; cer(run('verify-equivocation', '--proof', scrie('dovada-rea.json', d)).cod === 1, '8. CONTROL: o dovada cu o intrare nesemnata -> 1'); // folosire gresita cer(run('nimic').cod === 2 && run('verify', '--ledger', L).cod === 2, '9. CONTROL: comanda necunoscuta sau argument lipsa -> 2'); } catch (e) { // un fisier care trebuia scris de o comanda si lipseste: drumul s-a rupt, deci proba e ROSIE cu motivul, nu tacuta cer(false, `proba s-a oprit la un pas al carui fisier lipseste: ${e.message}`); } finally { fs.rmSync(T, { recursive: true, force: true }); } console.log(`\nagent-cli: ${ok}/${ok + rau} ${rau ? 'CU ESECURI' : 'cum trebuia'}`); process.exitCode = rau ? 1 : 0;