isolation-fire-drill.mjs84 lines · main
1/**
2 * Auth isolation fire drill — two projects must not see each other's users.
3 *
4 * bun scripts/isolation-fire-drill.mjs
5 *
6 * Requires local/engine Doltgres (same env as other proofs).
7 */
8
9process.env.BRIVEN_AUTH_CORE_ENABLED = 'true';
10process.env.BRIVEN_ENV = process.env.BRIVEN_ENV ?? 'development';
11process.env.BRIVEN_ENGINE_DATABASE_URL =
12 process.env.BRIVEN_ENGINE_DATABASE_URL ??
13 'postgres://postgres:devpass@127.0.0.1:5434/briven_engine?sslmode=disable';
14process.env.BRIVEN_DATA_PLANE_URL =
15 process.env.BRIVEN_DATA_PLANE_URL ??
16 'postgres://postgres:devpass@127.0.0.1:5434/postgres?sslmode=disable';
17
18const { ensureBrivenEngineDatabase } = await import(
19 '../src/services/auth-core/ensure-db.ts'
20);
21const { initAuthCoreSdk } = await import('../src/services/auth-core/engine.ts');
22const { signUpEmailPassword } = await import(
23 '../src/services/auth-core/emailpassword.ts'
24);
25const { listBrivenEngineUsers, getBrivenEngineUser } = await import(
26 '../src/services/auth-core/users.ts'
27);
28const { projectIdToTenantId } = await import(
29 '../src/services/auth-core/project-map.ts'
30);
31
32function fail(m, x) {
33 console.error('FAIL', m, x ?? '');
34 process.exit(1);
35}
36
37console.log('=== Isolation fire drill ===');
38if (!(await ensureBrivenEngineDatabase()).ok) fail('db');
39if (!(await initAuthCoreSdk())) fail('sdk');
40
41const a = `p_iso_a_${Date.now().toString(36)}`;
42const b = `p_iso_b_${Date.now().toString(36)}`;
43const emailA = `a_${Date.now()}@iso.test`;
44const emailB = `b_${Date.now()}@iso.test`;
45
46const ua = await signUpEmailPassword({
47 email: emailA,
48 password: 'IsoA!9999xx',
49 projectId: a,
50});
51const ub = await signUpEmailPassword({
52 email: emailB,
53 password: 'IsoB!9999xx',
54 projectId: b,
55});
56if (ua.status !== 'OK' || ub.status !== 'OK') fail('signup', { ua, ub });
57
58const listA = await listBrivenEngineUsers({
59 tenantId: projectIdToTenantId(a),
60 limit: 50,
61});
62const listB = await listBrivenEngineUsers({
63 tenantId: projectIdToTenantId(b),
64 limit: 50,
65});
66
67const idsA = new Set(listA.users.map((u) => u.id));
68const idsB = new Set(listB.users.map((u) => u.id));
69if (idsA.has(ub.user.id)) fail('project A list contains B user');
70if (idsB.has(ua.user.id)) fail('project B list contains A user');
71if (!idsA.has(ua.user.id)) fail('project A missing own user');
72if (!idsB.has(ub.user.id)) fail('project B missing own user');
73
74// Cross-tenant get by id without tenant should still resolve user, but
75// tenant-scoped get must miss.
76const cross = await getBrivenEngineUser(ua.user.id, {
77 tenantId: projectIdToTenantId(b),
78});
79if (cross) fail('B tenant can read A user by id', cross);
80
81console.log('ok project A users', listA.users.length);
82console.log('ok project B users', listB.users.length);
83console.log('=== Isolation fire drill PASSED ===');
84process.exit(0);