isolation-fire-drill.mjs 2.7 KB

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