/** * Phase 7C-L1c — hosted delegation store persistence (Netlify Blobs). * * Tiers: unit, integration, e2e, stress, data-integrity, performance, security. */ import { describe, it, beforeEach, afterEach } from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { DELEGATION_BLOB_FILES, delegationBlobKey, hydrateDelegationStoresFromBlob, mergeGrantsStoreJson, persistDelegationStoresToBlob, withDelegationBlobSync, } from '../hub/bridge/delegation-blob-store.mjs'; import { DELEGATION_CONSENTS_FILE, DELEGATION_GRANTS_FILE, handleDelegationGrantMintRequest, seedDelegationFixtures, } from '../lib/agent/delegation.mjs'; import { writeDelegationPolicy, makeAgentIdentity, makeDelegationConsent } from './fixtures/agent/delegation-helpers.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-delegation-l1c'); /** @returns {Map & { get: (k: string, o?: { type?: string }) => Promise, set: (k: string, v: string) => Promise }} */ function makeMockBlobStore() { const map = new Map(); return { async get(key, opts) { const v = map.get(key); if (v == null) return null; return opts?.type === 'text' || typeof v === 'string' ? v : null; }, async set(key, value) { map.set(key, value); }, map, }; } describe('7C-L1c delegation blob store — unit', () => { it('delegationBlobKey namespaces filenames', () => { assert.equal(delegationBlobKey('hub_delegation_consents.json'), 'delegation/hub_delegation_consents.json'); }); it('DELEGATION_BLOB_FILES includes core index files', () => { assert.ok(DELEGATION_BLOB_FILES.includes(DELEGATION_CONSENTS_FILE)); }); it('mergeGrantsStoreJson keeps local mint when blob is stale', () => { const local = JSON.stringify({ vaults: { default: { grants: [{ grant_id: 'dgrnt_new', issued_at: '2026-06-28T12:00:00.000Z', revoked_at: null, }], }, }, }); const blob = JSON.stringify({ vaults: { default: { grants: [] } } }); const merged = JSON.parse(mergeGrantsStoreJson(local, blob)); assert.equal(merged.vaults.default.grants.length, 1); assert.equal(merged.vaults.default.grants[0].grant_id, 'dgrnt_new'); }); it('mergeGrantsStoreJson prefers revoked grant from blob', () => { const local = JSON.stringify({ vaults: { default: { grants: [{ grant_id: 'dgrnt_x', issued_at: '2026-06-28T12:00:00.000Z', revoked_at: null, }], }, }, }); const blob = JSON.stringify({ vaults: { default: { grants: [{ grant_id: 'dgrnt_x', issued_at: '2026-06-28T12:00:00.000Z', revoked_at: '2026-06-28T12:05:00.000Z', }], }, }, }); const merged = JSON.parse(mergeGrantsStoreJson(local, blob)); assert.equal(merged.vaults.default.grants[0].revoked_at, '2026-06-28T12:05:00.000Z'); }); it('mergeGrantsStoreJson keeps local revoke when blob is stale', () => { const local = JSON.stringify({ vaults: { default: { grants: [{ grant_id: 'dgrnt_x', issued_at: '2026-06-28T12:00:00.000Z', revoked_at: '2026-06-28T12:05:00.000Z', }], }, }, }); const blob = JSON.stringify({ vaults: { default: { grants: [{ grant_id: 'dgrnt_x', issued_at: '2026-06-28T12:00:00.000Z', revoked_at: null, }], }, }, }); const merged = JSON.parse(mergeGrantsStoreJson(local, blob)); assert.equal(merged.vaults.default.grants[0].revoked_at, '2026-06-28T12:05:00.000Z'); }); }); describe('7C-L1c delegation blob store — integration', () => { const dataDir = path.join(tmpRoot, 'integration', 'data'); const vaultId = 'Business'; beforeEach(() => { fs.rmSync(path.join(tmpRoot, 'integration'), { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); writeDelegationPolicy(dataDir); process.env.DELEGATION_ENABLED = '1'; }); afterEach(() => { delete process.env.DELEGATION_ENABLED; }); it('hydrate merges grants without dropping warm-lambda mint', async () => { const dataDir = path.join(tmpRoot, 'integration', 'merge-data'); fs.rmSync(dataDir, { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); const localGrant = JSON.stringify({ vaults: { default: { grants: [{ grant_id: 'dgrnt_warm', issued_at: '2026-06-28T12:00:00.000Z', revoked_at: null, }], }, }, }); fs.writeFileSync(path.join(dataDir, DELEGATION_GRANTS_FILE), localGrant, 'utf8'); const blob = makeMockBlobStore(); await blob.set(delegationBlobKey(DELEGATION_GRANTS_FILE), JSON.stringify({ vaults: { default: { grants: [] } } })); await hydrateDelegationStoresFromBlob(blob, dataDir); const merged = JSON.parse(fs.readFileSync(path.join(dataDir, DELEGATION_GRANTS_FILE), 'utf8')); assert.equal(merged.vaults.default.grants[0].grant_id, 'dgrnt_warm'); }); it('persist then hydrate round-trips consent index across cold start', async () => { const identity = makeAgentIdentity({ agentId: 'agent_l1c_smoke01' }); const consent = makeDelegationConsent({ consentId: 'dcons_l1c_smoke01', agentId: 'agent_l1c_smoke01' }); seedDelegationFixtures(dataDir, vaultId, identity, consent); const blob = makeMockBlobStore(); await persistDelegationStoresToBlob(blob, dataDir); fs.rmSync(path.join(dataDir, DELEGATION_CONSENTS_FILE)); await hydrateDelegationStoresFromBlob(blob, dataDir); assert.ok(fs.existsSync(path.join(dataDir, DELEGATION_CONSENTS_FILE))); const mint = handleDelegationGrantMintRequest({ dataDir, vaultId, consentId: 'dcons_l1c_smoke01', actorAgentId: 'agent_l1c_smoke01', taskRef: 'task_hw_week3', }); assert.equal(mint.ok, true); }); }); describe('7C-L1c delegation blob store — e2e', () => { const dataDir = path.join(tmpRoot, 'e2e', 'data'); const vaultId = 'Business'; beforeEach(() => { fs.rmSync(path.join(tmpRoot, 'e2e'), { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); writeDelegationPolicy(dataDir); process.env.DELEGATION_ENABLED = '1'; }); afterEach(() => { delete process.env.DELEGATION_ENABLED; }); it('withDelegationBlobSync persists mint result for next lambda', async () => { const identity = makeAgentIdentity({ agentId: 'agent_l1c_smoke01' }); const consent = makeDelegationConsent({ consentId: 'dcons_l1c_smoke01', agentId: 'agent_l1c_smoke01' }); seedDelegationFixtures(dataDir, vaultId, identity, consent); const blob = makeMockBlobStore(); const mint = await withDelegationBlobSync({ blobStore: blob, dataDir, run: () => handleDelegationGrantMintRequest({ dataDir, vaultId, consentId: 'dcons_l1c_smoke01', actorAgentId: 'agent_l1c_smoke01', taskRef: 'task_hw_week3', }), }); assert.equal(mint.ok, true); fs.rmSync(dataDir, { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); writeDelegationPolicy(dataDir); await hydrateDelegationStoresFromBlob(blob, dataDir); const list = handleDelegationGrantMintRequest({ dataDir, vaultId, consentId: 'dcons_l1c_smoke01', actorAgentId: 'agent_l1c_smoke01', taskRef: 'task_hw_week3', }); assert.equal(list.ok, true); }); }); describe('7C-L1c delegation blob store — stress', () => { it('hydrate/persist handles empty blob store', async () => { const dataDir = path.join(tmpRoot, 'stress', 'data'); fs.rmSync(path.join(tmpRoot, 'stress'), { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); await hydrateDelegationStoresFromBlob(null, dataDir); await persistDelegationStoresToBlob(null, dataDir); assert.ok(true); }); }); describe('7C-L1c delegation blob store — data-integrity', () => { it('blob key matches persisted consent JSON', async () => { const dataDir = path.join(tmpRoot, 'integrity', 'data'); fs.rmSync(path.join(tmpRoot, 'integrity'), { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); writeDelegationPolicy(dataDir); const identity = makeAgentIdentity({ agentId: 'agent_l1c_smoke01' }); const consent = makeDelegationConsent({ consentId: 'dcons_l1c_smoke01', agentId: 'agent_l1c_smoke01' }); seedDelegationFixtures(dataDir, 'Business', identity, consent); const blob = makeMockBlobStore(); await persistDelegationStoresToBlob(blob, dataDir); const raw = blob.map.get(delegationBlobKey(DELEGATION_CONSENTS_FILE)); assert.ok(typeof raw === 'string' && raw.includes('dcons_l1c_smoke01')); }); }); describe('7C-L1c delegation blob store — performance', () => { it('withDelegationBlobSync completes under 500ms for fixture mint', async () => { const dataDir = path.join(tmpRoot, 'perf', 'data'); fs.rmSync(path.join(tmpRoot, 'perf'), { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); writeDelegationPolicy(dataDir); const identity = makeAgentIdentity({ agentId: 'agent_l1c_smoke01' }); const consent = makeDelegationConsent({ consentId: 'dcons_l1c_smoke01', agentId: 'agent_l1c_smoke01' }); seedDelegationFixtures(dataDir, 'Business', identity, consent); const blob = makeMockBlobStore(); const t0 = Date.now(); await withDelegationBlobSync({ blobStore: blob, dataDir, run: () => handleDelegationGrantMintRequest({ dataDir, vaultId: 'Business', consentId: 'dcons_l1c_smoke01', actorAgentId: 'agent_l1c_smoke01', taskRef: 'task_hw_week3', }), }); assert.ok(Date.now() - t0 < 500); }); }); describe('7C-L1c delegation blob store — security', () => { it('hydrate ignores malformed blob entries without throwing', async () => { const dataDir = path.join(tmpRoot, 'security', 'data'); fs.rmSync(path.join(tmpRoot, 'security'), { recursive: true, force: true }); fs.mkdirSync(dataDir, { recursive: true }); const blob = { async get() { throw new Error('blob read denied'); }, async set() {}, }; await hydrateDelegationStoresFromBlob(blob, dataDir); assert.ok(true); }); });