@opengeni/db 3.2.0-canary.0 → 3.4.0-canary.0

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 (81) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-SIBYBA2D.js → chunk-6DPJA36C.js} +30 -11
  3. package/dist/chunk-6DPJA36C.js.map +1 -0
  4. package/dist/{chunk-KRLPEMLH.js → chunk-C2AFP7SB.js} +184 -6
  5. package/dist/chunk-C2AFP7SB.js.map +1 -0
  6. package/dist/{chunk-AZHW7R5V.js → chunk-H7MXYG7R.js} +12 -8
  7. package/dist/chunk-H7MXYG7R.js.map +1 -0
  8. package/dist/{chunk-2PRS4J5Q.js → chunk-HY3F5Q4E.js} +3 -3
  9. package/dist/{chunk-NAB6FKFN.js → chunk-O6FTELKH.js} +3 -3
  10. package/dist/{chunk-UZNXG44K.js → chunk-PYMY3AJW.js} +324 -8
  11. package/dist/chunk-PYMY3AJW.js.map +1 -0
  12. package/dist/{chunk-6HMM2R5T.js → chunk-TRBOWUG3.js} +98 -4
  13. package/dist/chunk-TRBOWUG3.js.map +1 -0
  14. package/dist/{chunk-E6CLMKEE.js → chunk-V3TRUXFJ.js} +2 -2
  15. package/dist/{chunk-2EH4WRHL.js → chunk-ZWRIPCTR.js} +2 -2
  16. package/dist/editable-artifact-durable-export.js +2 -2
  17. package/dist/editable-artifacts.js +3 -3
  18. package/dist/governed-learning-activation.d.ts +16 -0
  19. package/dist/index.d.ts +108 -7
  20. package/dist/index.js +3605 -1417
  21. package/dist/index.js.map +1 -1
  22. package/dist/insights-model-bundle.d.ts +30 -0
  23. package/dist/insights-usage-bundle.d.ts +32 -0
  24. package/dist/insights.d.ts +10 -2
  25. package/dist/lossless-json.d.ts +1 -1
  26. package/dist/managed-user-setup.d.ts +82 -0
  27. package/dist/memory-domain.d.ts +2 -2
  28. package/dist/migrate.d.ts +3 -1
  29. package/dist/migrate.js +1 -1
  30. package/dist/new-session-drafts.d.ts +4 -4
  31. package/dist/organization-membership-lifecycle.d.ts +60 -1
  32. package/dist/pr-review.d.ts +44 -3
  33. package/dist/provision-roles.js +1 -1
  34. package/dist/runtime-posture.d.ts +12 -7
  35. package/dist/schema.d.ts +839 -101
  36. package/dist/schema.js +9 -1
  37. package/dist/session-background-commands.js +3 -3
  38. package/dist/session-tenancy.d.ts +12 -1
  39. package/dist/session-tenancy.js +3 -3
  40. package/dist/video-generation.js +3 -3
  41. package/drizzle/0348_named_signup_and_user_setup.sql +838 -0
  42. package/drizzle/0349_greenfield_session_tenancy_activation.sql +792 -0
  43. package/drizzle/0350_organization_shared_workspace_administration.sql +889 -0
  44. package/drizzle/0351_organization_user_setup_delivery.sql +978 -0
  45. package/drizzle/0352_session_variable_set_attachments.sql +1661 -0
  46. package/drizzle/0353_automatic_session_title_policy_fence.sql +476 -0
  47. package/drizzle/0354_automatic_session_title_quarantine_index.sql +9 -0
  48. package/drizzle/0355_automatic_session_title_quarantine.sql +92 -0
  49. package/drizzle/0356_set_based_insights_session_visibility.sql +237 -0
  50. package/drizzle/0357_rig_platform_base_only.sql +44 -0
  51. package/drizzle/0358_pr_review_managed_github_app.sql +108 -0
  52. package/drizzle/0359_insights_force_rls_read_capability.sql +936 -0
  53. package/drizzle/0360_organization_identity_confirmation_prompt.sql +103 -0
  54. package/drizzle/0361_remember_knowledge_memory_materialization.sql +249 -0
  55. package/package.json +6 -6
  56. package/src/database.ts +12 -8
  57. package/src/governed-learning-activation.ts +74 -2
  58. package/src/index.ts +879 -92
  59. package/src/insights-model-bundle.ts +681 -0
  60. package/src/insights-usage-bundle.ts +240 -0
  61. package/src/insights.ts +265 -152
  62. package/src/lossless-json.ts +2 -1
  63. package/src/managed-user-setup.ts +316 -0
  64. package/src/memory-domain.ts +3 -3
  65. package/src/migrate.ts +38 -14
  66. package/src/new-session-drafts.ts +22 -15
  67. package/src/organization-membership-lifecycle.ts +253 -1
  68. package/src/pr-review.ts +449 -6
  69. package/src/provision-roles.ts +92 -0
  70. package/src/runtime-posture.ts +247 -4
  71. package/src/schema.ts +210 -4
  72. package/src/session-tenancy.ts +120 -2
  73. package/dist/chunk-6HMM2R5T.js.map +0 -1
  74. package/dist/chunk-AZHW7R5V.js.map +0 -1
  75. package/dist/chunk-KRLPEMLH.js.map +0 -1
  76. package/dist/chunk-SIBYBA2D.js.map +0 -1
  77. package/dist/chunk-UZNXG44K.js.map +0 -1
  78. /package/dist/{chunk-2PRS4J5Q.js.map → chunk-HY3F5Q4E.js.map} +0 -0
  79. /package/dist/{chunk-NAB6FKFN.js.map → chunk-O6FTELKH.js.map} +0 -0
  80. /package/dist/{chunk-E6CLMKEE.js.map → chunk-V3TRUXFJ.js.map} +0 -0
  81. /package/dist/{chunk-2EH4WRHL.js.map → chunk-ZWRIPCTR.js.map} +0 -0
