Files
boc/aamos-ledger-refactor/test/tenant-isolation.test.mjs
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

141 lines
4.4 KiB
JavaScript

/**
* test/tenant-isolation.test.mjs — Tenant isolation tests
*/
import { describe, it } from 'node:test';
import assert from 'node:assert';
// Mock pool that tracks tenant isolation
function createMockPool() {
const executedQueries = [];
return {
executedQueries,
query: async (sql, params) => {
executedQueries.push({ sql, params });
// Verify tenant_id is first param for most queries
return { rows: [] };
},
connect: async () => ({
query: async (sql, params) => {
executedQueries.push({ sql, params, client: true });
return { rows: [] };
},
release: () => {}
})
};
}
// Tenant context builder (same as in index.mjs)
function buildCtx(req, entityType = null, entityId = null, decisionSource = 'user') {
return {
trace_id: req.headers?.['x-trace-id'] || 'test-trace',
correlation_id: req.headers?.['x-correlation-id'] || 'test-correlation',
tenant_id: req.headers?.['x-tenant-id'] || req.body?.tenant_id || 'wavult-group',
user_id: req.headers?.['x-user-id'] || req.body?.user_id || 'system',
entity_type: entityType,
entity_id: entityId,
decision_source: decisionSource,
};
}
describe('Tenant isolation', () => {
it('should use tenant_id from headers', () => {
const req = {
headers: { 'x-tenant-id': 'tenant-a' },
body: {}
};
const ctx = buildCtx(req);
assert.strictEqual(ctx.tenant_id, 'tenant-a');
});
it('should fallback to body tenant_id if header missing', () => {
const req = {
headers: {},
body: { tenant_id: 'tenant-b' }
};
const ctx = buildCtx(req);
assert.strictEqual(ctx.tenant_id, 'tenant-b');
});
it('should use default tenant when no tenant specified', () => {
const req = { headers: {}, body: {} };
const ctx = buildCtx(req);
assert.strictEqual(ctx.tenant_id, 'wavult-group');
});
it('should include tenant_id in SQL queries', async () => {
const pool = createMockPool();
const tenantId = 'tenant-test';
// Simulate a query that should include tenant_id
await pool.query(
'SELECT * FROM ledger_accounts WHERE tenant_id = $1',
[tenantId]
);
const query = pool.executedQueries[0];
assert.strictEqual(query.params[0], tenantId);
assert.ok(query.sql.includes('tenant_id'));
});
it('should prevent cross-tenant data access', () => {
const tenantA = 'tenant-a';
const tenantB = 'tenant-b';
// Simulate query for tenant A
const queryA = {
sql: 'SELECT * FROM ledger_journal_entries WHERE tenant_id = $1',
params: [tenantA]
};
// Ensure tenant B cannot access tenant A's data
const isIsolated = queryA.params[0] !== tenantB;
assert.strictEqual(isIsolated, true);
});
it('should include tenant_id in all journal entry operations', () => {
const operations = [
'SELECT * FROM ledger_journal_entries WHERE tenant_id = $1',
'INSERT INTO ledger_journal_entries (tenant_id, ...) VALUES ($1, ...)',
'UPDATE ledger_journal_entries SET ... WHERE id = $2 AND tenant_id = $1',
'DELETE FROM ledger_journal_entries WHERE id = $1 AND tenant_id = $2'
];
for (const sql of operations) {
assert.ok(sql.includes('tenant_id'), `Missing tenant_id in: ${sql}`);
}
});
});
describe('Multi-tenant scenarios', () => {
it('should maintain separate contexts for concurrent requests', () => {
const req1 = { headers: { 'x-tenant-id': 'tenant-1' }, body: {} };
const req2 = { headers: { 'x-tenant-id': 'tenant-2' }, body: {} };
const ctx1 = buildCtx(req1);
const ctx2 = buildCtx(req2);
assert.strictEqual(ctx1.tenant_id, 'tenant-1');
assert.strictEqual(ctx2.tenant_id, 'tenant-2');
assert.notStrictEqual(ctx1.tenant_id, ctx2.tenant_id);
});
it('should propagate trace context across operations', () => {
const req = {
headers: {
'x-trace-id': 'trace-123',
'x-correlation-id': 'corr-456',
'x-tenant-id': 'tenant-x'
},
body: {}
};
const ctx = buildCtx(req, 'journal_entry', 'entry-1');
assert.strictEqual(ctx.trace_id, 'trace-123');
assert.strictEqual(ctx.correlation_id, 'corr-456');
assert.strictEqual(ctx.tenant_id, 'tenant-x');
assert.strictEqual(ctx.entity_type, 'journal_entry');
assert.strictEqual(ctx.entity_id, 'entry-1');
});
});