'use strict'; // Proba motorului de politica al agentilor (B2 m2), cu CONTROALE NEGATIVE: sub limita permis, peste limita refuzat, unealta/destinatar // nepermis refuzat, iar plicul de decizie verifica sub AIP-23 si leaga policyHash (o politica schimbata -> alt hash, decizia nu se // poate atribui altei politici). 2026-09-29 (B-17): hash-ul unei politici PRIMITE se recalculeaza (o politica laxa nu poate purta // hash-ul celei reale), politica se valideaza, un alt activ decat al limitei e refuzat, actionHash-ul plicului e canonic. // node proba-agent-policy.mjs -> 0 toate cum trebuia, 1 altfel, 2 fara verificatorul AIP-23 (partea lui NEMASURATA) // Verificatorul AIP-23: AERE_VERIFY_PROOF= sau, in depozitul de dezvoltare, ../aere-proof-protocol/verify.mjs. import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { definePolicy, hashPolicy, checkAction, decisionEnvelope, canonical } from './agent-policy.mjs'; import crypto from 'node:crypto'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const VERIFY = process.env.AERE_VERIFY_PROOF || path.resolve(AICI, '..', 'aere-proof-protocol', 'verify.mjs'); const T = fs.mkdtempSync(path.join(os.tmpdir(), 'ap-')); let ok = 0, rele = 0, sarite = 0; const cer = (n, c) => { console.log(` [${c ? 'OK ' : 'RAU '}] ${n}`); c ? ok++ : rele++; }; const arunca = (fn) => { try { fn(); return null; } catch (e) { return e.message; } }; const verdict = (p) => { try { return JSON.parse(execFileSync(process.execPath, [VERIFY, p, '--json'], { encoding: 'utf8' })).verdict; } catch (e) { try { return JSON.parse(e.stdout || '').verdict; } catch { return '?'; } } }; try { const { policy, policyHash } = definePolicy({ agentId: 'agent-1', spend: { amount: '100', windowSeconds: 3600 }, tools: ['retrieval', 'calc'], recipients: ['0xBBBB'] }); cer('policyHash e digest 0x+64', /^0x[0-9a-f]{64}$/.test(policyHash)); // unelte cer('unealta permisa -> allowed', checkAction(policy, { kind: 'tool', tool: 'retrieval', at: 1 }).allowed === true); cer('CONTROL: unealta nepermisa -> denied, cu motivul in engleza', /is not in the allowed list/.test(checkAction(policy, { kind: 'tool', tool: 'shell', at: 1 }).reason)); // cheltuiala cer('plata sub limita, destinatar permis -> allowed', checkAction(policy, { kind: 'payment', to: '0xbbbb', amount: '40', at: 1000 }, [{ amount: '30', at: 999 }]).allowed === true); const peste = checkAction(policy, { kind: 'payment', to: '0xbbbb', amount: '80', at: 1000 }, [{ amount: '30', at: 999 }]); cer(`CONTROL: plata care depaseste limita in fereastra -> denied (${peste.reason})`, peste.allowed === false && /over the limit: 110 > 100/.test(peste.reason)); cer('CONTROL: destinatar nepermis -> denied', checkAction(policy, { kind: 'payment', to: '0xCCCC', amount: '10', at: 1000 }, []).allowed === false); cer('cheltuiala veche (in afara ferestrei) nu conteaza', checkAction(policy, { kind: 'payment', to: '0xbbbb', amount: '90', at: 100000 }, [{ amount: '90', at: 1 }]).allowed === true); // activul: implicit al limitei; altul e refuzat, nu adunat cer('plata cu activul politicii (AERE) scris explicit -> allowed', checkAction(policy, { kind: 'payment', to: '0xbbbb', amount: '10', asset: 'AERE', at: 1 }).allowed === true); const altActiv = checkAction(policy, { kind: 'payment', to: '0xbbbb', amount: '10', asset: 'USDC', at: 1 }); cer(`CONTROL: plata in alt activ decat al limitei -> denied (${altActiv.reason})`, !altActiv.allowed && /not the policy's asset/.test(altActiv.reason)); // portofelul numit (2026-09-29): o plata trebuie sa spuna `from` si sa fie chiar el const cuPortofel = definePolicy({ agentId: 'agent-1', spend: { amount: '100', windowSeconds: 3600 }, wallet: '0xAbCd00000000000000000000000000000000Ef01' }).policy; cer('portofelul politicii e scris cu litere mici', cuPortofel.wallet === '0xabcd00000000000000000000000000000000ef01'); cer('plata din portofelul numit (orice litere) -> allowed', checkAction(cuPortofel, { kind: 'payment', to: '0xbbbb', amount: '10', from: '0xABCD00000000000000000000000000000000EF01', at: 1 }).allowed === true); const fara = checkAction(cuPortofel, { kind: 'payment', to: '0xbbbb', amount: '10', at: 1 }); const dinAlt = checkAction(cuPortofel, { kind: 'payment', to: '0xbbbb', amount: '10', from: '0x1111111111111111111111111111111111111111', at: 1 }); cer(`CONTROL: plata fara from, sau din alt portofel, sub o politica ce numeste portofelul -> denied (${dinAlt.reason})`, !fara.allowed && !dinAlt.allowed && /not from the wallet/.test(dinAlt.reason)); cer('CONTROL: un portofel care nu e adresa EVM -> politica refuzata', /wallet must be an EVM address/.test(arunca(() => definePolicy({ agentId: 'a', wallet: '0x12' })) || '')); // validarea politicii cer('CONTROL: spend.amount care nu e intreg -> politica refuzata', /spend.amount/.test(arunca(() => definePolicy({ agentId: 'a', spend: { amount: '1e9', windowSeconds: 60 } })) || '')); cer('CONTROL: fereastra zero -> politica refuzata', /windowSeconds/.test(arunca(() => definePolicy({ agentId: 'a', spend: { amount: '1', windowSeconds: 0 } })) || '')); // hashPolicy: hash-ul unei politici PRIMITE se recalculeaza const dinFisier = JSON.parse(JSON.stringify(policy)); cer('hashPolicy pe politica citita dintr-un fisier = hash-ul definePolicy', hashPolicy(dinFisier).policyHash === policyHash); const reordonata = Object.fromEntries(Object.entries(dinFisier).reverse()); cer('hashPolicy nu depinde de ordinea cheilor din fisier', hashPolicy(reordonata).policyHash === policyHash); const laxa = { ...dinFisier, spend: { ...dinFisier.spend, amount: '1000000' } }; cer('CONTROL: o politica LAXA are alt hash (nu poate purta hash-ul celei reale)', hashPolicy(laxa).policyHash !== policyHash); cer('CONTROL: un camp necunoscut in politica -> refuzat', /unknown policy field/.test(arunca(() => hashPolicy({ ...dinFisier, bypass: true })) || '')); cer('politicile de dinainte de 2026-09-29 pastreaza hash-ul (forma normala neschimbata)', definePolicy({ agentId: 'agent-7', spend: { amount: '100', windowSeconds: 3600, asset: 'AERE' }, tools: ['search'], recipients: null }).policyHash === '0xc7d983a9886a0899bd6f3f09fde526514b0075f8f6abe77a1886405d86048c27'); // plic de decizie const act = { kind: 'payment', to: '0xbbbb', amount: '80', at: 1000 }; const dec = checkAction(policy, act, [{ amount: '30', at: 999 }]); const env = decisionEnvelope({ policyHash, action: act, decision: dec, createdAt: '2026-09-26T09:00:00Z' }); cer('plicul leaga policyHash', env.statement.policyHash === policyHash); cer('plicul spune allowed=false (decizia reala)', env.statement.allowed === false); const inversa = { at: 1000, amount: '80', to: '0xbbbb', kind: 'payment' }; cer('actionHash e canonic: aceeasi actiune cu cheile in alta ordine -> acelasi digest', decisionEnvelope({ policyHash, action: inversa, decision: dec, createdAt: '2026-09-26T09:00:00Z' }).statement.actionHash === env.statement.actionHash); cer('actionHash = sha256 peste JSON-ul canonic al actiunii (reproductibil de un strain)', env.statement.actionHash === '0x' + crypto.createHash('sha256').update(canonical(act)).digest('hex')); if (fs.existsSync(VERIFY)) { const f = path.join(T, 'dec.json'); fs.writeFileSync(f, JSON.stringify(env, null, 1)); cer('plicul de decizie verifica sub AIP-23', verdict(f) === 'VALID'); const rau = JSON.parse(JSON.stringify(env)); rau.statement.allowed = true; const f2 = path.join(T, 'rau.json'); fs.writeFileSync(f2, JSON.stringify(rau)); cer('CONTROL: plicul cu decizia rescrisa nu mai verifica sub AIP-23', verdict(f2) !== 'VALID'); } else { sarite += 2; console.log(` [SARIT] plicul sub AIP-23 (2 probe): verificatorul nu e la ${VERIFY}; AERE_VERIFY_PROOF=`); } // o politica schimbata -> alt hash (decizia nu se poate atribui altei politici) const alt = definePolicy({ agentId: 'agent-1', spend: { amount: '1000000', windowSeconds: 3600 }, tools: ['retrieval'], recipients: ['0xBBBB'] }); cer('CONTROL: politica cu alta limita -> alt policyHash', alt.policyHash !== policyHash); } finally { fs.rmSync(T, { recursive: true, force: true }); } console.log(`\nagent-policy: ${ok}/${ok + rele} cum trebuia${sarite ? `, ${sarite} NEMASURATE (fara verificatorul AIP-23)` : ''}`); process.exitCode = rele ? 1 : (sarite ? 2 : 0);