sandbox.constants.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // ALTER ROLE postgres SUPERUSER succeeds because the bootstrap connection owns the cluster.
  2. // Each statement is individual so a single failure cannot abort the rest.
  3. export const SANDBOX_SETUP_STATEMENTS = [
  4. `ALTER ROLE postgres SUPERUSER`,
  5. `DO $$ BEGIN
  6. IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'anon') THEN
  7. CREATE ROLE anon NOLOGIN;
  8. END IF;
  9. IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticated') THEN
  10. CREATE ROLE authenticated NOLOGIN;
  11. END IF;
  12. IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'service_role') THEN
  13. CREATE ROLE service_role NOLOGIN;
  14. END IF;
  15. IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticator') THEN
  16. CREATE ROLE authenticator NOLOGIN;
  17. END IF;
  18. IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'dashboard_user') THEN
  19. CREATE ROLE dashboard_user NOLOGIN;
  20. END IF;
  21. IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'pgbouncer') THEN
  22. CREATE ROLE pgbouncer NOLOGIN;
  23. END IF;
  24. IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'briven_admin') THEN
  25. CREATE ROLE briven_admin NOLOGIN;
  26. END IF;
  27. END $$`,
  28. `ALTER ROLE service_role BYPASSRLS`,
  29. `GRANT anon TO postgres WITH ADMIN OPTION`,
  30. `GRANT authenticated TO postgres WITH ADMIN OPTION`,
  31. `GRANT service_role TO postgres WITH ADMIN OPTION`,
  32. `GRANT CONNECT ON DATABASE postgres TO anon, authenticated, service_role`,
  33. `CREATE SCHEMA IF NOT EXISTS auth`,
  34. `GRANT USAGE ON SCHEMA auth TO anon, authenticated, service_role`,
  35. `GRANT USAGE ON SCHEMA public TO anon, authenticated, service_role`,
  36. // Read both the per-claim setting (request.jwt.claim.<name>) and the JSON blob
  37. // (request.jwt.claims) so these work whether the caller uses Studio's role
  38. // impersonation (sets the JSON blob) or PostgREST-style per-claim settings.
  39. // Mirrors how the real Briven auth.* helpers are defined.
  40. `CREATE OR REPLACE FUNCTION auth.uid() RETURNS uuid LANGUAGE sql STABLE AS
  41. $fn$ SELECT COALESCE(
  42. NULLIF(current_setting('request.jwt.claim.sub', true), ''),
  43. (NULLIF(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
  44. )::uuid $fn$`,
  45. `CREATE OR REPLACE FUNCTION auth.role() RETURNS text LANGUAGE sql STABLE AS
  46. $fn$ SELECT COALESCE(
  47. NULLIF(current_setting('request.jwt.claim.role', true), ''),
  48. (NULLIF(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role'),
  49. 'anon'
  50. ) $fn$`,
  51. `CREATE OR REPLACE FUNCTION auth.email() RETURNS text LANGUAGE sql STABLE AS
  52. $fn$ SELECT COALESCE(
  53. NULLIF(current_setting('request.jwt.claim.email', true), ''),
  54. (NULLIF(current_setting('request.jwt.claims', true), '')::jsonb ->> 'email')
  55. ) $fn$`,
  56. `GRANT EXECUTE ON FUNCTION auth.uid() TO anon, authenticated, service_role`,
  57. `GRANT EXECUTE ON FUNCTION auth.role() TO anon, authenticated, service_role`,
  58. `GRANT EXECUTE ON FUNCTION auth.email() TO anon, authenticated, service_role`,
  59. // Minimal auth table stubs — enough for FK references and policy expressions.
  60. // Projects commonly have FKs to auth.users from public schema tables (e.g. profiles),
  61. // so without this stub those tables fail to create and their policies can't be tested.
  62. `CREATE TABLE IF NOT EXISTS auth.users (
  63. instance_id uuid,
  64. id uuid NOT NULL PRIMARY KEY,
  65. aud varchar(255),
  66. role varchar(255),
  67. email varchar(255),
  68. encrypted_password varchar(255),
  69. email_confirmed_at timestamptz,
  70. invited_at timestamptz,
  71. confirmation_token varchar(255),
  72. confirmation_sent_at timestamptz,
  73. recovery_token varchar(255),
  74. recovery_sent_at timestamptz,
  75. email_change_token_new varchar(255),
  76. email_change varchar(255),
  77. email_change_sent_at timestamptz,
  78. last_sign_in_at timestamptz,
  79. raw_app_meta_data jsonb,
  80. raw_user_meta_data jsonb,
  81. is_super_admin boolean,
  82. created_at timestamptz,
  83. updated_at timestamptz,
  84. phone text DEFAULT NULL,
  85. phone_confirmed_at timestamptz,
  86. phone_change text DEFAULT '',
  87. phone_change_token varchar(255) DEFAULT '',
  88. phone_change_sent_at timestamptz,
  89. confirmed_at timestamptz,
  90. email_change_token_current varchar(255) DEFAULT '',
  91. email_change_confirm_status smallint DEFAULT 0,
  92. banned_until timestamptz,
  93. reauthentication_token varchar(255) DEFAULT '',
  94. reauthentication_sent_at timestamptz,
  95. is_sso_user boolean NOT NULL DEFAULT false,
  96. deleted_at timestamptz,
  97. is_anonymous boolean NOT NULL DEFAULT false
  98. )`,
  99. `CREATE TABLE IF NOT EXISTS auth.sessions (
  100. id uuid NOT NULL PRIMARY KEY,
  101. user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  102. created_at timestamptz,
  103. updated_at timestamptz,
  104. factor_id uuid,
  105. aal text,
  106. not_after timestamptz,
  107. refreshed_at timestamp,
  108. user_agent text,
  109. ip inet,
  110. tag text
  111. )`,
  112. `CREATE TABLE IF NOT EXISTS auth.mfa_factors (
  113. id uuid NOT NULL PRIMARY KEY,
  114. user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  115. friendly_name text,
  116. factor_type text NOT NULL,
  117. status text NOT NULL,
  118. created_at timestamptz NOT NULL,
  119. updated_at timestamptz NOT NULL,
  120. secret text,
  121. phone text,
  122. last_challenged_at timestamptz,
  123. web_authn_credential jsonb,
  124. web_authn_aaguid uuid
  125. )`,
  126. `GRANT SELECT, INSERT, UPDATE, DELETE ON auth.users, auth.sessions, auth.mfa_factors TO anon, authenticated, service_role`,
  127. ]
  128. // Seeded alongside public tables so FK references from public → auth.users
  129. // resolve to real rows. rls flags are ignored here — auth.users is set up by
  130. // SANDBOX_SETUP_STATEMENTS, this entry is only used by the seed step.
  131. //
  132. // Columns are an explicit allow-list: enough to evaluate realistic RLS
  133. // policies (id for FK matching, role/email/metadata for claim-style checks)
  134. // while keeping secrets out of the browser-side PGlite instance — no
  135. // encrypted_password, no *_token columns.
  136. export const AUTH_USERS_SEED_TABLE = {
  137. schema: 'auth',
  138. table: 'users',
  139. rls_enabled: false,
  140. rls_forced: false,
  141. columns: [
  142. 'id',
  143. 'aud',
  144. 'role',
  145. 'email',
  146. 'phone',
  147. 'email_confirmed_at',
  148. 'phone_confirmed_at',
  149. 'last_sign_in_at',
  150. 'confirmed_at',
  151. 'raw_app_meta_data',
  152. 'raw_user_meta_data',
  153. 'is_super_admin',
  154. 'is_sso_user',
  155. 'is_anonymous',
  156. 'banned_until',
  157. 'deleted_at',
  158. 'created_at',
  159. 'updated_at',
  160. ],
  161. } as const