#!/usr/bin/env node // Local-only convenience wrapper around scripts/provision-rls-roles.mjs. // // The app-wide RLS cutover migration GRANTs to hivegrid_app / hivegrid_worker / // hivegrid_rls_definer, so those roles must exist before `prisma migrate deploy` // touches an empty database — otherwise migration 20260713190000 fails halfway // and leaves the database in a failed-migration state (P3009). // // The managed role passwords are external deployment secrets and therefore have // no place in .env.example or the config catalog. Locally they are irrelevant: // dev runs with RLS_RUNTIME_MODE=off and the app connects as the DATABASE_URL // owner, never as one of these roles. So we mint throwaway random passwords here // instead of committing any value. Staging and production keep using // `pnpm run db:roles:provision` with real, externally managed secrets. import { randomBytes } from "node:crypto"; import { provisionRlsRoles, ROLE_PASSWORD_ENV } from "./provision-rls-roles.mjs"; if (process.env.NODE_ENV === "production") { process.stderr.write("FAIL dev:db:roles is a local helper; use db:roles:provision with managed secrets instead\n"); process.exit(1); } const connectionString = process.env.HIVEGRID_RLS_PROVISION_DATABASE_URL ?? process.env.DIRECT_URL ?? process.env.DATABASE_URL; if (!connectionString) { process.stderr.write("FAIL no DATABASE_URL (or DIRECT_URL) found — copy .env.example to .env first\n"); process.exit(1); } const env = { ...process.env, HIVEGRID_RLS_PROVISION_DATABASE_URL: connectionString, }; for (const passwordEnvName of Object.values(ROLE_PASSWORD_ENV)) { // 48 hex chars, comfortably above the provisioner's 32-character floor and // distinct per role (it rejects duplicates). env[passwordEnvName] = randomBytes(24).toString("hex"); } try { await provisionRlsRoles({ env }); process.stdout.write("PASS local RLS roles provisioned (throwaway passwords, not persisted)\n"); } catch (error) { const message = error instanceof Error ? error.message : "role provisioning failed"; process.stderr.write(`FAIL ${message}\n`); process.exit(1); }