@opengeni/db 0.14.0 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/{chunk-ELMUCYZF.js → chunk-4RUK5CON.js} +183 -42
  2. package/dist/chunk-4RUK5CON.js.map +1 -0
  3. package/dist/chunk-HZD7KVAR.js +4648 -0
  4. package/dist/chunk-HZD7KVAR.js.map +1 -0
  5. package/dist/{chunk-Y5WZZVQK.js → chunk-SK7YYHBI.js} +5 -2
  6. package/dist/chunk-SK7YYHBI.js.map +1 -0
  7. package/dist/codex-token-resolver.d.ts +64 -0
  8. package/dist/connection-token-resolver.d.ts +90 -0
  9. package/dist/environment-crypto.d.ts +11 -0
  10. package/dist/event-payload-sanitizer.d.ts +32 -0
  11. package/dist/index.d.ts +6217 -10
  12. package/dist/index.js +6992 -2728
  13. package/dist/index.js.map +1 -1
  14. package/dist/insights.d.ts +157 -0
  15. package/dist/memory-domain.d.ts +44 -0
  16. package/dist/migrate.d.ts +5 -7
  17. package/dist/migrate.js +1 -1
  18. package/dist/new-session-drafts.d.ts +49 -0
  19. package/dist/persistence-errors.d.ts +69 -0
  20. package/dist/preference-registry-schema.d.ts +1147 -0
  21. package/dist/preference-registry.d.ts +878 -0
  22. package/dist/provision-roles.d.ts +4 -6478
  23. package/dist/provision-roles.js +1 -1
  24. package/dist/role-relationships.d.ts +35 -0
  25. package/dist/runtime-posture-cli.d.ts +1 -0
  26. package/dist/runtime-posture.d.ts +103 -0
  27. package/dist/schema.d.ts +23533 -3
  28. package/dist/schema.js +17 -1
  29. package/dist/session-control.d.ts +331 -0
  30. package/dist/session-queue-commands.d.ts +186 -0
  31. package/dist/session-tool-call-settlement.d.ts +32 -0
  32. package/dist/turn-initiator.d.ts +28 -0
  33. package/dist/workspace-instruction-policies-schema.d.ts +735 -0
  34. package/dist/workspace-instruction-policies.d.ts +64 -0
  35. package/drizzle/0136_unified_session_tool_policy.sql +109 -0
  36. package/drizzle/0137_preference_registry.sql +1347 -0
  37. package/drizzle/0138_sandbox_checkpoint_artifacts_and_deadlines.sql +1074 -0
  38. package/drizzle/0139_codex_provider_artifact_invalidations.sql +51 -0
  39. package/drizzle/0140_sandbox_restore_and_reaper_fences.sql +276 -0
  40. package/drizzle/0142_sandbox_archive_capture_gate.sql +80 -0
  41. package/drizzle/0143_session_codex_compaction_mode.sql +20 -0
  42. package/drizzle/0144_sandbox_viewer_force_drain_gate.sql +95 -0
  43. package/drizzle/0145_model_call_facts.sql +96 -0
  44. package/drizzle/0146_slack_bot_delete_idempotency.sql +105 -0
  45. package/drizzle/0147_draft_latency_mode.sql +12 -0
  46. package/drizzle/0148_session_turn_latency_mode.sql +12 -0
  47. package/package.json +6 -6
  48. package/src/index.ts +5095 -430
  49. package/src/insights.ts +837 -0
  50. package/src/migrate.ts +9 -1
  51. package/src/new-session-drafts.ts +4 -0
  52. package/src/preference-registry-schema.ts +170 -0
  53. package/src/preference-registry.ts +1220 -0
  54. package/src/provision-roles.ts +95 -22
  55. package/src/role-relationships.ts +132 -0
  56. package/src/runtime-posture.ts +28 -26
  57. package/src/schema.ts +484 -12
  58. package/src/session-queue-commands.ts +47 -46
  59. package/dist/chunk-ELMUCYZF.js.map +0 -1
  60. package/dist/chunk-PQKVUWQW.js +0 -4047
  61. package/dist/chunk-PQKVUWQW.js.map +0 -1
  62. package/dist/chunk-Y5WZZVQK.js.map +0 -1
  63. package/dist/schema-FoPub9yt.d.ts +0 -22666
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  metadataWithTurnExecutionPolicyV1,
3
3
  mergeResourceRefs,
4
- mergeToolRefs,
4
+ ResourceRef,
5
+ resourceMountPath,
6
+ stableJson,
5
7
  turnExecutionPolicyAuditMetadata,
8
+ type LatencyMode,
6
9
  type ReasoningEffort,
7
- type ResourceRef,
8
- type SessionToolPolicy,
9
- type ToolRef,
10
10
  type TurnExecutionPolicyV1,
11
11
  } from "@opengeni/contracts";
12
12
  import { and, asc, eq, inArray, sql } from "drizzle-orm";
@@ -367,13 +367,28 @@ async function normalizeQueuePositions(
367
367
  }
368
368
 
369
369
  function draftIsNonEmpty(draft: ComposerDraftRow): boolean {
370
- return (
371
- draft.text.length > 0 ||
372
- draft.resources.length > 0 ||
373
- draft.tools.length > 0 ||
374
- draft.toolsProvided ||
375
- draft.sourceTurnId !== null
376
- );
370
+ return draft.text.length > 0 || draft.resources.length > 0 || draft.sourceTurnId !== null;
371
+ }
372
+
373
+ function withCanonicalResourceMountPaths(resources: readonly unknown[]): unknown[] {
374
+ const seen = new Set<string>();
375
+ const canonical: unknown[] = [];
376
+ for (const value of resources) {
377
+ const parsed = ResourceRef.safeParse(value);
378
+ if (!parsed.success) {
379
+ canonical.push(value);
380
+ continue;
381
+ }
382
+ const normalized = {
383
+ ...(value as Record<string, unknown>),
384
+ mountPath: resourceMountPath(parsed.data),
385
+ };
386
+ const key = stableJson(normalized);
387
+ if (seen.has(key)) continue;
388
+ seen.add(key);
389
+ canonical.push(normalized);
390
+ }
391
+ return canonical;
377
392
  }
378
393
 