@@ -0,0 +1,936 @@
1
+ -- deployment-mode: rolling
2
+ -- Migration 0356 moved Insights visibility into set-based SECURITY DEFINER
3
+ -- scans, but a production migration owner is deliberately NOSUPERUSER and
4
+ -- NOBYPASSRLS. FORCE RLS therefore still ran the restrictive scalar
5
+ -- session_reference_visible() predicate once per fact. Open one exact,
6
+ -- transaction-local read capability while each audited function is active and
7
+ -- add that owner-only capability only to the SELECT form of the two fact-table
8
+ -- visibility policies. Sessions retain their ordinary policy, and every fact
9
+ -- write keeps the original predicate. The capability is a private row bound to
10
+ -- backend PID + xid + exact tenant/actor context, not a caller-forgeable GUC.
11
+
12
+ SET LOCAL lock_timeout = '5s';
13
+ SET LOCAL statement_timeout = '10min';
14
+
15
+ CREATE TABLE opengeni_private.insights_fact_read_runtime_capabilities (
16
+ backend_pid integer NOT NULL,
17
+ transaction_id xid8 NOT NULL,
18
+ capability_kind text NOT NULL,
19
+ account_id uuid NOT NULL,
20
+ workspace_id uuid NOT NULL,
21
+ subject_id text,
22
+ initiating_human_subject_id text,
23
+ created_at timestamp with time zone NOT NULL DEFAULT pg_catalog.clock_timestamp(),
24
+ CONSTRAINT insights_fact_read_runtime_capabilities_kind_chk CHECK (
25
+ capability_kind IN ('model_call_facts', 'usage_events')
26
+ ),
27
+ CONSTRAINT insights_fact_read_runtime_capabilities_pk PRIMARY KEY (
28
+ backend_pid, transaction_id, capability_kind
29
+ )
30
+ );
31
+
32
+ REVOKE ALL ON TABLE
33
+ opengeni_private.insights_fact_read_runtime_capabilities
34
+ FROM PUBLIC;
35
+
36
+ -- Owner ALTER DEFAULT PRIVILEGES may have admitted arbitrary roles before this
37
+ -- migration. Strip every explicit non-owner table grantee before constructing
38
+ -- the allow-list from the configured application roles below.
39
+ DO $insights_fact_read_capability_table_acl_reset$
40
+ DECLARE
41
+ role_name text;
42
+ BEGIN
43
+ FOR role_name IN
44
+ SELECT grantee_role.rolname
45
+ FROM pg_catalog.pg_class relation
46
+ CROSS JOIN LATERAL pg_catalog.aclexplode(
47
+ coalesce(
48
+ relation.relacl,
49
+ pg_catalog.acldefault('r', relation.relowner)
50
+ )
51
+ ) privilege
52
+ INNER JOIN pg_catalog.pg_roles grantee_role
53
+ ON grantee_role.oid = privilege.grantee
54
+ WHERE relation.oid =
55
+ 'opengeni_private.insights_fact_read_runtime_capabilities'::pg_catalog.regclass
56
+ AND privilege.grantee <> 0
57
+ AND privilege.grantee <> relation.relowner
58
+ GROUP BY grantee_role.rolname
59
+ ORDER BY grantee_role.rolname COLLATE "C"
60
+ LOOP
61
+ EXECUTE pg_catalog.format(
62
+ 'REVOKE ALL ON TABLE '
63
+ || 'opengeni_private.insights_fact_read_runtime_capabilities FROM %I',
64
+ role_name
65
+ );
66
+ END LOOP;
67
+ END
68
+ $insights_fact_read_capability_table_acl_reset$;
69
+
70
+ -- PostgreSQL checks EXECUTE on every function referenced by an RLS policy
71
+ -- before it can short-circuit an owner-only branch. Put the value-free policy
72
+ -- guard in the fact-table schema and make only that guard public, so ordinary
73
+ -- reporting roles can keep using scalar fact visibility without widening
74
+ -- their private-schema ACLs or receiving EXECUTE on either analytical entry
75
+ -- point. A direct caller can spoof the two role arguments, but can only observe
76
+ -- a same-backend, same-transaction capability that it cannot mint.
77
+ DO $insights_fact_read_policy_capability_function$
78
+ DECLARE
79
+ data_schema text := pg_catalog.current_schema();
80
+ BEGIN
81
+ EXECUTE pg_catalog.format($ddl$
82
+ CREATE OR REPLACE FUNCTION %1$I.insights_fact_read_policy_capability_active(
83
+ p_actor text,
84
+ p_expected_owner text,
85
+ p_capability_kind text
86
+ ) RETURNS boolean
87
+ LANGUAGE sql
88
+ STABLE
89
+ SECURITY DEFINER
90
+ SET search_path = pg_catalog
91
+ AS $function$
92
+ SELECT p_actor = p_expected_owner AND EXISTS (
93
+ SELECT 1
94
+ FROM opengeni_private.insights_fact_read_runtime_capabilities capability
95
+ WHERE capability.backend_pid = pg_catalog.pg_backend_pid()
96
+ AND capability.transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
97
+ AND capability.capability_kind = p_capability_kind
98
+ AND capability.account_id IS NOT DISTINCT FROM nullif(
99
+ pg_catalog.current_setting('opengeni.account_id', true), ''
100
+ )::uuid
101
+ AND capability.workspace_id IS NOT DISTINCT FROM nullif(
102
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
103
+ )::uuid
104
+ AND capability.subject_id IS NOT DISTINCT FROM nullif(
105
+ pg_catalog.current_setting('opengeni.subject_id', true), ''
106
+ )
107
+ AND capability.initiating_human_subject_id IS NOT DISTINCT FROM nullif(
108
+ pg_catalog.current_setting(
109
+ 'opengeni.initiating_human_subject_id', true
110
+ ), ''
111
+ )
112
+ )
113
+ $function$;
114
+ REVOKE ALL ON FUNCTION
115
+ %1$I.insights_fact_read_policy_capability_active(text, text, text)
116
+ FROM PUBLIC;
117
+ GRANT EXECUTE ON FUNCTION
118
+ %1$I.insights_fact_read_policy_capability_active(text, text, text)
119
+ TO PUBLIC;
120
+ $ddl$, data_schema);
121
+ END
122
+ $insights_fact_read_policy_capability_function$;
123
+
124
+ -- Split the existing restrictive FOR ALL policy into command-specific forms.
125
+ -- SELECT alone receives the owner+private-capability alternative. INSERT,
126
+ -- UPDATE, and DELETE retain the exact installed expression, including all
127
+ -- session-tenancy owner/fence behavior on sessions. Refuse definition drift
128
+ -- instead of weakening an unknown future policy.
129
+ DO $insights_fact_read_select_policies$
130
+ DECLARE
131
+ data_schema text := pg_catalog.current_schema();
132
+ target record;
133
+ installed record;
134
+ capability_expression text;
135
+ BEGIN
136
+ FOR target IN
137
+ SELECT *
138
+ FROM (VALUES
139
+ ('model_call_facts'::text, 'model_call_facts'::text),
140
+ ('usage_events'::text, 'usage_events'::text)
141
+ ) target_row(table_name, capability_kind)
142
+ LOOP
143
+ SELECT
144
+ policy.polpermissive AS permissive,
145
+ policy.polcmd AS command,
146
+ pg_catalog.pg_get_expr(policy.polqual, policy.polrelid) AS using_expression,
147
+ pg_catalog.pg_get_expr(policy.polwithcheck, policy.polrelid) AS check_expression
148
+ INTO installed
149
+ FROM pg_catalog.pg_policy policy
150
+ INNER JOIN pg_catalog.pg_class relation ON relation.oid = policy.polrelid
151
+ INNER JOIN pg_catalog.pg_namespace namespace ON namespace.oid = relation.relnamespace
152
+ WHERE namespace.nspname = data_schema
153
+ AND relation.relname = target.table_name
154
+ AND policy.polname = 'session_visibility_isolation';
155
+
156
+ IF NOT FOUND
157
+ OR installed.permissive
158
+ OR installed.command <> '*'
159
+ OR installed.using_expression IS NULL
160
+ OR installed.check_expression IS DISTINCT FROM installed.using_expression
161
+ THEN
162
+ RAISE EXCEPTION '0359 unexpected session visibility policy on %.%',
163
+ data_schema, target.table_name
164
+ USING ERRCODE = '55000';
165
+ END IF;
166
+
167
+ capability_expression := pg_catalog.format(
168
+ '%1$I.insights_fact_read_policy_capability_active('
169
+ || 'current_user, pg_catalog.pg_get_userbyid(('
170
+ || 'SELECT relation.relowner FROM pg_catalog.pg_class relation '
171
+ || 'WHERE relation.oid = %2$L::pg_catalog.regclass)), %3$L)',
172
+ data_schema,
173
+ pg_catalog.format('%I.%I', data_schema, target.table_name),
174
+ target.capability_kind
175
+ );
176
+
177
+ EXECUTE pg_catalog.format(
178
+ 'DROP POLICY session_visibility_isolation ON %I.%I',
179
+ data_schema,
180
+ target.table_name
181
+ );
182
+ EXECUTE pg_catalog.format(
183
+ 'DROP POLICY IF EXISTS session_visibility_insert_isolation ON %I.%I',
184
+ data_schema,
185
+ target.table_name
186
+ );
187
+ EXECUTE pg_catalog.format(
188
+ 'DROP POLICY IF EXISTS session_visibility_update_isolation ON %I.%I',
189
+ data_schema,
190
+ target.table_name
191
+ );
192
+ EXECUTE pg_catalog.format(
193
+ 'DROP POLICY IF EXISTS session_visibility_delete_isolation ON %I.%I',
194
+ data_schema,
195
+ target.table_name
196
+ );
197
+
198
+ EXECUTE pg_catalog.format(
199
+ 'CREATE POLICY session_visibility_isolation ON %I.%I AS RESTRICTIVE '
200
+ || 'FOR SELECT USING (CASE WHEN (%s) THEN true ELSE (%s) END)',
201
+ data_schema,
202
+ target.table_name,
203
+ capability_expression,
204
+ installed.using_expression
205
+ );
206
+ EXECUTE pg_catalog.format(
207
+ 'CREATE POLICY session_visibility_insert_isolation ON %I.%I AS RESTRICTIVE '
208
+ || 'FOR INSERT WITH CHECK (%s)',
209
+ data_schema,
210
+ target.table_name,
211
+ installed.check_expression
212
+ );
213
+ EXECUTE pg_catalog.format(
214
+ 'CREATE POLICY session_visibility_update_isolation ON %I.%I AS RESTRICTIVE '
215
+ || 'FOR UPDATE USING (%s) WITH CHECK (%s)',
216
+ data_schema,
217
+ target.table_name,
218
+ installed.using_expression,
219
+ installed.check_expression
220
+ );
221
+ EXECUTE pg_catalog.format(
222
+ 'CREATE POLICY session_visibility_delete_isolation ON %I.%I AS RESTRICTIVE '
223
+ || 'FOR DELETE USING (%s)',
224
+ data_schema,
225
+ target.table_name,
226
+ installed.using_expression
227
+ );
228
+ END LOOP;
229
+ END
230
+ $insights_fact_read_select_policies$;
231
+
232
+ DO $insights_model_fact_read_functions$
233
+ DECLARE
234
+ data_schema text := pg_catalog.current_schema();
235
+ BEGIN
236
+ EXECUTE pg_catalog.format($ddl$
237
+ CREATE OR REPLACE FUNCTION opengeni_private.visible_workspace_insights_model_call_facts(
238
+ p_workspace_id uuid,
239
+ p_since timestamp with time zone,
240
+ p_until timestamp with time zone,
241
+ p_provider text,
242
+ p_model text
243
+ ) RETURNS SETOF %1$I.model_call_facts
244
+ LANGUAGE plpgsql
245
+ VOLATILE
246
+ SECURITY DEFINER
247
+ SET search_path = pg_catalog, %1$I, opengeni_private, pg_temp
248
+ AS $function$
249
+ DECLARE
250
+ context_account_id uuid;
251
+ context_workspace_id uuid;
252
+ context_subject_id text;
253
+ context_initiating_human_subject_id text;
254
+ BEGIN
255
+ PERFORM opengeni_private.session_variable_set_attachments_protocol_v1_active();
256
+ BEGIN
257
+ context_account_id := nullif(
258
+ pg_catalog.current_setting('opengeni.account_id', true), ''
259
+ )::uuid;
260
+ context_workspace_id := nullif(
261
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
262
+ )::uuid;
263
+ EXCEPTION WHEN invalid_text_representation THEN
264
+ RAISE EXCEPTION 'Insights RLS context is malformed'
265
+ USING ERRCODE = '42501';
266
+ END;
267
+ context_subject_id := nullif(
268
+ pg_catalog.current_setting('opengeni.subject_id', true), ''
269
+ );
270
+ context_initiating_human_subject_id := nullif(
271
+ pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''
272
+ );
273
+ IF context_account_id IS NULL
274
+ OR context_workspace_id IS NULL
275
+ OR context_workspace_id IS DISTINCT FROM p_workspace_id
276
+ THEN
277
+ RAISE EXCEPTION 'Insights RLS context does not match the requested workspace'
278
+ USING ERRCODE = '42501';
279
+ END IF;
280
+ IF p_since IS NULL
281
+ OR p_until IS NULL
282
+ OR p_since IN (
283
+ '-infinity'::timestamp with time zone,
284
+ 'infinity'::timestamp with time zone
285
+ )
286
+ OR p_until = '-infinity'::timestamp with time zone
287
+ OR p_until < p_since
288
+ OR (
289
+ p_until <> 'infinity'::timestamp with time zone
290
+ AND p_until - p_since > interval '370 days'
291
+ )
292
+ OR (
293
+ p_until = 'infinity'::timestamp with time zone
294
+ AND p_since < CURRENT_TIMESTAMP - interval '370 days'
295
+ )
296
+ THEN
297
+ RAISE EXCEPTION 'Insights fact window must be non-negative and at most 370 days'
298
+ USING ERRCODE = '22023';
299
+ END IF;
300
+ IF (p_provider IS NOT NULL AND (
301
+ pg_catalog.btrim(p_provider) = ''
302
+ OR pg_catalog.octet_length(p_provider) > 256
303
+ ))
304
+ OR (p_model IS NOT NULL AND (
305
+ pg_catalog.btrim(p_model) = ''
306
+ OR pg_catalog.octet_length(p_model) > 512
307
+ ))
308
+ THEN
309
+ RAISE EXCEPTION 'Insights model filters are invalid'
310
+ USING ERRCODE = '22023';
311
+ END IF;
312
+ IF p_until = p_since THEN
313
+ RETURN;
314
+ END IF;
315
+
316
+ INSERT INTO opengeni_private.insights_fact_read_runtime_capabilities (
317
+ backend_pid,
318
+ transaction_id,
319
+ capability_kind,
320
+ account_id,
321
+ workspace_id,
322
+ subject_id,
323
+ initiating_human_subject_id
324
+ ) VALUES (
325
+ pg_catalog.pg_backend_pid(),
326
+ pg_catalog.pg_current_xact_id(),
327
+ 'model_call_facts',
328
+ context_account_id,
329
+ context_workspace_id,
330
+ context_subject_id,
331
+ context_initiating_human_subject_id
332
+ );
333
+ BEGIN
334
+ -- Keep each nullability shape static. A cached generic PL/pgSQL plan
335
+ -- for nullable OR predicates can abandon the selective
336
+ -- workspace/provider/model/occurred_at index after repeated calls.
337
+ IF p_provider IS NULL AND p_model IS NULL THEN
338
+ RETURN QUERY
339
+ WITH visible_sessions AS MATERIALIZED (
340
+ SELECT
341
+ id, account_id, workspace_id, visibility,
342
+ owner_organization_membership_id, owner_subject_id
343
+ FROM %1$I.sessions
344
+ WHERE account_id = context_account_id
345
+ AND workspace_id = p_workspace_id
346
+ )
347
+ SELECT fact.*
348
+ FROM %1$I.model_call_facts fact
349
+ INNER JOIN visible_sessions session_row
350
+ ON session_row.account_id = fact.account_id
351
+ AND session_row.workspace_id = fact.workspace_id
352
+ AND session_row.id = fact.session_id
353
+ WHERE fact.account_id = context_account_id
354
+ AND fact.workspace_id = p_workspace_id
355
+ AND fact.occurred_at >= p_since
356
+ AND fact.occurred_at < p_until
357
+ AND (
358
+ context_subject_id IS NULL
359
+ OR session_row.visibility = 'workspace_shared'
360
+ OR %1$I.session_private_actor_visible(
361
+ session_row.account_id,
362
+ session_row.workspace_id,
363
+ session_row.owner_organization_membership_id,
364
+ session_row.owner_subject_id
365
+ )
366
+ );
367
+ ELSIF p_provider IS NOT NULL AND p_model IS NULL THEN
368
+ RETURN QUERY
369
+ WITH visible_sessions AS MATERIALIZED (
370
+ SELECT
371
+ id, account_id, workspace_id, visibility,
372
+ owner_organization_membership_id, owner_subject_id
373
+ FROM %1$I.sessions
374
+ WHERE account_id = context_account_id
375
+ AND workspace_id = p_workspace_id
376
+ )
377
+ SELECT fact.*
378
+ FROM %1$I.model_call_facts fact
379
+ INNER JOIN visible_sessions session_row
380
+ ON session_row.account_id = fact.account_id
381
+ AND session_row.workspace_id = fact.workspace_id
382
+ AND session_row.id = fact.session_id
383
+ WHERE fact.account_id = context_account_id
384
+ AND fact.workspace_id = p_workspace_id
385
+ AND fact.provider = p_provider
386
+ AND fact.occurred_at >= p_since
387
+ AND fact.occurred_at < p_until
388
+ AND (
389
+ context_subject_id IS NULL
390
+ OR session_row.visibility = 'workspace_shared'
391
+ OR %1$I.session_private_actor_visible(
392
+ session_row.account_id,
393
+ session_row.workspace_id,
394
+ session_row.owner_organization_membership_id,
395
+ session_row.owner_subject_id
396
+ )
397
+ );
398
+ ELSIF p_provider IS NULL AND p_model IS NOT NULL THEN
399
+ RETURN QUERY
400
+ WITH visible_sessions AS MATERIALIZED (
401
+ SELECT
402
+ id, account_id, workspace_id, visibility,
403
+ owner_organization_membership_id, owner_subject_id
404
+ FROM %1$I.sessions
405
+ WHERE account_id = context_account_id
406
+ AND workspace_id = p_workspace_id
407
+ )
408
+ SELECT fact.*
409
+ FROM %1$I.model_call_facts fact
410
+ INNER JOIN visible_sessions session_row
411
+ ON session_row.account_id = fact.account_id
412
+ AND session_row.workspace_id = fact.workspace_id
413
+ AND session_row.id = fact.session_id
414
+ WHERE fact.account_id = context_account_id
415
+ AND fact.workspace_id = p_workspace_id
416
+ AND fact.model = p_model
417
+ AND fact.occurred_at >= p_since
418
+ AND fact.occurred_at < p_until
419
+ AND (
420
+ context_subject_id IS NULL
421
+ OR session_row.visibility = 'workspace_shared'
422
+ OR %1$I.session_private_actor_visible(
423
+ session_row.account_id,
424
+ session_row.workspace_id,
425
+ session_row.owner_organization_membership_id,
426
+ session_row.owner_subject_id
427
+ )
428
+ );
429
+ ELSE
430
+ RETURN QUERY
431
+ WITH visible_sessions AS MATERIALIZED (
432
+ SELECT
433
+ id, account_id, workspace_id, visibility,
434
+ owner_organization_membership_id, owner_subject_id
435
+ FROM %1$I.sessions
436
+ WHERE account_id = context_account_id
437
+ AND workspace_id = p_workspace_id
438
+ )
439
+ SELECT fact.*
440
+ FROM %1$I.model_call_facts fact
441
+ INNER JOIN visible_sessions session_row
442
+ ON session_row.account_id = fact.account_id
443
+ AND session_row.workspace_id = fact.workspace_id
444
+ AND session_row.id = fact.session_id
445
+ WHERE fact.account_id = context_account_id
446
+ AND fact.workspace_id = p_workspace_id
447
+ AND fact.provider = p_provider
448
+ AND fact.model = p_model
449
+ AND fact.occurred_at >= p_since
450
+ AND fact.occurred_at < p_until
451
+ AND (
452
+ context_subject_id IS NULL
453
+ OR session_row.visibility = 'workspace_shared'
454
+ OR %1$I.session_private_actor_visible(
455
+ session_row.account_id,
456
+ session_row.workspace_id,
457
+ session_row.owner_organization_membership_id,
458
+ session_row.owner_subject_id
459
+ )
460
+ );
461
+ END IF;
462
+
463
+ DELETE FROM opengeni_private.insights_fact_read_runtime_capabilities
464
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
465
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
466
+ AND capability_kind = 'model_call_facts';
467
+ RETURN;
468
+ EXCEPTION WHEN OTHERS THEN
469
+ DELETE FROM opengeni_private.insights_fact_read_runtime_capabilities
470
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
471
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
472
+ AND capability_kind = 'model_call_facts';
473
+ RAISE;
474
+ END;
475
+ END
476
+ $function$;
477
+ $ddl$, data_schema);
478
+
479
+ EXECUTE pg_catalog.format($ddl$
480
+ CREATE OR REPLACE FUNCTION opengeni_private.visible_workspace_insights_model_call_facts(
481
+ p_workspace_id uuid,
482
+ p_since timestamp with time zone,
483
+ p_until timestamp with time zone
484
+ ) RETURNS SETOF %1$I.model_call_facts
485
+ LANGUAGE sql
486
+ VOLATILE
487
+ SECURITY DEFINER
488
+ SET search_path = pg_catalog, %1$I, opengeni_private, pg_temp
489
+ AS $function$
490
+ SELECT *
491
+ FROM opengeni_private.visible_workspace_insights_model_call_facts(
492
+ p_workspace_id, p_since, p_until, NULL, NULL
493
+ )
494
+ $function$;
495
+ $ddl$, data_schema);
496
+ END
497
+ $insights_model_fact_read_functions$;
498
+
499
+ DO $insights_usage_fact_read_functions$
500
+ DECLARE
501
+ data_schema text := pg_catalog.current_schema();
502
+ BEGIN
503
+ EXECUTE pg_catalog.format($ddl$
504
+ CREATE OR REPLACE FUNCTION opengeni_private.visible_workspace_insights_usage_events(
505
+ p_workspace_id uuid,
506
+ p_since timestamp with time zone,
507
+ p_until timestamp with time zone
508
+ ) RETURNS SETOF %1$I.usage_events
509
+ LANGUAGE plpgsql
510
+ VOLATILE
511
+ SECURITY DEFINER
512
+ SET search_path = pg_catalog, %1$I, opengeni_private, pg_temp
513
+ AS $function$
514
+ DECLARE
515
+ context_account_id uuid;
516
+ context_workspace_id uuid;
517
+ context_subject_id text;
518
+ context_initiating_human_subject_id text;
519
+ BEGIN
520
+ PERFORM opengeni_private.session_variable_set_attachments_protocol_v1_active();
521
+ BEGIN
522
+ context_account_id := nullif(
523
+ pg_catalog.current_setting('opengeni.account_id', true), ''
524
+ )::uuid;
525
+ context_workspace_id := nullif(
526
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
527
+ )::uuid;
528
+ EXCEPTION WHEN invalid_text_representation THEN
529
+ RAISE EXCEPTION 'Insights RLS context is malformed'
530
+ USING ERRCODE = '42501';
531
+ END;
532
+ context_subject_id := nullif(
533
+ pg_catalog.current_setting('opengeni.subject_id', true), ''
534
+ );
535
+ context_initiating_human_subject_id := nullif(
536
+ pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''
537
+ );
538
+ IF context_account_id IS NULL
539
+ OR context_workspace_id IS NULL
540
+ OR context_workspace_id IS DISTINCT FROM p_workspace_id
541
+ THEN
542
+ RAISE EXCEPTION 'Insights RLS context does not match the requested workspace'
543
+ USING ERRCODE = '42501';
544
+ END IF;
545
+ IF p_since IS NULL
546
+ OR p_until IS NULL
547
+ OR p_since IN (
548
+ '-infinity'::timestamp with time zone,
549
+ 'infinity'::timestamp with time zone
550
+ )
551
+ OR p_until = '-infinity'::timestamp with time zone
552
+ OR p_until < p_since
553
+ OR (
554
+ p_until <> 'infinity'::timestamp with time zone
555
+ AND p_until - p_since > interval '370 days'
556
+ )
557
+ OR (
558
+ p_until = 'infinity'::timestamp with time zone
559
+ AND p_since < CURRENT_TIMESTAMP - interval '370 days'
560
+ )
561
+ THEN
562
+ RAISE EXCEPTION 'Insights fact window must be non-negative and at most 370 days'
563
+ USING ERRCODE = '22023';
564
+ END IF;
565
+ IF p_until = p_since THEN
566
+ RETURN;
567
+ END IF;
568
+
569
+ INSERT INTO opengeni_private.insights_fact_read_runtime_capabilities (
570
+ backend_pid,
571
+ transaction_id,
572
+ capability_kind,
573
+ account_id,
574
+ workspace_id,
575
+ subject_id,
576
+ initiating_human_subject_id
577
+ ) VALUES (
578
+ pg_catalog.pg_backend_pid(),
579
+ pg_catalog.pg_current_xact_id(),
580
+ 'usage_events',
581
+ context_account_id,
582
+ context_workspace_id,
583
+ context_subject_id,
584
+ context_initiating_human_subject_id
585
+ );
586
+ BEGIN
587
+ RETURN QUERY
588
+ WITH visible_sessions AS MATERIALIZED (
589
+ SELECT
590
+ id, account_id, workspace_id, visibility,
591
+ owner_organization_membership_id, owner_subject_id
592
+ FROM %1$I.sessions
593
+ WHERE account_id = context_account_id
594
+ AND workspace_id = p_workspace_id
595
+ )
596
+ SELECT usage_row.*
597
+ FROM %1$I.usage_events usage_row
598
+ LEFT JOIN visible_sessions session_row
599
+ ON session_row.account_id = usage_row.account_id
600
+ AND session_row.workspace_id = usage_row.workspace_id
601
+ AND session_row.id = usage_row.session_id
602
+ WHERE usage_row.account_id = context_account_id
603
+ AND usage_row.workspace_id = p_workspace_id
604
+ AND usage_row.occurred_at >= p_since
605
+ AND usage_row.occurred_at < p_until
606
+ AND (
607
+ usage_row.session_id IS NULL
608
+ OR (
609
+ session_row.id IS NOT NULL
610
+ AND (
611
+ context_subject_id IS NULL
612
+ OR session_row.visibility = 'workspace_shared'
613
+ OR %1$I.session_private_actor_visible(
614
+ session_row.account_id,
615
+ session_row.workspace_id,
616
+ session_row.owner_organization_membership_id,
617
+ session_row.owner_subject_id
618
+ )
619
+ )
620
+ )
621
+ );
622
+
623
+ DELETE FROM opengeni_private.insights_fact_read_runtime_capabilities
624
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
625
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
626
+ AND capability_kind = 'usage_events';
627
+ RETURN;
628
+ EXCEPTION WHEN OTHERS THEN
629
+ DELETE FROM opengeni_private.insights_fact_read_runtime_capabilities
630
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
631
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
632
+ AND capability_kind = 'usage_events';
633
+ RAISE;
634
+ END;
635
+ END
636
+ $function$;
637
+ $ddl$, data_schema);
638
+
639
+ EXECUTE pg_catalog.format($ddl$
640
+ CREATE OR REPLACE FUNCTION opengeni_private.visible_workspace_insights_usage_events(
641
+ p_workspace_id uuid,
642
+ p_since timestamp with time zone,
643
+ p_until timestamp with time zone,
644
+ p_event_types text[]
645
+ ) RETURNS SETOF %1$I.usage_events
646
+ LANGUAGE plpgsql
647
+ VOLATILE
648
+ SECURITY DEFINER
649
+ SET search_path = pg_catalog, %1$I, opengeni_private, pg_temp
650
+ AS $function$
651
+ DECLARE
652
+ context_account_id uuid;
653
+ context_workspace_id uuid;
654
+ context_subject_id text;
655
+ context_initiating_human_subject_id text;
656
+ BEGIN
657
+ PERFORM opengeni_private.session_variable_set_attachments_protocol_v1_active();
658
+ BEGIN
659
+ context_account_id := nullif(
660
+ pg_catalog.current_setting('opengeni.account_id', true), ''
661
+ )::uuid;
662
+ context_workspace_id := nullif(
663
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
664
+ )::uuid;
665
+ EXCEPTION WHEN invalid_text_representation THEN
666
+ RAISE EXCEPTION 'Insights RLS context is malformed'
667
+ USING ERRCODE = '42501';
668
+ END;
669
+ context_subject_id := nullif(
670
+ pg_catalog.current_setting('opengeni.subject_id', true), ''
671
+ );
672
+ context_initiating_human_subject_id := nullif(
673
+ pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''
674
+ );
675
+ IF context_account_id IS NULL
676
+ OR context_workspace_id IS NULL
677
+ OR context_workspace_id IS DISTINCT FROM p_workspace_id
678
+ THEN
679
+ RAISE EXCEPTION 'Insights RLS context does not match the requested workspace'
680
+ USING ERRCODE = '42501';
681
+ END IF;
682
+ IF p_since IS NULL
683
+ OR p_until IS NULL
684
+ OR p_since IN (
685
+ '-infinity'::timestamp with time zone,
686
+ 'infinity'::timestamp with time zone
687
+ )
688
+ OR p_until = '-infinity'::timestamp with time zone
689
+ OR p_until < p_since
690
+ OR (
691
+ p_until <> 'infinity'::timestamp with time zone
692
+ AND p_until - p_since > interval '370 days'
693
+ )
694
+ OR (
695
+ p_until = 'infinity'::timestamp with time zone
696
+ AND p_since < CURRENT_TIMESTAMP - interval '370 days'
697
+ )
698
+ THEN
699
+ RAISE EXCEPTION 'Insights fact window must be non-negative and at most 370 days'
700
+ USING ERRCODE = '22023';
701
+ END IF;
702
+ IF p_event_types IS NULL
703
+ OR pg_catalog.array_ndims(p_event_types) <> 1
704
+ OR pg_catalog.cardinality(p_event_types) < 1
705
+ OR pg_catalog.cardinality(p_event_types) > 16
706
+ OR EXISTS (
707
+ SELECT 1
708
+ FROM pg_catalog.unnest(p_event_types) event_type(value)
709
+ WHERE event_type.value IS NULL
710
+ OR pg_catalog.btrim(event_type.value) = ''
711
+ OR pg_catalog.octet_length(event_type.value) > 256
712
+ )
713
+ OR (
714
+ SELECT pg_catalog.count(DISTINCT event_type.value COLLATE "C")
715
+ FROM pg_catalog.unnest(p_event_types) event_type(value)
716
+ ) <> pg_catalog.cardinality(p_event_types)
717
+ THEN
718
+ RAISE EXCEPTION 'Insights usage event types must contain 1-16 unique bounded values'
719
+ USING ERRCODE = '22023';
720
+ END IF;
721
+ IF p_until = p_since THEN
722
+ RETURN;
723
+ END IF;
724
+
725
+ INSERT INTO opengeni_private.insights_fact_read_runtime_capabilities (
726
+ backend_pid,
727
+ transaction_id,
728
+ capability_kind,
729
+ account_id,
730
+ workspace_id,
731
+ subject_id,
732
+ initiating_human_subject_id
733
+ ) VALUES (
734
+ pg_catalog.pg_backend_pid(),
735
+ pg_catalog.pg_current_xact_id(),
736
+ 'usage_events',
737
+ context_account_id,
738
+ context_workspace_id,
739
+ context_subject_id,
740
+ context_initiating_human_subject_id
741
+ );
742
+ BEGIN
743
+ RETURN QUERY
744
+ WITH visible_sessions AS MATERIALIZED (
745
+ SELECT
746
+ id, account_id, workspace_id, visibility,
747
+ owner_organization_membership_id, owner_subject_id
748
+ FROM %1$I.sessions
749
+ WHERE account_id = context_account_id
750
+ AND workspace_id = p_workspace_id
751
+ )
752
+ SELECT usage_row.*
753
+ FROM %1$I.usage_events usage_row
754
+ LEFT JOIN visible_sessions session_row
755
+ ON session_row.account_id = usage_row.account_id
756
+ AND session_row.workspace_id = usage_row.workspace_id
757
+ AND session_row.id = usage_row.session_id
758
+ WHERE usage_row.account_id = context_account_id
759
+ AND usage_row.workspace_id = p_workspace_id
760
+ AND usage_row.event_type = ANY (p_event_types)
761
+ AND usage_row.occurred_at >= p_since
762
+ AND usage_row.occurred_at < p_until
763
+ AND (
764
+ usage_row.session_id IS NULL
765
+ OR (
766
+ session_row.id IS NOT NULL
767
+ AND (
768
+ context_subject_id IS NULL
769
+ OR session_row.visibility = 'workspace_shared'
770
+ OR %1$I.session_private_actor_visible(
771
+ session_row.account_id,
772
+ session_row.workspace_id,
773
+ session_row.owner_organization_membership_id,
774
+ session_row.owner_subject_id
775
+ )
776
+ )
777
+ )
778
+ );
779
+
780
+ DELETE FROM opengeni_private.insights_fact_read_runtime_capabilities
781
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
782
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
783
+ AND capability_kind = 'usage_events';
784
+ RETURN;
785
+ EXCEPTION WHEN OTHERS THEN
786
+ DELETE FROM opengeni_private.insights_fact_read_runtime_capabilities
787
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
788
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
789
+ AND capability_kind = 'usage_events';
790
+ RAISE;
791
+ END;
792
+ END
793
+ $function$;
794
+ $ddl$, data_schema);
795
+ END
796
+ $insights_usage_fact_read_functions$;
797
+
798
+ REVOKE ALL ON FUNCTION
799
+ opengeni_private.visible_workspace_insights_model_call_facts(
800
+ uuid, timestamp with time zone, timestamp with time zone
801
+ )
802
+ FROM PUBLIC;
803
+ REVOKE ALL ON FUNCTION
804
+ opengeni_private.visible_workspace_insights_model_call_facts(
805
+ uuid, timestamp with time zone, timestamp with time zone, text, text
806
+ )
807
+ FROM PUBLIC;
808
+ REVOKE ALL ON FUNCTION
809
+ opengeni_private.visible_workspace_insights_usage_events(
810
+ uuid, timestamp with time zone, timestamp with time zone
811
+ )
812
+ FROM PUBLIC;
813
+ REVOKE ALL ON FUNCTION
814
+ opengeni_private.visible_workspace_insights_usage_events(
815
+ uuid, timestamp with time zone, timestamp with time zone, text[]
816
+ )
817
+ FROM PUBLIC;
818
+
819
+ -- All entry points are subject to explicit or owner-default ACL drift. Reset
820
+ -- every non-owner grantee, including the released functions, then rebuild the
821
+ -- allow-list only from the migration runner's exact configured application
822
+ -- roles and 0356's dual-fact-SELECT eligibility rule.
823
+ DO $insights_fact_read_function_acl_reset$
824
+ DECLARE
825
+ role_name text;
826
+ target record;
827
+ BEGIN
828
+ FOR target IN
829
+ SELECT *
830
+ FROM (VALUES
831
+ (
832
+ 'visible_workspace_insights_model_call_facts'::text,
833
+ 'p_workspace_id uuid, p_since timestamp with time zone, p_until timestamp with time zone'::text,
834
+ 'uuid, timestamp with time zone, timestamp with time zone'::text
835
+ ),
836
+ (
837
+ 'visible_workspace_insights_model_call_facts'::text,
838
+ 'p_workspace_id uuid, p_since timestamp with time zone, p_until timestamp with time zone, p_provider text, p_model text'::text,
839
+ 'uuid, timestamp with time zone, timestamp with time zone, text, text'::text
840
+ ),
841
+ (
842
+ 'visible_workspace_insights_usage_events'::text,
843
+ 'p_workspace_id uuid, p_since timestamp with time zone, p_until timestamp with time zone'::text,
844
+ 'uuid, timestamp with time zone, timestamp with time zone'::text
845
+ ),
846
+ (
847
+ 'visible_workspace_insights_usage_events'::text,
848
+ 'p_workspace_id uuid, p_since timestamp with time zone, p_until timestamp with time zone, p_event_types text[]'::text,
849
+ 'uuid, timestamp with time zone, timestamp with time zone, text[]'::text
850
+ )
851
+ ) target_row(function_name, identity_arguments, call_arguments)
852
+ LOOP
853
+ FOR role_name IN
854
+ SELECT grantee_role.rolname
855
+ FROM pg_catalog.pg_proc procedure
856
+ INNER JOIN pg_catalog.pg_namespace namespace
857
+ ON namespace.oid = procedure.pronamespace
858
+ CROSS JOIN LATERAL pg_catalog.aclexplode(
859
+ coalesce(
860
+ procedure.proacl,
861
+ pg_catalog.acldefault('f', procedure.proowner)
862
+ )
863
+ ) privilege
864
+ INNER JOIN pg_catalog.pg_roles grantee_role
865
+ ON grantee_role.oid = privilege.grantee
866
+ WHERE namespace.nspname = 'opengeni_private'
867
+ AND procedure.proname = target.function_name
868
+ AND pg_catalog.pg_get_function_identity_arguments(procedure.oid) =
869
+ target.identity_arguments
870
+ AND privilege.grantee <> 0
871
+ AND privilege.grantee <> procedure.proowner
872
+ GROUP BY grantee_role.rolname
873
+ ORDER BY grantee_role.rolname COLLATE "C"
874
+ LOOP
875
+ EXECUTE pg_catalog.format(
876
+ 'REVOKE ALL ON FUNCTION opengeni_private.%I(%s) FROM %I',
877
+ target.function_name,
878
+ target.call_arguments,
879
+ role_name
880
+ );
881
+ END LOOP;
882
+ END LOOP;
883
+ END
884
+ $insights_fact_read_function_acl_reset$;
885
+
886
+ DO $insights_fact_read_function_grants$
887
+ DECLARE
888
+ data_schema text := pg_catalog.current_schema();
889
+ role_name text;
890
+ BEGIN
891
+ FOR role_name IN
892
+ SELECT role_row.rolname
893
+ FROM pg_catalog.jsonb_array_elements_text(
894
+ pg_catalog.current_setting('opengeni.migration_application_roles')::jsonb
895
+ ) configured(value)
896
+ INNER JOIN pg_catalog.pg_roles role_row
897
+ ON role_row.rolname = configured.value
898
+ WHERE pg_catalog.has_table_privilege(
899
+ role_row.rolname,
900
+ pg_catalog.format('%I.model_call_facts', data_schema),
901
+ 'SELECT'
902
+ )
903
+ AND pg_catalog.has_table_privilege(
904
+ role_row.rolname,
905
+ pg_catalog.format('%I.usage_events', data_schema),
906
+ 'SELECT'
907
+ )
908
+ ORDER BY role_row.rolname COLLATE "C"
909
+ LOOP
910
+ EXECUTE pg_catalog.format(
911
+ 'REVOKE ALL ON TABLE '
912
+ || 'opengeni_private.insights_fact_read_runtime_capabilities FROM %I',
913
+ role_name
914
+ );
915
+ EXECUTE pg_catalog.format(
916
+ 'GRANT USAGE ON SCHEMA opengeni_private TO %I',
917
+ role_name
918
+ );
919
+ EXECUTE pg_catalog.format(
920
+ 'GRANT EXECUTE ON FUNCTION '
921
+ || 'opengeni_private.visible_workspace_insights_model_call_facts('
922
+ || 'uuid, timestamp with time zone, timestamp with time zone), '
923
+ || 'opengeni_private.visible_workspace_insights_model_call_facts('
924
+ || 'uuid, timestamp with time zone, timestamp with time zone, text, text), '
925
+ || 'opengeni_private.visible_workspace_insights_usage_events('
926
+ || 'uuid, timestamp with time zone, timestamp with time zone), '
927
+ || 'opengeni_private.visible_workspace_insights_usage_events('
928
+ || 'uuid, timestamp with time zone, timestamp with time zone, text[]) TO %I',
929
+ role_name
930
+ );
931
+ END LOOP;
932
+ END
933
+ $insights_fact_read_function_grants$;
934
+
935
+ RESET statement_timeout;
936
+ RESET lock_timeout;