@aere/cloud 1.4.0: auditExport({ day, format }): the audit log of a day as a file (jsonl = the exact bytes whose sha256 you notarize, verified locally; cef for a SIEM)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Liviu 2026-09-18 15:15:19 +03:00
parent ade68667c0
commit 53fd47b23b
4 changed files with 34 additions and 1 deletions

View File

@ -49,6 +49,8 @@ const attested = await aere.readiness('example.com', { attest: true }); // + att
const perimeter = await aere.readinessPerimeter('example.com', { hosts: ['api', 'mail'] }); const perimeter = await aere.readinessPerimeter('example.com', { hosts: ['api', 'mail'] });
// perimeter.summary: { measured, withoutPqKeyExchange: [...], soonestCertificateExpiry, worstScore, verdict, complete } // perimeter.summary: { measured, withoutPqKeyExchange: [...], soonestCertificateExpiry, worstScore, verdict, complete }
// while summary.complete is false, call again: finished scans are cached; { attest: true } notarizes a complete report // while summary.complete is false, call again: finished scans are cached; { attest: true } notarizes a complete report
// the audit log of a day as a FILE (1.4.0): the exact bytes whose sha256 is the digest you notarize; format: 'cef' for a SIEM
const file = await aere.auditExport({ day: '2026-09-17' }); // file.verified === true: sha256(file.bytes) is the stated digest
const fin = await aere.pqFinality('latest', 'testnet', 'both'); // AIP-21: { finality, agreement, postQuantumConfirmedByBoth, besu: {…}, nethermind: {…} } const fin = await aere.pqFinality('latest', 'testnet', 'both'); // AIP-21: { finality, agreement, postQuantumConfirmedByBoth, besu: {…}, nethermind: {…} }
// pqVerify: pass interface:'external' to verify a standard FIPS 204/205 signature (the precompile implements the // pqVerify: pass interface:'external' to verify a standard FIPS 204/205 signature (the precompile implements the

View File

@ -107,6 +107,19 @@ export class AereCloud {
if (day) q.set('day', day); if (day) q.set('day', day);
return this._req('GET', `/account/audit?${q}`); return this._req('GET', `/account/audit?${q}`);
} }
// the same day as a file (1.4.0): format 'jsonl' = the EXACT bytes of the day file, whose sha256 is the digest you notarize
// (`verified` says the bytes you received hash to the digest the gateway states); 'cef' = one ArcSight CEF line per request
// for a SIEM, carrying the digest of the source file. Returns { day, format, bytes, text, entries, digest, verified }.
async auditExport({ day, format = 'jsonl' } = {}) {
const q = new URLSearchParams({ format }); if (day) q.set('day', day);
const r = await this._req('GET', `/account/audit?${q}`, { raw: true });
if (!r.ok) { let d = null; try { d = await r.json(); } catch { /* non-JSON */ } throw new AereCloudError(r.status, d, '/account/audit'); }
const bytes = new Uint8Array(await r.arrayBuffer());
const digest = r.headers.get('x-aere-digest');
const local = '0x' + [...new Uint8Array(await globalThis.crypto.subtle.digest('SHA-256', bytes))].map((b) => b.toString(16).padStart(2, '0')).join('');
return { day: r.headers.get('x-aere-day'), format, bytes, text: new TextDecoder().decode(bytes), entries: Number(r.headers.get('x-aere-entries') || 0), digest,
verified: format === 'jsonl' ? local === digest : null };
}
// ---- webhooks ---- // ---- webhooks ----
listWebhooks() { return this._req('GET', '/webhooks'); } listWebhooks() { return this._req('GET', '/webhooks'); }

View File

@ -1,6 +1,6 @@
{ {
"name": "@aere/cloud", "name": "@aere/cloud",
"version": "1.3.0", "version": "1.4.0",
"description": "Official client for the Aere Cloud API: keyed RPC, post-quantum verification, chain data, notarization, webhooks and gas sponsorship on Aere Network (chain 2800).", "description": "Official client for the Aere Cloud API: keyed RPC, post-quantum verification, chain data, notarization, webhooks and gas sponsorship on Aere Network (chain 2800).",
"type": "module", "type": "module",
"main": "index.mjs", "main": "index.mjs",

View File

@ -113,6 +113,24 @@ await test('2026-09-18: readinessPerimeter(): ruta cu cheie, corpul poarta doar
await assert.rejects(() => c409.readinessPerimeter('example.com', { attest: true }), (e) => e.status === 409); await assert.rejects(() => c409.readinessPerimeter('example.com', { attest: true }), (e) => e.status === 409);
}); });
await test('2026-09-18: auditExport(): octetii zilei + digestul din antet; verified=true cand octetii dau digestul, FALSE cand nu il dau; cef nu pretinde verificare; un 400 ajunge la apelant', async () => {
const { createHash } = await import('node:crypto');
const corp = Buffer.from('{"t":"2026-09-17T10:00:00.000Z","m":"GET","p":"/v1/account","s":200}\n');
const d = '0x' + createHash('sha256').update(corp).digest('hex');
const raspuns = (octeti, digest, status = 200) => async (url, init) => new Response(octeti, { status, headers: { 'x-aere-digest': digest, 'x-aere-day': '2026-09-17', 'x-aere-entries': '1' } });
const vazute = [];
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: async (u, i) => { vazute.push({ u, cheie: !!i.headers['x-api-key'] }); return raspuns(corp, d)(u, i); } });
const e = await c.auditExport({ day: '2026-09-17' });
assert.equal(e.verified, true); assert.equal(e.digest, d); assert.equal(e.entries, 1); assert.equal(e.text, corp.toString('utf8')); assert.equal(vazute[0].cheie, true);
assert.ok(vazute[0].u.endsWith('/account/audit?format=jsonl&day=2026-09-17'), vazute[0].u);
const stricat = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: raspuns(Buffer.from('alti octeti'), d) });
assert.equal((await stricat.auditExport({ day: '2026-09-17' })).verified, false, 'octeti care nu dau digestul declarat nu au voie sa iasa verified');
const cef = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: raspuns(Buffer.from('CEF:0|x\n'), d) });
assert.equal((await cef.auditExport({ day: '2026-09-17', format: 'cef' })).verified, null, 'pentru cef digestul e al fisierului-sursa, nu al textului primit');
const rau = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: async () => new Response(JSON.stringify({ error: 'bad_format' }), { status: 400 }) });
await assert.rejects(() => rau.auditExport({ format: 'xml' }), (x) => x.status === 400);
});
await test('verifyWebhook: semnatura buna trece, una gresita pica, o litera in plus pica', async () => { await test('verifyWebhook: semnatura buna trece, una gresita pica, o litera in plus pica', async () => {
const secret = 'AERE-SINTETIC-secretul-meu'; const secret = 'AERE-SINTETIC-secretul-meu';
const corp = JSON.stringify({ event: 'pq-anchor', data: { height: 42 } }); const corp = JSON.stringify({ event: 'pq-anchor', data: { height: 42 } });