379
394
  export async function getComposerDraftInTransaction(
@@ -410,10 +425,9 @@ export async function saveComposerDraftInTransaction(
410
425
  expectedRevision: number;
411
426
  text: string;
412
427
  resources: ResourceRef[];
413
- tools: ToolRef[];
414
- toolsProvided: boolean;
415
428
  model: string;
416
429
  reasoningEffort: ReasoningEffort;
430
+ latencyMode?: LatencyMode;
417
431
  },
418
432
  ): Promise<ComposerDraftRow> {
419
433
  await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
@@ -441,11 +455,12 @@ export async function saveComposerDraftInTransaction(
441
455
  subjectId: input.subjectId,
442
456
  revision,
443
457
  text: input.text,
444
- resources: input.resources,
445
- tools: input.tools,
446
- toolsProvided: input.toolsProvided,
458
+ resources: withCanonicalResourceMountPaths(input.resources),
459
+ tools: [],
460
+ toolsProvided: false,
447
461
  model: input.model,
448
462
  reasoningEffort: input.reasoningEffort,
463
+ latencyMode: input.latencyMode ?? "standard",
449
464
  // A queue edit is still the same accepted work item. Preserve its frozen
450
465
  // initiator through arbitrary draft saves; only a genuinely new compose or
451
466
  // Steer captures the submitting actor.
@@ -813,11 +828,12 @@ export async function editQueuedTurnInTransaction(
813
828
  subjectId: input.subjectId,
814
829
  revision: nextDraftRevision,
815
830
  text: turn.prompt,
816
- resources: turn.resources,
817
- tools: turn.tools,
818
- toolsProvided: turn.toolsProvided,
831
+ resources: withCanonicalResourceMountPaths(turn.resources),
832
+ tools: [],
833
+ toolsProvided: false,
819
834
  model: turn.model,
820
835
  reasoningEffort: turn.reasoningEffort,
836
+ latencyMode: turn.latencyMode,
821
837
  sourceTurnId: turn.id,
822
838
  sourceTurnVersion: turn.version,
823
839
  updatedAt: new Date(),
@@ -1131,10 +1147,9 @@ export async function submitHumanPromptInTransaction(
1131
1147
  text: string;
1132
1148
  turnInstructions?: string | null;
1133
1149
  resources: ResourceRef[];
1134
- tools: ToolRef[];
1135
- toolsProvided?: boolean;
1136
1150
  model?: string | null;
1137
1151
  reasoningEffort?: ReasoningEffort | null;
1152
+ latencyMode?: LatencyMode | null;
1138
1153
  reasoningEffortFallback: ReasoningEffort;
1139
1154
  /** Trusted API/core admission snapshot. Omitted only by legacy low-level callers. */
1140
1155
  turnExecutionPolicy?: TurnExecutionPolicyV1;
@@ -1162,11 +1177,10 @@ export async function submitHumanPromptInTransaction(
1162
1177
  expectedDraftRevision: input.expectedDraftRevision ?? null,
1163
1178
  text: input.text,
1164
1179
  turnInstructions: input.turnInstructions ?? null,
1165
- resources: input.resources,
1166
- tools: input.tools,
1167
- toolsProvided: input.toolsProvided === true,
1180
+ resources: withCanonicalResourceMountPaths(input.resources),
1168
1181
  model: input.model ?? null,
1169
1182
  reasoningEffort: input.reasoningEffort ?? null,
1183
+ latencyMode: input.latencyMode ?? null,
1170
1184
  source: input.source,
1171
1185
  mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
1172
1186
  ...(input.actor.type === "service"
@@ -1271,19 +1285,17 @@ export async function submitHumanPromptInTransaction(
1271
1285
  draft &&
1272
1286
  canonicalSessionCommandHash({
1273
1287
  text: draft.text,
1274
- resources: draft.resources,
1275
- tools: draft.tools,
1276
- toolsProvided: draft.toolsProvided,
1288
+ resources: withCanonicalResourceMountPaths(draft.resources),
1277
1289
  model: draft.model,
1278
1290
  reasoningEffort: draft.reasoningEffort,
1291
+ latencyMode: draft.latencyMode,
1279
1292
  }) !==
1280
1293
  canonicalSessionCommandHash({
1281
1294
  text: input.text,
1282
- resources: input.resources,
1283
- tools: input.tools,
1284
- toolsProvided: input.toolsProvided === true,
1295
+ resources: withCanonicalResourceMountPaths(input.resources),
1285
1296
  model: input.model ?? session.model,
1286
1297
  reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback,
1298
+ latencyMode: input.turnExecutionPolicy?.latencyMode ?? input.latencyMode ?? "standard",
1287
1299
  })
1288
1300
  ) {
1289
1301
  throw new QueueCommandConflictError(
@@ -1401,13 +1413,9 @@ export async function submitHumanPromptInTransaction(
1401
1413
  payload: sanitizeEventPayload({
1402
1414
  text: input.text,
1403
1415
  ...(input.resources.length ? { resources: input.resources } : {}),
1404
- ...(input.toolsProvided === true
1405
- ? { tools: input.tools }
1406
- : input.tools.length
1407
- ? { tools: input.tools }
1408
- : {}),
1409
1416
  ...(input.model ? { model: input.model } : {}),
1410
1417
  ...(input.reasoningEffort ? { reasoningEffort: input.reasoningEffort } : {}),
1418
+ ...(input.latencyMode ? { latencyMode: input.latencyMode } : {}),
1411
1419
  delivery: input.delivery,
1412
1420
  initiator: frozenInitiator.initiator,
1413
1421
  }),
@@ -1433,10 +1441,11 @@ export async function submitHumanPromptInTransaction(
1433
1441
  ? editedSourceTurnInstructions
1434
1442
  : (input.turnInstructions ?? null),
1435
1443
  resources: input.resources,
1436
- tools: input.tools,
1437
- toolsProvided: input.toolsProvided === true,
1444
+ tools: [],
1445
+ toolsProvided: false,
1438
1446
  model: input.model ?? session.model,
1439
1447
  reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback,
1448
+ latencyMode: input.turnExecutionPolicy?.latencyMode ?? input.latencyMode ?? "standard",
1440
1449
  sandboxBackend: session.sandboxBackend,
1441
1450
  metadata: input.turnExecutionPolicy
1442
1451
  ? metadataWithTurnExecutionPolicyV1({}, input.turnExecutionPolicy)
@@ -1578,9 +1587,7 @@ export async function submitHumanPromptInTransaction(
1578
1587
  .update(schema.sessions)
1579
1588
  .set({
1580
1589
  resources: mergeResourceRefs(session.resources as ResourceRef[], input.resources),
1581
- tools: sessionToolPolicyIsFixed(session.toolPolicy)
1582
- ? session.tools
1583
- : mergeToolRefs(session.tools as ToolRef[], input.tools),
1590
+ tools: session.tools,
1584
1591
  activeTurnId: input.delivery === "steer" ? liveCurrentTurnId : session.activeTurnId,
1585
1592
  status: nextStatus,
1586
1593
  queueVersion,
@@ -1653,12 +1660,6 @@ export async function submitHumanPromptInTransaction(
1653
1660
  };
1654
1661
  }
1655
1662
 
1656
- function sessionToolPolicyIsFixed(value: unknown): boolean {
1657
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1658
- const mode = (value as Partial<SessionToolPolicy>).mode;
1659
- return mode === "workspace_default" || mode === "explicit" || mode === "inherited";
1660
- }
1661
-
1662
1663
  export async function sendAgentMessageInTransaction(
1663
1664
  db: Database,
1664
1665
  input: {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/provision-roles.ts","../src/runtime-posture.ts"],"sourcesContent":["import postgres from \"postgres\";\nimport type { RlsStrategy } from \"./index\";\nimport {\n RUNTIME_FULL_DML_TABLES,\n RUNTIME_READ_INSERT_TABLES,\n RUNTIME_READ_ONLY_TABLES,\n} from \"./runtime-posture\";\n\nexport type ProvisionResult = {\n appRole: string | null;\n hostExportRole: string | null;\n temporalRole: string | null;\n temporalDatabases: string[];\n schema: string;\n rlsStrategy: RlsStrategy;\n};\n\nexport type ProvisionRolesOptions = {\n /**\n * The schema OpenGeni's tables live in. The app-role GRANTs target this\n * schema + `opengeni_private`. Defaults to `public` (standalone).\n */\n targetSchema?: string;\n /**\n * RLS posture (Step I). `\"force\"` (default) provisions the non-owner\n * `opengeni_app` login role and GRANTs it table DML in the target schema —\n * the role OpenGeni connects as under FORCE-RLS. `\"scoped\"` SKIPS the app-role\n * provisioning entirely: the embedded host runs OpenGeni's queries over a role\n * IT owns/manages (typically the schema owner), so OpenGeni neither creates\n * nor grants the `opengeni_app` role. Temporal-role provisioning is unaffected\n * by strategy.\n */\n rlsStrategy?: RlsStrategy;\n appRole?: string;\n appPassword?: string;\n /**\n * Optional cross-workspace projection role. It receives schema USAGE and\n * EXECUTE only on the host-export API; it receives no table privileges.\n * Provision it after the first migration run so the schema exists. The\n * provisioner also registers same-owner default privileges for future\n * host-export functions; shipped migrations preserve existing exporter ACLs\n * when a migration-only upgrade adds a function.\n */\n hostExportRole?: string;\n hostExportPassword?: string;\n temporalRole?: string;\n temporalPassword?: string;\n temporalDatabases?: string[];\n};\n\n/**\n * SDK entry point (Step I): provision the OpenGeni database roles + grants over\n * a host-supplied admin connection. This is the named, parameterized form of the\n * historical env-driven `provision-roles` script (which still works as a CLI via\n * the `import.meta.main` block at the bottom — it just reads env into these\n * options).\n *\n * STANDALONE (default): `provisionRoles(adminConnection)` with no options →\n * `targetSchema: \"public\"`, `rlsStrategy: \"force\"`, reads `opengeni_app` creds\n * from env. Byte-for-byte the historical script behavior.\n *\n * EMBEDDED: `provisionRoles(adminConnection, { targetSchema, rlsStrategy })` lets\n * a host provision the app role over a dedicated schema (force) OR skip the\n * app role entirely and own the connection role itself (scoped).\n */\nexport async function provisionRoles(\n adminConnection: string,\n options: ProvisionRolesOptions = {},\n): Promise<ProvisionResult> {\n const schema = validateIdentifier(\"targetSchema\", options.targetSchema ?? \"public\");\n const rlsStrategy: RlsStrategy = options.rlsStrategy ?? \"force\";\n\n const appRole = validateIdentifier(\n \"appRole\",\n options.appRole ?? (process.env.OPENGENI_APP_DATABASE_USER?.trim() || \"opengeni_app\"),\n );\n const appPassword = options.appPassword ?? process.env.OPENGENI_APP_DATABASE_PASSWORD;\n const hostExportRole = validateIdentifier(\n \"hostExportRole\",\n options.hostExportRole ??\n (process.env.OPENGENI_HOST_EXPORT_DATABASE_USER?.trim() || \"opengeni_host_exporter\"),\n );\n const hostExportPassword =\n options.hostExportPassword ?? process.env.OPENGENI_HOST_EXPORT_DATABASE_PASSWORD;\n const temporalRole = validateIdentifier(\n \"temporalRole\",\n options.temporalRole ??\n (process.env.OPENGENI_TEMPORAL_DATABASE_USER?.trim() || \"opengeni_temporal\"),\n );\n const temporalPassword =\n options.temporalPassword ?? process.env.OPENGENI_TEMPORAL_DATABASE_PASSWORD;\n const temporalDatabases = (\n options.temporalDatabases ??\n commaSeparated(process.env.OPENGENI_TEMPORAL_DATABASES ?? \"temporal,temporal_visibility\")\n ).map((name) => validateIdentifier(\"temporalDatabases\", name));\n\n const sql = postgres(adminConnection, { max: 1 });\n try {\n // FORCE strategy provisions the non-owner app role OpenGeni connects as.\n // SCOPED strategy: the host owns the connection role; OpenGeni provisions no\n // app role (skipped here), only the optional Temporal role.\n let provisionedAppRole: string | null = null;\n if (rlsStrategy === \"force\") {\n if (!appPassword) {\n throw new Error(\n \"OPENGENI_APP_DATABASE_PASSWORD (or appPassword) is required for rlsStrategy 'force'\",\n );\n }\n // Ownership and role-graph edges cannot be safely guessed away. Refuse to\n // mutate an existing role until an operator has explicitly transferred\n // objects/removed memberships; role attributes and direct grants, however,\n // are deterministic and are converged below on every run.\n await assertAppRoleSafeToNormalize(sql, appRole);\n await ensureRestrictedAppLoginRole(sql, appRole, appPassword);\n provisionedAppRole = appRole;\n }\n\n if (temporalPassword) {\n await ensureLoginRole(sql, temporalRole, temporalPassword);\n for (const database of temporalDatabases) {\n await ensureDatabase(sql, database, temporalRole);\n await grantTemporalRoleInDatabase(adminConnection, database, temporalRole);\n }\n }\n\n if (hostExportPassword) {\n await ensureLoginRole(sql, hostExportRole, hostExportPassword);\n await grantHostExportRoleIfSchemaExists(sql, hostExportRole);\n }\n\n if (rlsStrategy === \"force\") {\n await grantAppRoleIfSchemaExists(sql, appRole, schema);\n }\n\n return {\n appRole: provisionedAppRole,\n hostExportRole: hostExportPassword ? hostExportRole : null,\n temporalRole: temporalPassword ? temporalRole : null,\n temporalDatabases: temporalPassword ? temporalDatabases : [],\n schema,\n rlsStrategy,\n };\n } finally {\n await sql.end();\n }\n}\n\n/**\n * The exporter is intentionally separate from `opengeni_app`: its functions\n * project every workspace into a host-owned sink and therefore cannot be made\n * available to the tenant-scoped application role.\n */\nasync function grantHostExportRoleIfSchemaExists(sql: postgres.Sql, role: string): Promise<void> {\n await sql.unsafe(`\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = 'opengeni_host_export') THEN\n EXECUTE format('GRANT USAGE ON SCHEMA opengeni_host_export TO %I', ${literal(role)});\n EXECUTE format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA opengeni_host_export TO %I', ${literal(role)});\n EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA opengeni_host_export GRANT EXECUTE ON FUNCTIONS TO %I', ${literal(role)});\n END IF;\nEND $$;\n`);\n}\n\nasync function ensureLoginRole(sql: postgres.Sql, role: string, password: string): Promise<void> {\n await sql.unsafe(`\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = ${literal(role)}) THEN\n EXECUTE format('CREATE ROLE %I LOGIN PASSWORD %L', ${literal(role)}, ${literal(password)});\n ELSE\n EXECUTE format('ALTER ROLE %I LOGIN PASSWORD %L', ${literal(role)}, ${literal(password)});\n END IF;\nEND $$;\n`);\n}\n\nasync function ensureRestrictedAppLoginRole(\n sql: postgres.Sql,\n role: string,\n password: string,\n): Promise<void> {\n await sql.unsafe(`\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = ${literal(role)}) THEN\n EXECUTE format(\n 'CREATE ROLE %I WITH LOGIN NOSUPERUSER NOBYPASSRLS NOCREATEROLE NOCREATEDB NOREPLICATION NOINHERIT PASSWORD %L',\n ${literal(role)},\n ${literal(password)}\n );\n ELSE\n EXECUTE format(\n 'ALTER ROLE %I WITH LOGIN NOSUPERUSER NOBYPASSRLS NOCREATEROLE NOCREATEDB NOREPLICATION NOINHERIT PASSWORD %L',\n ${literal(role)},\n ${literal(password)}\n );\n END IF;\nEND $$;\n`);\n}\n\n/**\n * Fail rather than silently revoking role relationships or transferring owned\n * objects. Those operations have effects outside OpenGeni's runtime grant\n * contract and require an explicit, audited operator decision.\n */\nasync function assertAppRoleSafeToNormalize(sql: postgres.Sql, role: string): Promise<void> {\n const exists = await sql<{ exists: boolean }[]>`\n select exists(select 1 from pg_roles where rolname = ${role}) as exists\n `;\n if (!exists[0]?.exists) {\n return;\n }\n\n const memberships = await sql<{ relationship: string }[]>`\n select ('inherits:' || parent.rolname)::text as relationship\n from pg_auth_members membership\n join pg_roles member on member.oid = membership.member\n join pg_roles parent on parent.oid = membership.roleid\n where member.rolname = ${role}\n union all\n select ('member:' || member.rolname)::text as relationship\n from pg_auth_members membership\n join pg_roles member on member.oid = membership.member\n join pg_roles parent on parent.oid = membership.roleid\n where parent.rolname = ${role}\n order by relationship\n `;\n if (memberships.length > 0) {\n throw new Error(\n `Refusing to normalize app role ${role}: remove role relationships first (${memberships\n .map((row) => row.relationship)\n .join(\", \")})`,\n );\n }\n\n const ownedObjects = await sql<{ object_name: string }[]>`\n select ('database:' || d.datname)::text as object_name\n from pg_database d\n join pg_roles owner on owner.oid = d.datdba\n where owner.rolname = ${role}\n union all\n select ('schema:' || n.nspname)::text as object_name\n from pg_namespace n\n join pg_roles owner on owner.oid = n.nspowner\n where owner.rolname = ${role}\n and n.nspname <> 'information_schema'\n and n.nspname !~ '^pg_'\n union all\n select ('relation:' || n.nspname || '.' || c.relname)::text as object_name\n from pg_class c\n join pg_namespace n on n.oid = c.relnamespace\n join pg_roles owner on owner.oid = c.relowner\n where owner.rolname = ${role}\n and n.nspname <> 'information_schema'\n and n.nspname !~ '^pg_'\n union all\n select (\n 'routine:' || n.nspname || '.' || p.proname || '(' ||\n pg_get_function_identity_arguments(p.oid) || ')'\n )::text as object_name\n from pg_proc p\n join pg_namespace n on n.oid = p.pronamespace\n join pg_roles owner on owner.oid = p.proowner\n where owner.rolname = ${role}\n and n.nspname <> 'information_schema'\n and n.nspname !~ '^pg_'\n order by object_name\n `;\n if (ownedObjects.length > 0) {\n throw new Error(\n `Refusing to normalize app role ${role}: transfer owned objects first (${ownedObjects\n .map((row) => row.object_name)\n .join(\", \")})`,\n );\n }\n}\n\nasync function ensureDatabase(sql: postgres.Sql, database: string, owner: string): Promise<void> {\n const existing = await sql<{ exists: boolean }[]>`\n select exists(select 1 from pg_database where datname = ${database}) as exists\n `;\n if (!existing[0]?.exists) {\n await sql.unsafe(`CREATE DATABASE ${identifier(database)} OWNER ${identifier(owner)}`);\n }\n await sql.unsafe(\n `GRANT ALL PRIVILEGES ON DATABASE ${identifier(database)} TO ${identifier(owner)}`,\n );\n}\n\nasync function grantTemporalRoleInDatabase(\n adminConnection: string,\n database: string,\n role: string,\n): Promise<void> {\n const databaseUrl = databaseUrlFor(adminConnection, database);\n const databaseSql = postgres(databaseUrl, { max: 1 });\n try {\n await databaseSql.unsafe(`GRANT USAGE, CREATE ON SCHEMA public TO ${identifier(role)}`);\n } finally {\n await databaseSql.end();\n }\n}\n\n/**\n * Grant the app role table DML in the OpenGeni data schema + EXECUTE on the\n * `opengeni_private` helper functions. Schema-parameterized (Step I): standalone\n * passes `public`; embedded passes the dedicated schema. The grants are guarded\n * on schema existence so provisioning before migrate is a safe no-op.\n */\nasync function grantAppRoleIfSchemaExists(\n sql: postgres.Sql,\n role: string,\n schema: string,\n): Promise<void> {\n const runtimeFullDmlTables = `ARRAY[${RUNTIME_FULL_DML_TABLES.map(literal).join(\", \")}]`;\n const runtimeReadOnlyTables = `ARRAY[${RUNTIME_READ_ONLY_TABLES.map(literal).join(\", \")}]`;\n const runtimeReadInsertTables = `ARRAY[${RUNTIME_READ_INSERT_TABLES.map(literal).join(\", \")}]`;\n await sql.unsafe(`\nDO $$\nDECLARE\n owner_role text := current_user;\n runtime_table text;\nBEGIN\n EXECUTE format('REVOKE CREATE ON DATABASE %I FROM %I', current_database(), ${literal(role)});\n IF EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = ${literal(schema)}) THEN\n EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', ${literal(schema)}, ${literal(role)});\n EXECUTE format('REVOKE CREATE ON SCHEMA %I FROM %I', ${literal(schema)}, ${literal(role)});\n EXECUTE format('REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA %I FROM %I', ${literal(schema)}, ${literal(role)});\n FOREACH runtime_table IN ARRAY ${runtimeFullDmlTables} LOOP\n IF to_regclass(format('%I.%I', ${literal(schema)}, runtime_table)) IS NOT NULL THEN\n EXECUTE format(\n 'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE %I.%I TO %I',\n ${literal(schema)},\n runtime_table,\n ${literal(role)}\n );\n END IF;\n END LOOP;\n FOREACH runtime_table IN ARRAY ${runtimeReadOnlyTables} LOOP\n IF to_regclass(format('%I.%I', ${literal(schema)}, runtime_table)) IS NOT NULL THEN\n EXECUTE format(\n 'GRANT SELECT ON TABLE %I.%I TO %I',\n ${literal(schema)},\n runtime_table,\n ${literal(role)}\n );\n END IF;\n END LOOP;\n FOREACH runtime_table IN ARRAY ${runtimeReadInsertTables} LOOP\n IF to_regclass(format('%I.%I', ${literal(schema)}, runtime_table)) IS NOT NULL THEN\n EXECUTE format(\n 'GRANT SELECT, INSERT ON TABLE %I.%I TO %I',\n ${literal(schema)},\n runtime_table,\n ${literal(role)}\n );\n END IF;\n END LOOP;\n -- Migration 0110 creates this target-schema-local SECURITY DEFINER\n -- capability before opengeni_app may exist. Re-converge its exact EXECUTE\n -- grant here so the supported migrate-then-provision order is equivalent to\n -- provisioning the role before that migration.\n IF to_regprocedure(\n format('%I.lock_nested_agent_depth_configuration()', ${literal(schema)})\n ) IS NOT NULL THEN\n EXECUTE format(\n 'GRANT EXECUTE ON FUNCTION %I.lock_nested_agent_depth_configuration() TO %I',\n ${literal(schema)},\n ${literal(role)}\n );\n END IF;\n EXECUTE format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA %I TO %I', ${literal(schema)}, ${literal(role)});\n EXECUTE format(\n 'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA %I REVOKE ALL PRIVILEGES ON TABLES FROM %I',\n owner_role,\n ${literal(schema)},\n ${literal(role)}\n );\n EXECUTE format(\n 'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA %I GRANT USAGE, SELECT ON SEQUENCES TO %I',\n owner_role,\n ${literal(schema)},\n ${literal(role)}\n );\n END IF;\n IF EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = 'opengeni_private') THEN\n EXECUTE format('GRANT USAGE ON SCHEMA opengeni_private TO %I', ${literal(role)});\n EXECUTE format('REVOKE CREATE ON SCHEMA opengeni_private FROM %I', ${literal(role)});\n EXECUTE format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA opengeni_private TO %I', ${literal(role)});\n EXECUTE format(\n 'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA opengeni_private GRANT EXECUTE ON FUNCTIONS TO %I',\n owner_role,\n ${literal(role)}\n );\n END IF;\nEND $$;\n`);\n}\n\nfunction commaSeparated(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\nfunction validateIdentifier(name: string, value: string): string {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {\n throw new Error(`${name} contains an invalid Postgres identifier: ${value}`);\n }\n return value;\n}\n\nfunction identifier(value: string): string {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction literal(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`;\n}\n\nfunction databaseUrlFor(value: string, database: string): string {\n const url = new URL(value);\n url.pathname = `/${database}`;\n return url.toString();\n}\n\n// CLI form (unchanged behavior): read env into the SDK options and run. This is\n// what `bun src/provision-roles.ts` / the `provision-roles` package script\n// invokes — standalone byte-for-byte the historical script (public schema,\n// force strategy, env-driven creds).\nif (import.meta.main) {\n const adminUrl =\n process.env.OPENGENI_MIGRATIONS_DATABASE_URL ??\n process.env.OPENGENI_DATABASE_ADMIN_URL ??\n process.env.OPENGENI_DATABASE_URL;\n if (!adminUrl) {\n throw new Error(\n \"OPENGENI_MIGRATIONS_DATABASE_URL, OPENGENI_DATABASE_ADMIN_URL, or OPENGENI_DATABASE_URL is required\",\n );\n }\n const result = await provisionRoles(adminUrl, {\n ...(process.env.OPENGENI_DB_SCHEMA?.trim()\n ? { targetSchema: process.env.OPENGENI_DB_SCHEMA.trim() }\n : {}),\n });\n console.log(JSON.stringify(result, null, 2));\n}\n","import { sql } from \"drizzle-orm\";\nimport type { Database, RlsStrategy } from \"./index\";\n\n/**\n * The complete standalone tenant-table contract. Adding or removing a\n * FORCE-RLS table is an architectural change: update this list in the same\n * commit as the migration so startup cannot silently accept an unreviewed gap.\n */\nexport const FORCE_RLS_TABLES = [\n \"agent_run_states\",\n \"api_keys\",\n \"audit_events\",\n \"billing_customers\",\n \"capability_catalog_items\",\n \"capability_installations\",\n \"codex_capacity_waiters\",\n \"codex_credential_leases\",\n \"codex_reset_redemption_attempts\",\n \"codex_rotation_settings\",\n \"codex_subscription_credentials\",\n \"composer_drafts\",\n \"connections\",\n \"credit_ledger_entries\",\n \"device_enrollment_requests\",\n \"document_bases\",\n \"document_chunks\",\n \"documents\",\n \"enrollments\",\n \"file_uploads\",\n \"files\",\n \"github_installation_repositories\",\n \"github_installations\",\n \"host_export_config\",\n \"host_export_consumers\",\n \"host_export_cursor_state\",\n \"host_export_dead_letters\",\n \"host_export_outbox\",\n \"import_batches\",\n \"integration_oauth_state_nonces\",\n \"knowledge_memories\",\n \"machine_metrics_latest\",\n \"machine_metrics_series\",\n \"new_session_drafts\",\n \"pack_installations\",\n \"rig_changes\",\n \"rig_versions\",\n \"rigs\",\n \"sandbox_lease_holders\",\n \"sandbox_leases\",\n \"sandbox_pty_sessions\",\n \"sandbox_retained_processes\",\n \"sandbox_session_envelopes\",\n \"sandbox_workspace_mutation_admissions\",\n \"sandboxes\",\n \"scheduled_task_runs\",\n \"scheduled_tasks\",\n \"session_attempt_interruptions\",\n \"session_command_receipts\",\n \"session_events\",\n \"session_goals\",\n \"session_history_items\",\n \"session_human_input_requests\",\n \"session_list_snapshots\",\n \"session_mcp_servers\",\n \"session_pending_tool_calls\",\n \"session_pins\",\n \"session_recordings\",\n \"session_spawn_denials\",\n \"session_stream_acknowledgments\",\n \"session_system_update_outbox\",\n \"session_system_updates\",\n \"session_turn_attempts\",\n \"session_turns\",\n \"session_workflow_wake_outbox\",\n \"sessions\",\n \"slack_bot_post_operations\",\n \"social_connections\",\n \"social_posts\",\n \"usage_events\",\n \"workspace_captures\",\n \"workspace_control_events\",\n \"workspace_inference_controls\",\n \"workspace_instruction_policy_activation_events\",\n \"workspace_instruction_policy_heads\",\n \"workspace_instruction_policy_revisions\",\n \"workspace_model_policies\",\n \"workspace_packs\",\n \"workspace_session_activity_revisions\",\n \"workspace_variable_set_variables\",\n \"workspace_variable_sets\",\n] as const;\n\n/**\n * Deployment-global and authentication tables used by ordinary API/worker\n * traffic. They intentionally do not carry workspace RLS: their access model\n * is implemented by the authentication/access layer or by exact global keys.\n */\nexport const NON_RLS_RUNTIME_TABLES = [\n \"auth_identities\",\n \"auth_rate_limits\",\n \"auth_sessions\",\n \"auth_users\",\n \"auth_verifications\",\n \"integration_oauth_clients\",\n \"managed_accounts\",\n \"nested_agent_depth_configuration\",\n \"stripe_webhook_events\",\n \"workspace_memberships\",\n \"workspaces\",\n] as const;\n\n/**\n * Exact full-CRUD class for the standalone runtime role. This is deliberately\n * explicit instead of being derived from FORCE_RLS_TABLES: adding a protected\n * table must not silently grant it broader DML than its migration intended.\n */\nexport const RUNTIME_FULL_DML_TABLES = [\n \"agent_run_states\",\n \"api_keys\",\n \"audit_events\",\n \"auth_identities\",\n \"auth_rate_limits\",\n \"auth_sessions\",\n \"auth_users\",\n \"auth_verifications\",\n \"billing_customers\",\n \"capability_catalog_items\",\n \"capability_installations\",\n \"codex_capacity_waiters\",\n \"codex_credential_leases\",\n \"codex_reset_redemption_attempts\",\n \"codex_rotation_settings\",\n \"codex_subscription_credentials\",\n \"composer_drafts\",\n \"connections\",\n \"credit_ledger_entries\",\n \"device_enrollment_requests\",\n \"document_bases\",\n \"document_chunks\",\n \"documents\",\n \"enrollments\",\n \"file_uploads\",\n \"files\",\n \"github_installation_repositories\",\n \"github_installations\",\n \"import_batches\",\n \"integration_oauth_clients\",\n \"integration_oauth_state_nonces\",\n \"knowledge_memories\",\n \"machine_metrics_latest\",\n \"machine_metrics_series\",\n \"managed_accounts\",\n \"new_session_drafts\",\n \"pack_installations\",\n \"rig_changes\",\n \"rig_versions\",\n \"rigs\",\n \"sandbox_lease_holders\",\n \"sandbox_leases\",\n \"sandbox_pty_sessions\",\n \"sandbox_retained_processes\",\n \"sandbox_session_envelopes\",\n \"sandbox_workspace_mutation_admissions\",\n \"sandboxes\",\n \"scheduled_task_runs\",\n \"scheduled_tasks\",\n \"session_attempt_interruptions\",\n \"session_command_receipts\",\n \"session_events\",\n \"session_goals\",\n \"session_history_items\",\n \"session_human_input_requests\",\n \"session_list_snapshots\",\n \"session_mcp_servers\",\n \"session_pending_tool_calls\",\n \"session_pins\",\n \"session_recordings\",\n \"session_stream_acknowledgments\",\n \"session_system_update_outbox\",\n \"session_system_updates\",\n \"session_turn_attempts\",\n \"session_turns\",\n \"session_workflow_wake_outbox\",\n \"sessions\",\n \"slack_bot_post_operations\",\n \"social_connections\",\n \"social_posts\",\n \"stripe_webhook_events\",\n \"usage_events\",\n \"workspace_captures\",\n \"workspace_control_events\",\n \"workspace_inference_controls\",\n \"workspace_instruction_policy_heads\",\n \"workspace_memberships\",\n \"workspace_model_policies\",\n \"workspace_packs\",\n \"workspace_session_activity_revisions\",\n \"workspace_variable_set_variables\",\n \"workspace_variable_sets\",\n \"workspaces\",\n] as const;\n\n/** Configuration is deployment-global and intentionally read-only at runtime. */\nexport const RUNTIME_READ_ONLY_TABLES = [\"nested_agent_depth_configuration\"] as const;\n\n/** Append-only evidence/revision tables are insertable and queryable, never mutable. */\nexport const RUNTIME_READ_INSERT_TABLES = [\n \"session_spawn_denials\",\n \"workspace_instruction_policy_activation_events\",\n \"workspace_instruction_policy_revisions\",\n] as const;\n\n/**\n * These FORCE-RLS tables are owned by security-definer host-export routines.\n * The ordinary application role must have no direct table privileges on them.\n */\nexport const PROTECTED_NO_DIRECT_DML_TABLES = [\n \"host_export_config\",\n \"host_export_consumers\",\n \"host_export_cursor_state\",\n \"host_export_dead_letters\",\n \"host_export_outbox\",\n] as const;\n\nexport type RuntimeTableDmlPrivilege = \"SELECT\" | \"INSERT\" | \"UPDATE\" | \"DELETE\";\nexport type RuntimeTablePrivilegeContract = Readonly<\n Record<string, readonly RuntimeTableDmlPrivilege[]>\n>;\n\nconst FULL_DML_PRIVILEGES = [\"SELECT\", \"INSERT\", \"UPDATE\", \"DELETE\"] as const;\n\n/** Exact per-table DML contract. Absence means no direct table privileges. */\nexport const RUNTIME_TABLE_PRIVILEGES: RuntimeTablePrivilegeContract = Object.freeze({\n ...Object.fromEntries(RUNTIME_FULL_DML_TABLES.map((table) => [table, FULL_DML_PRIVILEGES])),\n ...Object.fromEntries(RUNTIME_READ_ONLY_TABLES.map((table) => [table, [\"SELECT\"] as const])),\n ...Object.fromEntries(\n RUNTIME_READ_INSERT_TABLES.map((table) => [table, [\"SELECT\", \"INSERT\"] as const]),\n ),\n});\n\n/** All tables with any direct runtime DML; retained as the aggregate public contract. */\nexport const RUNTIME_DML_TABLES = Object.freeze(\n Object.keys(RUNTIME_TABLE_PRIVILEGES).sort((a, b) => a.localeCompare(b)),\n);\n\nexport type RuntimeDatabasePostureOptions = {\n rlsStrategy: RlsStrategy;\n expectedRole?: string;\n targetSchema?: string;\n protectedTables?: readonly string[];\n tablePrivileges?: RuntimeTablePrivilegeContract;\n protectedNoDirectDmlTables?: readonly string[];\n};\n\nexport type RuntimeDatabaseIdentity = {\n currentUser: string;\n sessionUser: string;\n databaseOwner: string;\n canConnectDatabase: boolean;\n canCreateInDatabase: boolean;\n rowSecurity: string;\n canLogin: boolean;\n superuser: boolean;\n inherit: boolean;\n createRole: boolean;\n createDatabase: boolean;\n replication: boolean;\n bypassRls: boolean;\n};\n\nexport type RuntimeSchemaPosture = {\n name: string;\n owner: string;\n usage: boolean;\n create: boolean;\n};\n\nexport type RuntimeTablePosture = {\n name: string;\n owner: string;\n rlsEnabled: boolean;\n rlsForced: boolean;\n rlsActive: boolean;\n policyCount: number;\n select: boolean;\n insert: boolean;\n update: boolean;\n delete: boolean;\n truncate: boolean;\n references: boolean;\n trigger: boolean;\n};\n\nexport type RuntimeRoutinePosture = {\n name: string;\n owner: string;\n execute: boolean;\n};\n\nexport type RuntimeDatabasePosture = {\n identity: RuntimeDatabaseIdentity;\n memberships: string[];\n schemas: RuntimeSchemaPosture[];\n ownedSchemas: string[];\n ownedRelations: string[];\n tables: RuntimeTablePosture[];\n privateRoutines: RuntimeRoutinePosture[];\n};\n\nexport class RuntimeDatabasePostureError extends Error {\n readonly violations: readonly string[];\n\n constructor(violations: readonly string[]) {\n super(`Runtime database posture check failed: ${violations.join(\"; \")}`);\n this.name = \"RuntimeDatabasePostureError\";\n this.violations = violations;\n }\n}\n\ntype IdentityRow = {\n current_user: string;\n session_user: string;\n database_owner: string;\n can_connect_database: boolean;\n can_create_in_database: boolean;\n row_security: string;\n rolcanlogin: boolean;\n rolsuper: boolean;\n rolinherit: boolean;\n rolcreaterole: boolean;\n rolcreatedb: boolean;\n rolreplication: boolean;\n rolbypassrls: boolean;\n};\n\nfunction resultRows<T>(result: unknown): T[] {\n if (Array.isArray(result)) {\n return result as T[];\n }\n const rows = (result as { rows?: unknown } | null)?.rows;\n if (Array.isArray(rows)) {\n return rows as T[];\n }\n throw new Error(\"Runtime database posture query returned an unsupported result shape\");\n}\n\nfunction sorted(values: Iterable<string>): string[] {\n return [...values].sort((a, b) => a.localeCompare(b));\n}\n\nfunction difference(left: ReadonlySet<string>, right: ReadonlySet<string>): string[] {\n return sorted([...left].filter((value) => !right.has(value)));\n}\n\n/** Inspect only PostgreSQL catalogs and privilege functions; no tenant rows. */\nexport async function inspectRuntimeDatabasePosture(\n db: Database,\n options: RuntimeDatabasePostureOptions,\n): Promise<RuntimeDatabasePosture> {\n const targetSchema = options.targetSchema?.trim() || \"public\";\n\n return await db.transaction(\n async (tx) => {\n const identityRows = resultRows<IdentityRow>(\n await tx.execute(sql`\n select\n current_user::text as current_user,\n session_user::text as session_user,\n pg_get_userbyid(d.datdba)::text as database_owner,\n has_database_privilege(current_user, d.oid, 'CONNECT') as can_connect_database,\n has_database_privilege(current_user, d.oid, 'CREATE') as can_create_in_database,\n current_setting('row_security')::text as row_security,\n r.rolcanlogin,\n r.rolsuper,\n r.rolinherit,\n r.rolcreaterole,\n r.rolcreatedb,\n r.rolreplication,\n r.rolbypassrls\n from pg_roles r\n join pg_database d on d.datname = current_database()\n where r.rolname = current_user\n `),\n );\n const identity = identityRows[0];\n if (!identity) {\n throw new Error(\"Runtime database posture could not resolve the current PostgreSQL role\");\n }\n\n const mappedIdentity: RuntimeDatabaseIdentity = {\n currentUser: identity.current_user,\n sessionUser: identity.session_user,\n databaseOwner: identity.database_owner,\n canConnectDatabase: identity.can_connect_database,\n canCreateInDatabase: identity.can_create_in_database,\n rowSecurity: identity.row_security,\n canLogin: identity.rolcanlogin,\n superuser: identity.rolsuper,\n inherit: identity.rolinherit,\n createRole: identity.rolcreaterole,\n createDatabase: identity.rolcreatedb,\n replication: identity.rolreplication,\n bypassRls: identity.rolbypassrls,\n };\n\n // Scoped/embedded topology deliberately leaves ownership and isolation to\n // the host. Prove the connection identity is coherent, but do not impose\n // the standalone opengeni_app object/grant contract on the host's role.\n if (options.rlsStrategy === \"scoped\") {\n return {\n identity: mappedIdentity,\n memberships: [],\n schemas: [],\n ownedSchemas: [],\n ownedRelations: [],\n tables: [],\n privateRoutines: [],\n };\n }\n\n const memberships = resultRows<{ relationship: string }>(\n await tx.execute(sql`\n with recursive inherited_roles(oid, rolname) as (\n select parent.oid, parent.rolname\n from pg_auth_members membership\n join pg_roles member on member.oid = membership.member\n join pg_roles parent on parent.oid = membership.roleid\n where member.rolname = current_user\n union\n select parent.oid, parent.rolname\n from inherited_roles inherited\n join pg_auth_members membership on membership.member = inherited.oid\n join pg_roles parent on parent.oid = membership.roleid\n )\n select ('inherits:' || rolname)::text as relationship from inherited_roles\n union\n select ('member:' || member.rolname)::text as relationship\n from pg_auth_members membership\n join pg_roles parent on parent.oid = membership.roleid\n join pg_roles member on member.oid = membership.member\n where parent.rolname = current_user\n order by relationship\n `),\n ).map((row) => row.relationship);\n\n const schemas = resultRows<{\n name: string;\n owner: string;\n usage: boolean;\n create: boolean;\n }>(\n await tx.execute(sql`\n select\n n.nspname::text as name,\n pg_get_userbyid(n.nspowner)::text as owner,\n has_schema_privilege(current_user, n.oid, 'USAGE') as usage,\n has_schema_privilege(current_user, n.oid, 'CREATE') as create\n from pg_namespace n\n where n.nspname in (${targetSchema}, 'opengeni_private')\n order by n.nspname\n `),\n );\n\n const ownedSchemas = resultRows<{ name: string }>(\n await tx.execute(sql`\n select n.nspname::text as name\n from pg_namespace n\n join pg_roles r on r.oid = n.nspowner\n where r.rolname = current_user\n and n.nspname <> 'information_schema'\n and n.nspname !~ '^pg_'\n order by n.nspname\n `),\n ).map((row) => row.name);\n\n const ownedRelations = resultRows<{ name: string }>(\n await tx.execute(sql`\n select (n.nspname || '.' || c.relname)::text as name\n from pg_class c\n join pg_namespace n on n.oid = c.relnamespace\n join pg_roles r on r.oid = c.relowner\n where r.rolname = current_user\n and c.relkind in ('r', 'p', 'S', 'v', 'm', 'f')\n and n.nspname <> 'information_schema'\n and n.nspname !~ '^pg_'\n order by n.nspname, c.relname\n `),\n ).map((row) => row.name);\n\n const tables = resultRows<{\n name: string;\n owner: string;\n rls_enabled: boolean;\n rls_forced: boolean;\n rls_active: boolean;\n policy_count: number;\n can_select: boolean;\n can_insert: boolean;\n can_update: boolean;\n can_delete: boolean;\n can_truncate: boolean;\n can_references: boolean;\n can_trigger: boolean;\n }>(\n await tx.execute(sql`\n select\n c.relname::text as name,\n pg_get_userbyid(c.relowner)::text as owner,\n c.relrowsecurity as rls_enabled,\n c.relforcerowsecurity as rls_forced,\n row_security_active(c.oid) as rls_active,\n (select count(*)::int from pg_policy policy where policy.polrelid = c.oid) as policy_count,\n has_table_privilege(current_user, c.oid, 'SELECT') as can_select,\n has_table_privilege(current_user, c.oid, 'INSERT') as can_insert,\n has_table_privilege(current_user, c.oid, 'UPDATE') as can_update,\n has_table_privilege(current_user, c.oid, 'DELETE') as can_delete,\n has_table_privilege(current_user, c.oid, 'TRUNCATE') as can_truncate,\n has_table_privilege(current_user, c.oid, 'REFERENCES') as can_references,\n has_table_privilege(current_user, c.oid, 'TRIGGER') as can_trigger\n from pg_class c\n join pg_namespace n on n.oid = c.relnamespace\n where n.nspname = ${targetSchema}\n and c.relkind in ('r', 'p')\n order by c.relname\n `),\n ).map((row) => ({\n name: row.name,\n owner: row.owner,\n rlsEnabled: row.rls_enabled,\n rlsForced: row.rls_forced,\n rlsActive: row.rls_active,\n policyCount: row.policy_count,\n select: row.can_select,\n insert: row.can_insert,\n update: row.can_update,\n delete: row.can_delete,\n truncate: row.can_truncate,\n references: row.can_references,\n trigger: row.can_trigger,\n }));\n\n const privateRoutines = resultRows<{\n name: string;\n owner: string;\n can_execute: boolean;\n }>(\n await tx.execute(sql`\n select\n (p.proname || '(' || pg_get_function_identity_arguments(p.oid) || ')')::text as name,\n pg_get_userbyid(p.proowner)::text as owner,\n has_function_privilege(current_user, p.oid, 'EXECUTE') as can_execute\n from pg_proc p\n join pg_namespace n on n.oid = p.pronamespace\n where n.nspname = 'opengeni_private'\n and p.prokind in ('f', 'p')\n order by p.proname, pg_get_function_identity_arguments(p.oid)\n `),\n ).map((row) => ({ name: row.name, owner: row.owner, execute: row.can_execute }));\n\n return {\n identity: mappedIdentity,\n memberships,\n schemas,\n ownedSchemas,\n ownedRelations,\n tables,\n privateRoutines,\n };\n },\n { isolationLevel: \"repeatable read\", accessMode: \"read only\" },\n );\n}\n\n/** Pure deterministic evaluator used by startup/readiness and unit tests. */\nexport function evaluateRuntimeDatabasePosture(\n posture: RuntimeDatabasePosture,\n options: RuntimeDatabasePostureOptions,\n): string[] {\n const violations: string[] = [];\n const identity = posture.identity;\n\n if (!identity.currentUser || !identity.sessionUser) {\n violations.push(\"database identity is empty\");\n }\n if (identity.currentUser !== identity.sessionUser) {\n violations.push(\n `current_user ${identity.currentUser} does not match session_user ${identity.sessionUser}`,\n );\n }\n if (!identity.canConnectDatabase) {\n violations.push(\"runtime role lacks CONNECT on the current database\");\n }\n\n if (options.rlsStrategy === \"scoped\") {\n return violations;\n }\n\n const expectedRole = options.expectedRole?.trim() || \"opengeni_app\";\n const targetSchema = options.targetSchema?.trim() || \"public\";\n const protectedTables = new Set(options.protectedTables ?? FORCE_RLS_TABLES);\n const tablePrivileges = options.tablePrivileges ?? RUNTIME_TABLE_PRIVILEGES;\n const directRuntimeTables = new Set(Object.keys(tablePrivileges));\n const protectedNoDirectDmlTables = new Set(\n options.protectedNoDirectDmlTables ??\n (options.protectedTables ? [] : PROTECTED_NO_DIRECT_DML_TABLES),\n );\n\n if (identity.currentUser !== expectedRole || identity.sessionUser !== expectedRole) {\n violations.push(\n `runtime identity must be ${expectedRole} (current_user=${identity.currentUser}, session_user=${identity.sessionUser})`,\n );\n }\n if (!identity.canLogin) violations.push(\"runtime role is not LOGIN\");\n if (identity.superuser) violations.push(\"runtime role is SUPERUSER\");\n if (identity.bypassRls) violations.push(\"runtime role has BYPASSRLS\");\n if (identity.createRole) violations.push(\"runtime role has CREATEROLE\");\n if (identity.createDatabase) violations.push(\"runtime role has CREATEDB\");\n if (identity.replication) violations.push(\"runtime role has REPLICATION\");\n if (identity.inherit) violations.push(\"runtime role must be NOINHERIT\");\n if (identity.databaseOwner === expectedRole) violations.push(\"runtime role owns the database\");\n if (identity.canCreateInDatabase) {\n violations.push(\"runtime role has CREATE on the current database\");\n }\n if (identity.rowSecurity.toLowerCase() !== \"on\") {\n violations.push(`row_security is ${identity.rowSecurity}, expected on`);\n }\n if (posture.memberships.length > 0) {\n violations.push(`runtime role has memberships: ${sorted(posture.memberships).join(\", \")}`);\n }\n if (posture.ownedSchemas.length > 0) {\n violations.push(`runtime role owns schemas: ${sorted(posture.ownedSchemas).join(\", \")}`);\n }\n if (posture.ownedRelations.length > 0) {\n violations.push(`runtime role owns relations: ${sorted(posture.ownedRelations).join(\", \")}`);\n }\n\n for (const schemaName of new Set([targetSchema, \"opengeni_private\"])) {\n const schema = posture.schemas.find((candidate) => candidate.name === schemaName);\n if (!schema) {\n violations.push(`required schema ${schemaName} is missing`);\n continue;\n }\n if (schema.owner === expectedRole) {\n violations.push(`runtime role owns schema ${schemaName}`);\n }\n if (!schema.usage) violations.push(`runtime role lacks USAGE on schema ${schemaName}`);\n if (schema.create) violations.push(`runtime role has CREATE on schema ${schemaName}`);\n }\n\n const tableByName = new Map(posture.tables.map((table) => [table.name, table]));\n const actualRlsTables = new Set(\n posture.tables.filter((table) => table.rlsEnabled).map((table) => table.name),\n );\n const classifiedProtectedTables = new Set([\n ...directRuntimeTables,\n ...protectedNoDirectDmlTables,\n ]);\n const unclassifiedProtectedTables = difference(protectedTables, classifiedProtectedTables);\n if (unclassifiedProtectedTables.length > 0) {\n violations.push(\n `protected tables lack an explicit privilege class: ${unclassifiedProtectedTables.join(\", \")}`,\n );\n }\n const protectedNoDirectDmlOverlap = difference(\n protectedNoDirectDmlTables,\n new Set([...protectedNoDirectDmlTables].filter((table) => !directRuntimeTables.has(table))),\n );\n if (protectedNoDirectDmlOverlap.length > 0) {\n violations.push(\n `protected no-direct-DML tables also declare runtime privileges: ${protectedNoDirectDmlOverlap.join(\", \")}`,\n );\n }\n const nonProtectedNoDirectDmlTables = difference(protectedNoDirectDmlTables, protectedTables);\n if (nonProtectedNoDirectDmlTables.length > 0) {\n violations.push(\n `no-direct-DML tables are absent from the protected contract: ${nonProtectedNoDirectDmlTables.join(\", \")}`,\n );\n }\n const catalogTables = new Set(tableByName.keys());\n const missingRuntimeTables = difference(directRuntimeTables, catalogTables);\n if (missingRuntimeTables.length > 0) {\n violations.push(`runtime privilege tables are missing: ${missingRuntimeTables.join(\", \")}`);\n }\n const missingTables = difference(protectedTables, catalogTables);\n if (missingTables.length > 0) {\n violations.push(`protected tables are missing: ${missingTables.join(\", \")}`);\n }\n const undeclaredRlsTables = difference(actualRlsTables, protectedTables);\n if (undeclaredRlsTables.length > 0) {\n violations.push(\n `RLS tables are absent from the declared contract: ${undeclaredRlsTables.join(\", \")}`,\n );\n }\n\n for (const table of posture.tables) {\n const privileges = [\n [\"SELECT\", table.select],\n [\"INSERT\", table.insert],\n [\"UPDATE\", table.update],\n [\"DELETE\", table.delete],\n [\"TRUNCATE\", table.truncate],\n [\"REFERENCES\", table.references],\n [\"TRIGGER\", table.trigger],\n ] as const;\n const expectedPrivileges = new Set<string>(tablePrivileges[table.name] ?? []);\n if (table.owner === expectedRole) {\n violations.push(`runtime role owns table ${table.name}`);\n }\n const missingPrivileges = privileges\n .filter(([privilege, granted]) => expectedPrivileges.has(privilege) && !granted)\n .map(([privilege]) => privilege);\n if (missingPrivileges.length > 0) {\n violations.push(\n `table ${table.name} lacks required runtime privileges: ${missingPrivileges.join(\", \")}`,\n );\n }\n const excessPrivileges = privileges\n .filter(([privilege, granted]) => !expectedPrivileges.has(privilege) && granted)\n .map(([privilege]) => privilege);\n if (excessPrivileges.length > 0) {\n violations.push(\n `table ${table.name} grants excess runtime privileges: ${excessPrivileges.join(\", \")}`,\n );\n }\n }\n\n for (const tableName of protectedTables) {\n const table = tableByName.get(tableName);\n if (!table) continue;\n if (!table.rlsEnabled) violations.push(`table ${tableName} does not ENABLE RLS`);\n if (!table.rlsForced) violations.push(`table ${tableName} does not FORCE RLS`);\n if (!table.rlsActive) violations.push(`table ${tableName} has inactive RLS for runtime role`);\n if (table.policyCount < 1) violations.push(`table ${tableName} has no RLS policy`);\n }\n\n if (posture.privateRoutines.length === 0) {\n violations.push(\"opengeni_private has no helper routines\");\n }\n for (const routine of posture.privateRoutines) {\n if (routine.owner === expectedRole) {\n violations.push(`runtime role owns private routine ${routine.name}`);\n }\n if (!routine.execute) {\n violations.push(`runtime role lacks EXECUTE on private routine ${routine.name}`);\n }\n }\n\n return violations;\n}\n\nexport async function assertRuntimeDatabasePosture(\n db: Database,\n options: RuntimeDatabasePostureOptions,\n): Promise<RuntimeDatabasePosture> {\n const posture = await inspectRuntimeDatabasePosture(db, options);\n const violations = evaluateRuntimeDatabasePosture(posture, options);\n if (violations.length > 0) {\n throw new RuntimeDatabasePostureError(violations);\n }\n return posture;\n}\n\nexport function runtimeDatabaseReadyCheck(\n db: Database,\n options: RuntimeDatabasePostureOptions,\n): () => Promise<void> {\n return async () => {\n await assertRuntimeDatabasePosture(db, options);\n };\n}\n"],"mappings":";AAAA,OAAO,cAAc;;;ACArB,SAAS,WAAW;AAQb,IAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOO,IAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOO,IAAM,0BAA0B;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AA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","names":["sql"]}