// Proof of Software 1.3.0: identitatea constructorului (acreditarea de dezvoltator emisa de o organizatie). Fiecare afirmatie cu // perechea ei negativa. Offline: lantul e un obiect `cloud` injectat care raspunde ca Aere Cloud (numai pentru timpul de pe lant). // node test/credential.test.mjs iesire 0 = toate cum trebuia 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 { attest, verify, issueCredential, revokeCredential, publicKeysOf } from '../pos.mjs'; import * as pq from '../../../sdk-pq-sign/index.mjs'; const AICI = path.dirname(fileURLToPath(import.meta.url)); let treceri = 0; const esecuri = []; async function test(nume, fn) { try { await fn(); treceri++; console.log(' OK ' + nume); } catch (e) { esecuri.push(nume); console.log(' ESEC ' + nume + ' — ' + (e.message || e)); } } const cere = (c, m) => { if (!c) throw new Error(m); }; const check = (r, re) => r.checks.find((c) => re.test(c.name)); const D = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-pos-cred-')); const A = path.join(D, 'app.tgz'); fs.writeFileSync(A, 'artifact bytes'); const org = pq.generateKeyPair(), alt = pq.generateKeyPair(), dev = pq.generateKeyPair(), strain = pq.generateKeyPair(); const cred = issueCredential({ issuerKeys: org, issuerName: 'Example Org', subjectKeys: publicKeysOf(dev), subjectName: 'Ana Dev', validFrom: '2026-01-01T00:00:00Z', validUntil: '2027-01-01T00:00:00Z' }); const acum = new Date('2026-06-01T00:00:00Z'); const att = await attest({ artifacts: [A], name: 'app', version: '1.0.0', keys: dev, credential: cred, cwd: D, now: acum }); await test('1. atestare sub acreditare, verificata cu radacina de incredere a organizatiei: VALIDA, identitatea judecata pe fiecare punct', async () => { const r = await verify(att, [A], { trustIssuer: publicKeysOf(org) }); cere(r.valid, JSON.stringify(r.checks.filter((c) => c.pass === false))); for (const re of [/carries the credential/, /signed by the issuer/, /trust root you gave/, /names the keys that signed/]) cere(check(r, re) && check(r, re).pass === true, 'lipseste sau nu trece: ' + re); cere(/createdAt, declared by the builder/.test(check(r, /valid at/).name), 'timpul folosit trebuie numit'); // 2026-09-29 (B-18): pe data declarata, "in valabilitate" nu se poate crede (o alege cine tine cheile): nejudecat, nu trecut cere(check(r, /valid at/).pass === null, 'pe data declarata, valabilitatea trebuie raportata nejudecata'); }); await test('2. CONTROL: alta radacina de incredere (alta organizatie) -> INVALIDA', async () => { const r = await verify(att, [A], { trustIssuer: publicKeysOf(alt) }); cere(!r.valid && check(r, /trust root/).pass === false, 'trebuia sa pice pe emitent'); }); await test('3. fara radacina de incredere: emitentul NU e judecat, si se spune (nu e trecut drept incredere)', async () => { const r = await verify(att, [A]); cere(check(r, /issuer trust/) && check(r, /issuer trust/).pass === null, 'trebuia raportat nejudecat'); }); await test('4. CONTROL: attest cu o acreditare care numeste alte chei decat --keys e refuzat', async () => { let aruncat = null; try { await attest({ artifacts: [A], keys: strain, credential: cred, cwd: D }); } catch (e) { aruncat = e.message; } cere(/other keys/.test(aruncat || ''), 'trebuia refuzat: ' + aruncat); }); await test('5. CONTROL: acreditarea inlocuita in atestare (declaratia numeste alta) -> INVALIDA', async () => { const alta = issueCredential({ issuerKeys: org, issuerName: 'Example Org', subjectKeys: publicKeysOf(dev), subjectName: 'Altcineva', validFrom: '2026-01-01T00:00:00Z', validUntil: '2027-01-01T00:00:00Z' }); const r = await verify({ ...att, credential: alta }, [A], { trustIssuer: publicKeysOf(org) }); cere(!r.valid && check(r, /carries the credential/).pass === false, 'trebuia prins'); }); await test('6. CONTROL: o acreditare care numeste organizatia dar e semnata de un strain -> INVALIDA (semnatarul nu e emitentul numit)', async () => { const fals = issueCredential({ issuerKeys: strain, issuerName: 'Example Org', subjectKeys: publicKeysOf(dev), subjectName: 'Ana Dev', validFrom: '2026-01-01T00:00:00Z', validUntil: '2027-01-01T00:00:00Z' }); fals.body.issuer.keys = publicKeysOf(org); fals.signature = pq.sign(JSON.stringify(fals.body), strain); const a2 = await attest({ artifacts: [A], keys: dev, credential: fals, cwd: D, now: acum }); const r = await verify(a2, [A], { trustIssuer: publicKeysOf(org) }); cere(!r.valid && check(r, /signed by the issuer/).pass === false, 'trebuia prins'); }); await test('7. CONTROL: declaratia semnata de alte chei decat cele din acreditare -> INVALIDA', async () => { const a2 = JSON.parse(JSON.stringify(att)); a2.signature = pq.sign(JSON.stringify(a2.statement), strain); const r = await verify(a2, [A], { trustIssuer: publicKeysOf(org) }); cere(!r.valid && check(r, /names the keys that signed/).pass === false, 'trebuia prins'); }); await test('8. CONTROL: momentul atestarii in afara valabilitatii -> INVALIDA', async () => { const a2 = await attest({ artifacts: [A], keys: dev, credential: cred, cwd: D, now: new Date('2027-03-01T00:00:00Z') }); const r = await verify(a2, [A], { trustIssuer: publicKeysOf(org) }); cere(!r.valid && check(r, /valid at/).pass === false, 'trebuia prins'); }); await test('9. revocarea: inaintea atestarii -> INVALIDA; dupa ea -> VALIDA; semnata de alt emitent -> ignorata si spusa', async () => { const inainte = revokeCredential({ issuerKeys: org, credential: cred, revokedAt: '2026-05-01T00:00:00Z', reason: 'cheie pierduta' }); const dupa = revokeCredential({ issuerKeys: org, credential: cred, revokedAt: '2026-07-01T00:00:00Z' }); const straina = revokeCredential({ issuerKeys: alt, credential: cred, revokedAt: '2026-02-01T00:00:00Z' }); const r1 = await verify(att, [A], { trustIssuer: publicKeysOf(org), revocations: [inainte] }); cere(!r1.valid && check(r1, /not revoked/).pass === false, 'revocarea de dinainte trebuia sa pice'); const r2 = await verify(att, [A], { trustIssuer: publicKeysOf(org), revocations: [dupa] }); cere(r2.valid && check(r2, /not revoked/).pass === null, 'revocarea de dupa nu acuza atestarea, dar pe data declarata nici nu o achita (B-18)'); const r3 = await verify(att, [A], { trustIssuer: publicKeysOf(org), revocations: [straina] }); cere(r3.valid && check(r3, /a revocation/).pass === null, 'o revocare straina se ignora si se spune'); const r4 = await verify(att, [A], { trustIssuer: publicKeysOf(org) }); // AERE-SINTETIC: nu e un secret; 'credential: revocations' e numele unei verificari cere(check(r4, /credential: revocations/).pass === null, 'fara revocari date, se spune ca nu s-a putut vedea'); }); await test('10. timpul de pe LANT bate data declarata: un constructor care isi antedateaza atestarea sub o acreditare expirata e prins', async () => { // createdAt declarat 2026-06-01 (in valabilitate), dar lantul a vazut-o prima oara pe 2027-02-01 (dupa expirare) const a2 = JSON.parse(JSON.stringify(att)); a2.notarization = { block: 123, txHash: '0x' + 'ab'.repeat(32) }; const cloud = { proof: async () => ({ notarized: true, block: 123, txHash: '0x' + 'ab'.repeat(32), firstSeenAt: Date.parse('2027-02-01T00:00:00Z') / 1000, finality: 'post-quantum', pqAnchor: null }) }; const r = await verify(a2, [A], { trustIssuer: publicKeysOf(org), cloud }); cere(!r.valid && check(r, /valid at/).pass === false && /first seen on chain/.test(check(r, /valid at/).name), JSON.stringify(check(r, /valid at/))); const cloudBun = { proof: async () => ({ notarized: true, block: 123, txHash: '0x' + 'ab'.repeat(32), firstSeenAt: Date.parse('2026-06-02T00:00:00Z') / 1000, finality: 'post-quantum', pqAnchor: null }) }; const rb = await verify(a2, [A], { trustIssuer: publicKeysOf(org), cloud: cloudBun }); cere(rb.valid && /first seen on chain/.test(check(rb, /valid at/).name), 'cu timpul lantului in valabilitate trebuia VALIDA'); }); await test('11. CLI cap la cap: pubkey, credential issue, attest --credential, verify --trust-issuer (0), alt emitent (1), revocare (1)', async () => { const pos = path.join(AICI, '..', 'pos.mjs'); const f = (n) => path.join(D, n); fs.writeFileSync(f('org.json'), JSON.stringify(org)); fs.writeFileSync(f('dev.json'), JSON.stringify(dev)); fs.writeFileSync(f('alt.json'), JSON.stringify(alt)); const run = (args) => { try { execFileSync(process.execPath, [pos, ...args], { cwd: D, stdio: 'pipe' }); return 0; } catch (e) { return e.status; } }; cere(run(['pubkey', '--keys', f('org.json'), '--out', f('org.pub.json')]) === 0 && run(['pubkey', '--keys', f('dev.json'), '--out', f('dev.pub.json')]) === 0 && run(['pubkey', '--keys', f('alt.json'), '--out', f('alt.pub.json')]) === 0, 'pubkey'); cere(!('secretKey' in (JSON.parse(fs.readFileSync(f('org.pub.json'), 'utf8')).classical || {})) && !JSON.stringify(JSON.parse(fs.readFileSync(f('org.pub.json'), 'utf8'))).includes(org.pq.secretKey), 'fisierul public nu are voie sa poarte cheia secreta'); cere(run(['credential', 'issue', '--issuer-keys', f('org.json'), '--issuer-name', 'Example Org', '--subject-pub', f('dev.pub.json'), '--subject-name', 'Ana Dev', '--valid-days', '30', '--out', f('cred.json')]) === 0, 'credential issue'); cere(run(['attest', '--out', f('att.json'), '--keys', f('dev.json'), '--credential', f('cred.json'), A]) === 0, 'attest'); cere(run(['verify', f('att.json'), '--trust-issuer', f('org.pub.json'), A]) === 0, 'verify cu emitentul bun'); cere(run(['verify', f('att.json'), '--trust-issuer', f('alt.pub.json'), A]) === 1, 'CONTROL: verify cu alt emitent'); cere(run(['credential', 'revoke', '--issuer-keys', f('org.json'), '--credential', f('cred.json'), '--at', '2020-01-01T00:00:00Z', '--out', f('rev.json')]) === 0, 'credential revoke'); cere(run(['verify', f('att.json'), '--trust-issuer', f('org.pub.json'), '--revocations', f('rev.json'), A]) === 1, 'CONTROL: verify cu revocarea'); }); await test('12. B-18: cu cheile unei acreditari REVOCATE, o atestare antedatata inaintea revocarii NU mai trece drept nerevocata; cu timpul lantului dupa revocare e prinsa, inainte e trecuta', async () => { const rev = revokeCredential({ issuerKeys: org, credential: cred, revokedAt: '2026-09-01T00:00:00Z', reason: 'the keys left the company' }); // hotul semneaza in octombrie, declara iunie const r = await verify(att, [A], { trustIssuer: publicKeysOf(org), revocations: [rev] }); cere(check(r, /not revoked/).pass === null && check(r, /valid at/).pass === null, 'pe data declarata, revocarea si valabilitatea trebuie raportate nejudecate: ' + JSON.stringify(check(r, /not revoked/))); const a2 = JSON.parse(JSON.stringify(att)); a2.notarization = { block: 7, txHash: '0x' + 'cd'.repeat(32) }; const lant = (iso) => ({ proof: async () => ({ notarized: true, block: 7, txHash: '0x' + 'cd'.repeat(32), firstSeenAt: Date.parse(iso) / 1000, finality: 'post-quantum', pqAnchor: null }) }); const rDupa = await verify(a2, [A], { trustIssuer: publicKeysOf(org), revocations: [rev], cloud: lant('2026-10-02T00:00:00Z') }); cere(!rDupa.valid && check(rDupa, /not revoked/).pass === false, 'lantul a vazut-o dupa revocare: trebuia prinsa'); const rInainte = await verify(a2, [A], { trustIssuer: publicKeysOf(org), revocations: [rev], cloud: lant('2026-06-02T00:00:00Z') }); cere(rInainte.valid && check(rInainte, /not revoked/).pass === true && check(rInainte, /valid at/).pass === true, 'lantul a vazut-o inainte de revocare, in valabilitate: trecuta'); }); fs.rmSync(D, { recursive: true, force: true }); console.log(`\n${treceri} treceri, ${esecuri.length} esecuri`); process.exitCode = esecuri.length ? 1 : 0;