@opengeni/db 3.6.0 → 3.7.3-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 (80) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-744DFC65.js → chunk-4NAR7FBA.js} +92 -6
  3. package/dist/chunk-4NAR7FBA.js.map +1 -0
  4. package/dist/{chunk-IW6O6G7R.js → chunk-5NNCGFQY.js} +2 -2
  5. package/dist/{chunk-G3732M3T.js → chunk-DZCYW2WT.js} +2 -2
  6. package/dist/{chunk-WW7AJ5IC.js → chunk-F6PBS6WE.js} +5 -7
  7. package/dist/chunk-F6PBS6WE.js.map +1 -0
  8. package/dist/{chunk-UJ2EW3QI.js → chunk-O56DM5GZ.js} +340 -85
  9. package/dist/chunk-O56DM5GZ.js.map +1 -0
  10. package/dist/{chunk-CDMMSUWJ.js → chunk-S3TDDCS2.js} +3 -3
  11. package/dist/{chunk-Q5YUGQVK.js → chunk-SZAWDXQC.js} +3 -3
  12. package/dist/{chunk-UGDVSQ6U.js → chunk-U4WPPEBH.js} +2 -2
  13. package/dist/{chunk-2NT476HD.js → chunk-US4IS6IV.js} +2 -2
  14. package/dist/codex-token-resolver.d.ts +12 -1
  15. package/dist/company-profile-agent-admin.d.ts +4 -2
  16. package/dist/company-profile-agent-policy.d.ts +20 -0
  17. package/dist/company-profile-schema.d.ts +573 -0
  18. package/dist/editable-artifact-durable-export.js +2 -2
  19. package/dist/editable-artifacts.js +3 -3
  20. package/dist/index.d.ts +382 -18
  21. package/dist/index.js +4513 -2065
  22. package/dist/index.js.map +1 -1
  23. package/dist/managed-auth-session-sets.js +3 -3
  24. package/dist/managed-human-provisioning.d.ts +3 -3
  25. package/dist/memory-domain.d.ts +5 -3
  26. package/dist/provision-roles.js +1 -1
  27. package/dist/runtime-posture.d.ts +5 -5
  28. package/dist/schema.d.ts +725 -4
  29. package/dist/schema.js +13 -1
  30. package/dist/session-background-commands.js +3 -3
  31. package/dist/session-control.d.ts +40 -5
  32. package/dist/session-queue-commands.d.ts +2 -0
  33. package/dist/session-tenancy.js +3 -3
  34. package/dist/user-resource-authority.d.ts +8 -0
  35. package/dist/video-generation.js +3 -3
  36. package/drizzle/0369_local_human_personal_authority.sql +350 -0
  37. package/drizzle/0370_workspace_member_management_scope.sql +98 -0
  38. package/drizzle/0371_workspace_member_candidate_inventory.sql +128 -0
  39. package/drizzle/0372_ordered_variable_set_runtime_authority.sql +287 -0
  40. package/drizzle/0373_sandbox_shared_preparation.sql +59 -0
  41. package/drizzle/0374_session_event_cursors.sql +315 -0
  42. package/drizzle/0375_session_recovery_observability.sql +73 -0
  43. package/drizzle/0376_organization_workspace_inventory.sql +88 -0
  44. package/drizzle/0377_scoped_rig_health_projection.sql +80 -0
  45. package/drizzle/0378_scoped_rig_health_audit_timestamp.sql +77 -0
  46. package/drizzle/0379_session_event_raw_lane_activation.sql +518 -0
  47. package/drizzle/0380_autonomous_company_profile_agent_policy.sql +829 -0
  48. package/drizzle/0381_organization_codex_subscription_inheritance.sql +720 -0
  49. package/drizzle/0382_organization_api_key_provenance.sql +91 -0
  50. package/drizzle/0383_codex_cooldown_reconciliation.sql +51 -0
  51. package/drizzle/0384_codex_cooldown_revision_guard_privileges.sql +6 -0
  52. package/drizzle/0385_connected_machine_legacy_tilde_workdirs.sql +25 -0
  53. package/drizzle/0386_local_organization_administration.sql +157 -0
  54. package/package.json +6 -6
  55. package/src/codex-token-resolver.ts +26 -1
  56. package/src/company-brain-governed-writes.ts +30 -1
  57. package/src/company-profile-agent-admin.ts +68 -1
  58. package/src/company-profile-agent-policy.ts +126 -0
  59. package/src/company-profile-schema.ts +115 -1
  60. package/src/database.ts +3 -5
  61. package/src/index.ts +3626 -456
  62. package/src/managed-human-provisioning.ts +3 -3
  63. package/src/memory-domain.ts +9 -4
  64. package/src/organization-membership-lifecycle.ts +0 -1
  65. package/src/provision-roles.ts +83 -4
  66. package/src/runtime-posture.ts +22 -0
  67. package/src/schema.ts +161 -8
  68. package/src/session-control.ts +177 -59
  69. package/src/session-queue-commands.ts +146 -40
  70. package/src/session-tool-call-settlement.ts +34 -7
  71. package/src/user-resource-authority.ts +56 -0
  72. package/dist/chunk-744DFC65.js.map +0 -1
  73. package/dist/chunk-UJ2EW3QI.js.map +0 -1
  74. package/dist/chunk-WW7AJ5IC.js.map +0 -1
  75. /package/dist/{chunk-IW6O6G7R.js.map → chunk-5NNCGFQY.js.map} +0 -0
  76. /package/dist/{chunk-G3732M3T.js.map → chunk-DZCYW2WT.js.map} +0 -0
  77. /package/dist/{chunk-CDMMSUWJ.js.map → chunk-S3TDDCS2.js.map} +0 -0
  78. /package/dist/{chunk-Q5YUGQVK.js.map → chunk-SZAWDXQC.js.map} +0 -0
  79. /package/dist/{chunk-UGDVSQ6U.js.map → chunk-U4WPPEBH.js.map} +0 -0
  80. /package/dist/{chunk-2NT476HD.js.map → chunk-US4IS6IV.js.map} +0 -0
@@ -0,0 +1,720 @@
1
+ -- deployment-mode: maintenance
2
+ --
3
+ -- Activate organization-owned Codex subscription pools. A shared workspace has
4
+ -- exactly one effective pool at a time: its own workspace credentials, the
5
+ -- organization's credentials, or disabled. Personal workspaces are always
6
+ -- workspace-local. Organization credentials keep one quota/refresh/cooldown
7
+ -- row and one allocator serialization point across every inheriting workspace.
8
+
9
+ SET LOCAL lock_timeout = '5s';
10
+ SET LOCAL statement_timeout = '10min';
11
+
12
+ LOCK TABLE "codex_subscription_credentials" IN ACCESS EXCLUSIVE MODE;
13
+ LOCK TABLE "codex_credential_leases" IN ACCESS EXCLUSIVE MODE;
14
+ LOCK TABLE "codex_rotation_settings" IN ACCESS EXCLUSIVE MODE;
15
+ LOCK TABLE "sessions" IN ACCESS EXCLUSIVE MODE;
16
+
17
+ ALTER TABLE "codex_subscription_credentials"
18
+ ADD COLUMN "organization_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
19
+
20
+ ALTER TABLE "codex_subscription_credentials"
21
+ ALTER COLUMN "workspace_id" DROP NOT NULL;
22
+
23
+ ALTER TABLE "codex_subscription_credentials"
24
+ DROP CONSTRAINT "codex_credentials_authority_scope_chk",
25
+ DROP CONSTRAINT "codex_credentials_authority_shape_chk";
26
+
27
+ ALTER TABLE "codex_subscription_credentials"
28
+ ADD CONSTRAINT "codex_credentials_authority_scope_chk" CHECK (
29
+ "authority_scope" IN ('workspace', 'user', 'organization')
30
+ ),
31
+ ADD CONSTRAINT "codex_credentials_authority_shape_chk" CHECK (
32
+ (
33
+ "authority_scope" = 'workspace'
34
+ AND "workspace_id" IS NOT NULL
35
+ AND "organization_id" IS NULL
36
+ AND "owner_organization_membership_id" IS NULL
37
+ AND "organization_user_resource_authority_id" IS NULL
38
+ AND "organization_user_resource_kind" IS NULL
39
+ AND "organization_user_resource_authority_generation" IS NULL
40
+ ) OR (
41
+ "authority_scope" = 'user'
42
+ AND "workspace_id" IS NOT NULL
43
+ AND "organization_id" IS NULL
44
+ AND "owner_organization_membership_id" IS NOT NULL
45
+ AND "organization_user_resource_authority_id" IS NOT NULL
46
+ AND "organization_user_resource_kind" = 'codex_subscription'
47
+ AND "organization_user_resource_authority_generation" IS NOT NULL
48
+ AND "organization_user_resource_authority_generation" > 0
49
+ ) OR (
50
+ "authority_scope" = 'organization'
51
+ AND "workspace_id" IS NULL
52
+ AND "organization_id" = "account_id"
53
+ AND "owner_organization_membership_id" IS NULL
54
+ AND "organization_user_resource_authority_id" IS NULL
55
+ AND "organization_user_resource_kind" IS NULL
56
+ AND "organization_user_resource_authority_generation" IS NULL
57
+ )
58
+ );
59
+
60
+ CREATE UNIQUE INDEX "codex_subscription_credentials_organization_account_idx"
61
+ ON "codex_subscription_credentials" ("organization_id", "chatgpt_account_id")
62
+ WHERE "authority_scope" = 'organization' AND "chatgpt_account_id" IS NOT NULL;
63
+ CREATE UNIQUE INDEX "codex_subscription_credentials_account_id_idx"
64
+ ON "codex_subscription_credentials" ("account_id", "id");
65
+ CREATE INDEX "codex_subscription_credentials_organization_lookup_idx"
66
+ ON "codex_subscription_credentials" ("organization_id", "created_at", "id")
67
+ WHERE "authority_scope" = 'organization';
68
+
69
+ CREATE TABLE "workspace_codex_subscription_preferences" (
70
+ "workspace_id" uuid PRIMARY KEY REFERENCES "workspaces"("id") ON DELETE CASCADE,
71
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
72
+ "mode" text NOT NULL DEFAULT 'automatic',
73
+ "updated_by_subject_id" text,
74
+ "created_at" timestamptz NOT NULL DEFAULT now(),
75
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
76
+ CONSTRAINT "workspace_codex_subscription_preferences_workspace_account_fk"
77
+ FOREIGN KEY ("workspace_id", "account_id")
78
+ REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE,
79
+ CONSTRAINT "workspace_codex_subscription_preferences_mode_chk"
80
+ CHECK ("mode" IN ('automatic', 'workspace', 'organization', 'disabled'))
81
+ );
82
+
83
+ ALTER TABLE "workspace_codex_subscription_preferences" ENABLE ROW LEVEL SECURITY;
84
+ ALTER TABLE "workspace_codex_subscription_preferences" FORCE ROW LEVEL SECURITY;
85
+ CREATE POLICY workspace_isolation ON "workspace_codex_subscription_preferences"
86
+ USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
87
+ WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
88
+
89
+ DO $codex_scope_visibility_schema$
90
+ DECLARE data_schema text := current_schema();
91
+ BEGIN
92
+ EXECUTE format($ddl$
93
+ CREATE OR REPLACE FUNCTION opengeni_private.codex_organization_scope_visible(
94
+ p_account_id uuid
95
+ ) RETURNS boolean
96
+ LANGUAGE plpgsql
97
+ SECURITY DEFINER
98
+ SET search_path = pg_catalog
99
+ AS $function$
100
+ DECLARE
101
+ workspace_value uuid := opengeni_private.current_workspace_id();
102
+ subject_value text := opengeni_private.current_subject_id();
103
+ visible boolean := false;
104
+ previous_lifecycle text := pg_catalog.current_setting(
105
+ 'opengeni.organization_tenancy_lifecycle', true
106
+ );
107
+ BEGIN
108
+ IF p_account_id IS NULL
109
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
110
+ THEN
111
+ RETURN false;
112
+ END IF;
113
+ IF workspace_value IS NOT NULL THEN
114
+ PERFORM pg_catalog.set_config(
115
+ 'opengeni.organization_tenancy_lifecycle',
116
+ 'organization_membership_lifecycle', true
117
+ );
118
+ SELECT EXISTS (
119
+ SELECT 1 FROM %1$I.workspaces workspace
120
+ WHERE workspace.account_id = p_account_id AND workspace.id = workspace_value
121
+ ) AND NOT EXISTS (
122
+ SELECT 1 FROM %1$I.organization_memberships membership
123
+ WHERE membership.account_id = p_account_id
124
+ AND membership.personal_workspace_id = workspace_value
125
+ ) INTO visible;
126
+ PERFORM pg_catalog.set_config(
127
+ 'opengeni.organization_tenancy_lifecycle', coalesce(previous_lifecycle, ''), true
128
+ );
129
+ RETURN coalesce(visible, false);
130
+ END IF;
131
+ IF subject_value IS NULL OR subject_value NOT LIKE 'user:%%' THEN
132
+ RETURN false;
133
+ END IF;
134
+ PERFORM pg_catalog.set_config(
135
+ 'opengeni.organization_tenancy_lifecycle',
136
+ 'organization_membership_lifecycle', true
137
+ );
138
+ SELECT EXISTS (
139
+ SELECT 1 FROM %1$I.organization_memberships membership
140
+ WHERE membership.account_id = p_account_id
141
+ AND membership.subject_id = subject_value
142
+ AND membership.status = 'active'
143
+ AND membership.role IN ('owner', 'admin')
144
+ ) INTO visible;
145
+ PERFORM pg_catalog.set_config(
146
+ 'opengeni.organization_tenancy_lifecycle', coalesce(previous_lifecycle, ''), true
147
+ );
148
+ RETURN coalesce(visible, false);
149
+ EXCEPTION WHEN OTHERS THEN
150
+ PERFORM pg_catalog.set_config(
151
+ 'opengeni.organization_tenancy_lifecycle', coalesce(previous_lifecycle, ''), true
152
+ );
153
+ RAISE;
154
+ END
155
+ $function$
156
+ $ddl$, data_schema);
157
+ END
158
+ $codex_scope_visibility_schema$;
159
+
160
+ CREATE OR REPLACE FUNCTION opengeni_private.codex_organization_admin_visible(
161
+ p_account_id uuid
162
+ ) RETURNS boolean
163
+ LANGUAGE sql
164
+ STABLE
165
+ SECURITY DEFINER
166
+ SET search_path = pg_catalog
167
+ AS $body$
168
+ SELECT opengeni_private.current_workspace_id() IS NULL
169
+ AND opengeni_private.codex_organization_scope_visible(p_account_id)
170
+ $body$;
171
+
172
+ DROP POLICY workspace_isolation ON "codex_subscription_credentials";
173
+ CREATE POLICY workspace_isolation ON "codex_subscription_credentials"
174
+ USING (
175
+ authority_scope IN ('workspace', 'user')
176
+ AND workspace_id IS NOT NULL
177
+ AND opengeni_private.workspace_rls_visible(account_id, workspace_id)
178
+ )
179
+ WITH CHECK (
180
+ authority_scope IN ('workspace', 'user')
181
+ AND workspace_id IS NOT NULL
182
+ AND opengeni_private.workspace_rls_visible(account_id, workspace_id)
183
+ );
184
+ CREATE POLICY organization_scope_select ON "codex_subscription_credentials"
185
+ FOR SELECT USING (
186
+ authority_scope = 'organization'
187
+ AND organization_id = account_id
188
+ AND opengeni_private.codex_organization_scope_visible(account_id)
189
+ );
190
+ CREATE POLICY organization_scope_update_admin ON "codex_subscription_credentials"
191
+ FOR UPDATE USING (
192
+ authority_scope = 'organization'
193
+ AND organization_id = account_id
194
+ AND opengeni_private.codex_organization_admin_visible(account_id)
195
+ ) WITH CHECK (
196
+ authority_scope = 'organization'
197
+ AND organization_id = account_id
198
+ AND opengeni_private.codex_organization_admin_visible(account_id)
199
+ );
200
+ CREATE POLICY organization_scope_update_runtime ON "codex_subscription_credentials"
201
+ FOR UPDATE USING (
202
+ authority_scope = 'organization'
203
+ AND organization_id = account_id
204
+ AND opengeni_private.current_workspace_id() IS NOT NULL
205
+ AND opengeni_private.codex_organization_scope_visible(account_id)
206
+ ) WITH CHECK (
207
+ authority_scope = 'organization'
208
+ AND organization_id = account_id
209
+ AND opengeni_private.current_workspace_id() IS NOT NULL
210
+ AND opengeni_private.codex_organization_scope_visible(account_id)
211
+ );
212
+ CREATE POLICY organization_scope_insert ON "codex_subscription_credentials"
213
+ FOR INSERT WITH CHECK (
214
+ authority_scope = 'organization'
215
+ AND organization_id = account_id
216
+ AND opengeni_private.codex_organization_admin_visible(account_id)
217
+ );
218
+ CREATE POLICY organization_scope_delete ON "codex_subscription_credentials"
219
+ FOR DELETE USING (
220
+ authority_scope = 'organization'
221
+ AND organization_id = account_id
222
+ AND opengeni_private.codex_organization_admin_visible(account_id)
223
+ );
224
+
225
+ -- Shared-workspace runtime paths must refresh tokens and maintain health,
226
+ -- quota, cooldown, and fairness metadata on the inherited organization row.
227
+ -- RLS selects the exact organization pool; this trigger keeps that runtime
228
+ -- exception column- and transition-limited so workspace-context code cannot
229
+ -- mutate organization ownership, provider identity, labels, or allocator
230
+ -- administration. Organization owner/admin writes run without a workspace GUC
231
+ -- and are governed by organization_scope_update_admin instead.
232
+ CREATE OR REPLACE FUNCTION opengeni_private.enforce_organization_codex_runtime_update()
233
+ RETURNS trigger
234
+ LANGUAGE plpgsql
235
+ SECURITY DEFINER
236
+ SET search_path = pg_catalog
237
+ AS $body$
238
+ BEGIN
239
+ IF OLD.authority_scope IS DISTINCT FROM 'organization'
240
+ OR opengeni_private.current_workspace_id() IS NULL
241
+ THEN
242
+ RETURN NEW;
243
+ END IF;
244
+
245
+ IF NEW.id IS DISTINCT FROM OLD.id
246
+ OR NEW.account_id IS DISTINCT FROM OLD.account_id
247
+ OR NEW.workspace_id IS DISTINCT FROM OLD.workspace_id
248
+ OR NEW.organization_id IS DISTINCT FROM OLD.organization_id
249
+ OR NEW.authority_scope IS DISTINCT FROM OLD.authority_scope
250
+ OR NEW.owner_organization_membership_id IS DISTINCT FROM OLD.owner_organization_membership_id
251
+ OR NEW.organization_user_resource_authority_id IS DISTINCT FROM OLD.organization_user_resource_authority_id
252
+ OR NEW.organization_user_resource_kind IS DISTINCT FROM OLD.organization_user_resource_kind
253
+ OR NEW.organization_user_resource_authority_generation IS DISTINCT FROM OLD.organization_user_resource_authority_generation
254
+ OR NEW.chatgpt_account_id IS DISTINCT FROM OLD.chatgpt_account_id
255
+ OR NEW.scopes IS DISTINCT FROM OLD.scopes
256
+ OR NEW.plan_type IS DISTINCT FROM OLD.plan_type
257
+ OR NEW.is_fedramp IS DISTINCT FROM OLD.is_fedramp
258
+ OR NEW.label IS DISTINCT FROM OLD.label
259
+ OR NEW.account_email IS DISTINCT FROM OLD.account_email
260
+ OR NEW.allocator_enabled IS DISTINCT FROM OLD.allocator_enabled
261
+ OR NEW.allocator_version IS DISTINCT FROM OLD.allocator_version
262
+ OR NEW.allocator_updated_by_subject_id IS DISTINCT FROM OLD.allocator_updated_by_subject_id
263
+ OR NEW.allocator_updated_at IS DISTINCT FROM OLD.allocator_updated_at
264
+ OR NEW.connected_by_subject_id IS DISTINCT FROM OLD.connected_by_subject_id
265
+ OR NEW.created_at IS DISTINCT FROM OLD.created_at
266
+ THEN
267
+ RAISE EXCEPTION 'organization Codex credential management requires organization administration'
268
+ USING ERRCODE = '42501';
269
+ END IF;
270
+
271
+ IF NEW.credential_encrypted IS DISTINCT FROM OLD.credential_encrypted
272
+ OR NEW.expires_at IS DISTINCT FROM OLD.expires_at
273
+ OR NEW.last_refresh_at IS DISTINCT FROM OLD.last_refresh_at
274
+ OR NEW.version IS DISTINCT FROM OLD.version
275
+ THEN
276
+ IF NEW.credential_encrypted IS NOT DISTINCT FROM OLD.credential_encrypted
277
+ OR NEW.version IS DISTINCT FROM OLD.version + 1
278
+ OR NEW.last_refresh_at IS NULL
279
+ OR NEW.last_refresh_at IS NOT DISTINCT FROM OLD.last_refresh_at
280
+ OR NEW.status IS DISTINCT FROM 'active'
281
+ OR NEW.last_error IS NOT NULL
282
+ OR NEW.primary_used_percent IS DISTINCT FROM OLD.primary_used_percent
283
+ OR NEW.primary_reset_at IS DISTINCT FROM OLD.primary_reset_at
284
+ OR NEW.secondary_used_percent IS DISTINCT FROM OLD.secondary_used_percent
285
+ OR NEW.secondary_reset_at IS DISTINCT FROM OLD.secondary_reset_at
286
+ OR NEW.usage_checked_at IS DISTINCT FROM OLD.usage_checked_at
287
+ OR NEW.exhausted_until IS DISTINCT FROM OLD.exhausted_until
288
+ OR NEW.reset_credit_available_count IS DISTINCT FROM OLD.reset_credit_available_count
289
+ OR NEW.reset_credits_checked_at IS DISTINCT FROM OLD.reset_credits_checked_at
290
+ OR NEW.selection_count IS DISTINCT FROM OLD.selection_count
291
+ OR NEW.last_selected_at IS DISTINCT FROM OLD.last_selected_at
292
+ THEN
293
+ RAISE EXCEPTION 'organization Codex runtime token refresh has an invalid mutation shape'
294
+ USING ERRCODE = '42501';
295
+ END IF;
296
+ END IF;
297
+
298
+ RETURN NEW;
299
+ END
300
+ $body$;
301
+
302
+ CREATE TABLE "organization_codex_rotation_settings" (
303
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
304
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
305
+ "active_credential_id" uuid,
306
+ "rotation_enabled" boolean NOT NULL DEFAULT false,
307
+ "lease_rotation_enabled" boolean NOT NULL DEFAULT false,
308
+ "rotation_strategy" text NOT NULL DEFAULT 'sharded',
309
+ "created_at" timestamptz NOT NULL DEFAULT now(),
310
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
311
+ CONSTRAINT "organization_codex_rotation_settings_active_fk"
312
+ FOREIGN KEY ("active_credential_id")
313
+ REFERENCES "codex_subscription_credentials"("id")
314
+ ON DELETE SET NULL
315
+ );
316
+ CREATE UNIQUE INDEX "organization_codex_rotation_settings_account_idx"
317
+ ON "organization_codex_rotation_settings" ("account_id");
318
+
319
+ ALTER TABLE "organization_codex_rotation_settings" ENABLE ROW LEVEL SECURITY;
320
+ ALTER TABLE "organization_codex_rotation_settings" FORCE ROW LEVEL SECURITY;
321
+ CREATE POLICY organization_scope ON "organization_codex_rotation_settings"
322
+ USING (opengeni_private.codex_organization_scope_visible(account_id))
323
+ WITH CHECK (opengeni_private.codex_organization_scope_visible(account_id));
324
+
325
+ CREATE OR REPLACE FUNCTION resolve_workspace_codex_subscription_source(
326
+ p_account_id uuid,
327
+ p_workspace_id uuid
328
+ ) RETURNS text
329
+ LANGUAGE plpgsql
330
+ SECURITY INVOKER
331
+ SET search_path FROM CURRENT
332
+ AS $body$
333
+ DECLARE
334
+ mode_value text := 'automatic';
335
+ workspace_kind text;
336
+ BEGIN
337
+ IF p_account_id IS NULL OR p_workspace_id IS NULL
338
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
339
+ OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
340
+ THEN
341
+ RAISE EXCEPTION 'Codex workspace source authority required' USING ERRCODE = '42501';
342
+ END IF;
343
+ IF NOT EXISTS (
344
+ SELECT 1 FROM workspaces workspace
345
+ WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
346
+ ) THEN
347
+ RAISE EXCEPTION 'workspace not found' USING ERRCODE = 'P0002';
348
+ END IF;
349
+ workspace_kind := get_workspace_kind(p_account_id, p_workspace_id);
350
+ IF workspace_kind = 'personal' THEN
351
+ RETURN 'workspace';
352
+ END IF;
353
+ SELECT preference.mode INTO mode_value
354
+ FROM workspace_codex_subscription_preferences preference
355
+ WHERE preference.account_id = p_account_id
356
+ AND preference.workspace_id = p_workspace_id;
357
+ mode_value := coalesce(mode_value, 'automatic');
358
+ IF mode_value <> 'automatic' THEN
359
+ RETURN mode_value;
360
+ END IF;
361
+ IF EXISTS (
362
+ SELECT 1 FROM codex_subscription_credentials credential
363
+ WHERE credential.account_id = p_account_id
364
+ AND credential.workspace_id = p_workspace_id
365
+ AND credential.authority_scope IN ('workspace', 'user')
366
+ ) THEN
367
+ RETURN 'workspace';
368
+ END IF;
369
+ IF EXISTS (
370
+ SELECT 1 FROM codex_subscription_credentials credential
371
+ WHERE credential.account_id = p_account_id
372
+ AND credential.organization_id = p_account_id
373
+ AND credential.authority_scope = 'organization'
374
+ ) THEN
375
+ RETURN 'organization';
376
+ END IF;
377
+ RETURN 'workspace';
378
+ END
379
+ $body$;
380
+
381
+ CREATE OR REPLACE FUNCTION validate_personal_codex_credential_authority()
382
+ RETURNS trigger
383
+ LANGUAGE plpgsql
384
+ AS $body$
385
+ DECLARE exact_authority boolean;
386
+ BEGIN
387
+ IF NEW.authority_scope IN ('workspace', 'organization') THEN
388
+ RETURN NEW;
389
+ END IF;
390
+ SELECT true INTO exact_authority
391
+ FROM organization_memberships membership
392
+ INNER JOIN organization_user_resource_authorities authority
393
+ ON authority.id = NEW.organization_user_resource_authority_id
394
+ AND authority.account_id = membership.account_id
395
+ AND authority.organization_membership_id = membership.id
396
+ WHERE membership.id = NEW.owner_organization_membership_id
397
+ AND membership.account_id = NEW.account_id
398
+ AND membership.status = 'active'
399
+ AND membership.revoked_at IS NULL
400
+ AND authority.resource_kind = 'codex_subscription'
401
+ AND authority.resource_id = NEW.id
402
+ AND authority.generation = NEW.organization_user_resource_authority_generation
403
+ AND authority.status = 'active'
404
+ AND authority.revoked_at IS NULL
405
+ FOR KEY SHARE OF membership, authority;
406
+ IF exact_authority IS DISTINCT FROM true THEN
407
+ RAISE EXCEPTION 'personal Codex credential authority tuple is invalid'
408
+ USING ERRCODE = '23514';
409
+ END IF;
410
+ RETURN NEW;
411
+ END
412
+ $body$;
413
+
414
+ -- Organization credentials may serve turns in many workspaces. Keep the turn
415
+ -- workspace FK, but validate the credential/source relation in a trigger.
416
+ ALTER TABLE "codex_credential_leases"
417
+ DROP CONSTRAINT "codex_credential_leases_workspace_credential_fk";
418
+ ALTER TABLE "codex_credential_leases"
419
+ ADD CONSTRAINT "codex_credential_leases_account_credential_fk"
420
+ FOREIGN KEY ("account_id", "credential_id")
421
+ REFERENCES "codex_subscription_credentials"("account_id", "id")
422
+ ON DELETE CASCADE;
423
+ DROP INDEX "codex_credential_leases_active_credential_idx";
424
+ CREATE INDEX "codex_credential_leases_active_credential_idx"
425
+ ON "codex_credential_leases" ("credential_id", "leased_until");
426
+
427
+ DO $codex_reference_guards$
428
+ DECLARE data_schema text := current_schema();
429
+ BEGIN
430
+ EXECUTE format($ddl$
431
+ CREATE OR REPLACE FUNCTION opengeni_private.codex_credential_serves_workspace(
432
+ p_account_id uuid,
433
+ p_workspace_id uuid,
434
+ p_credential_id uuid
435
+ ) RETURNS boolean
436
+ LANGUAGE plpgsql
437
+ SECURITY DEFINER
438
+ SET search_path = pg_catalog, %1$I
439
+ AS $function$
440
+ DECLARE
441
+ credential codex_subscription_credentials%%ROWTYPE;
442
+ workspace_kind text;
443
+ mode_value text := 'automatic';
444
+ effective_source text;
445
+ BEGIN
446
+ SELECT * INTO credential
447
+ FROM codex_subscription_credentials candidate
448
+ WHERE candidate.account_id = p_account_id AND candidate.id = p_credential_id;
449
+ IF NOT FOUND THEN RETURN false; END IF;
450
+ workspace_kind := CASE WHEN EXISTS (
451
+ SELECT 1 FROM organization_memberships membership
452
+ WHERE membership.account_id = p_account_id
453
+ AND membership.personal_workspace_id = p_workspace_id
454
+ ) THEN 'personal' ELSE 'shared' END;
455
+ IF workspace_kind = 'personal' THEN
456
+ effective_source := 'workspace';
457
+ ELSE
458
+ SELECT preference.mode INTO mode_value
459
+ FROM workspace_codex_subscription_preferences preference
460
+ WHERE preference.account_id = p_account_id
461
+ AND preference.workspace_id = p_workspace_id;
462
+ mode_value := coalesce(mode_value, 'automatic');
463
+ IF mode_value <> 'automatic' THEN
464
+ effective_source := mode_value;
465
+ ELSIF EXISTS (
466
+ SELECT 1 FROM codex_subscription_credentials candidate
467
+ WHERE candidate.account_id = p_account_id
468
+ AND candidate.workspace_id = p_workspace_id
469
+ AND candidate.authority_scope IN ('workspace', 'user')
470
+ ) THEN
471
+ effective_source := 'workspace';
472
+ ELSIF EXISTS (
473
+ SELECT 1 FROM codex_subscription_credentials candidate
474
+ WHERE candidate.account_id = p_account_id
475
+ AND candidate.organization_id = p_account_id
476
+ AND candidate.authority_scope = 'organization'
477
+ ) THEN
478
+ effective_source := 'organization';
479
+ ELSE
480
+ effective_source := 'workspace';
481
+ END IF;
482
+ END IF;
483
+ IF credential.authority_scope IN ('workspace', 'user') THEN
484
+ RETURN credential.workspace_id = p_workspace_id
485
+ AND effective_source = 'workspace';
486
+ END IF;
487
+ RETURN credential.authority_scope = 'organization'
488
+ AND credential.organization_id = p_account_id
489
+ AND effective_source = 'organization';
490
+ END
491
+ $function$;
492
+
493
+ CREATE OR REPLACE FUNCTION opengeni_private.enforce_codex_lease_source()
494
+ RETURNS trigger
495
+ LANGUAGE plpgsql
496
+ SECURITY DEFINER
497
+ SET search_path = pg_catalog, %1$I
498
+ AS $function$
499
+ BEGIN
500
+ IF NOT opengeni_private.codex_credential_serves_workspace(
501
+ NEW.account_id, NEW.workspace_id, NEW.credential_id
502
+ ) THEN
503
+ RAISE EXCEPTION 'Codex credential is outside the workspace effective pool'
504
+ USING ERRCODE = '23514';
505
+ END IF;
506
+ RETURN NEW;
507
+ END
508
+ $function$;
509
+
510
+ CREATE OR REPLACE FUNCTION opengeni_private.codex_organization_live_lease_count(
511
+ p_account_id uuid,
512
+ p_credential_id uuid,
513
+ p_exclude_turn_id uuid
514
+ ) RETURNS integer
515
+ LANGUAGE plpgsql
516
+ SECURITY DEFINER
517
+ SET search_path = pg_catalog, %1$I
518
+ AS $function$
519
+ DECLARE live_count integer;
520
+ BEGIN
521
+ IF p_account_id IS NULL
522
+ OR p_credential_id IS NULL
523
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
524
+ OR opengeni_private.current_workspace_id() IS NULL
525
+ OR NOT EXISTS (
526
+ SELECT 1 FROM codex_subscription_credentials credential
527
+ WHERE credential.account_id = p_account_id
528
+ AND credential.id = p_credential_id
529
+ AND credential.organization_id = p_account_id
530
+ AND credential.authority_scope = 'organization'
531
+ )
532
+ OR NOT opengeni_private.codex_credential_serves_workspace(
533
+ p_account_id,
534
+ opengeni_private.current_workspace_id(),
535
+ p_credential_id
536
+ )
537
+ THEN
538
+ RAISE EXCEPTION 'organization Codex lease-count authority required'
539
+ USING ERRCODE = '42501';
540
+ END IF;
541
+ SELECT count(*)::integer INTO live_count
542
+ FROM codex_credential_leases lease
543
+ WHERE lease.account_id = p_account_id
544
+ AND lease.credential_id = p_credential_id
545
+ AND lease.leased_until > now()
546
+ AND (p_exclude_turn_id IS NULL OR lease.turn_id <> p_exclude_turn_id);
547
+ RETURN live_count;
548
+ END
549
+ $function$;
550
+
551
+ CREATE OR REPLACE FUNCTION opengeni_private.enforce_codex_credential_workspace()
552
+ RETURNS trigger
553
+ LANGUAGE plpgsql
554
+ SECURITY DEFINER
555
+ SET search_path = pg_catalog, %1$I
556
+ AS $function$
557
+ DECLARE candidate uuid;
558
+ BEGIN
559
+ IF TG_TABLE_NAME = 'codex_rotation_settings' THEN
560
+ candidate := NEW.active_credential_id;
561
+ IF candidate IS NOT NULL AND NOT EXISTS (
562
+ SELECT 1 FROM codex_subscription_credentials credential
563
+ WHERE credential.id = candidate
564
+ AND credential.account_id = NEW.account_id
565
+ AND credential.workspace_id = NEW.workspace_id
566
+ AND credential.authority_scope IN ('workspace', 'user')
567
+ ) THEN
568
+ RAISE EXCEPTION 'Codex rotation credential must remain workspace-owned'
569
+ USING ERRCODE = '23514';
570
+ END IF;
571
+ ELSIF TG_TABLE_NAME = 'organization_codex_rotation_settings' THEN
572
+ candidate := NEW.active_credential_id;
573
+ IF candidate IS NOT NULL AND NOT EXISTS (
574
+ SELECT 1 FROM codex_subscription_credentials credential
575
+ WHERE credential.id = candidate
576
+ AND credential.account_id = NEW.account_id
577
+ AND credential.organization_id = NEW.account_id
578
+ AND credential.authority_scope = 'organization'
579
+ ) THEN
580
+ RAISE EXCEPTION 'Codex rotation credential must remain organization-owned'
581
+ USING ERRCODE = '23514';
582
+ END IF;
583
+ ELSIF TG_ARGV[0] = 'pinned' THEN
584
+ candidate := NEW.codex_pinned_credential_id;
585
+ ELSE
586
+ candidate := NEW.codex_last_credential_id;
587
+ END IF;
588
+ IF candidate IS NULL OR TG_TABLE_NAME IN (
589
+ 'codex_rotation_settings', 'organization_codex_rotation_settings'
590
+ ) THEN
591
+ RETURN NEW;
592
+ END IF;
593
+ IF NOT opengeni_private.codex_credential_serves_workspace(
594
+ NEW.account_id, NEW.workspace_id, candidate
595
+ ) THEN
596
+ RAISE EXCEPTION 'Codex session credential is outside the workspace effective pool'
597
+ USING ERRCODE = '23514';
598
+ END IF;
599
+ RETURN NEW;
600
+ END
601
+ $function$;
602
+
603
+ CREATE OR REPLACE FUNCTION opengeni_private.prevent_organization_codex_disconnect_with_live_leases()
604
+ RETURNS trigger
605
+ LANGUAGE plpgsql
606
+ SECURITY DEFINER
607
+ SET search_path = pg_catalog, %1$I
608
+ AS $function$
609
+ BEGIN
610
+ IF EXISTS (
611
+ SELECT 1 FROM codex_credential_leases lease
612
+ WHERE lease.account_id = OLD.account_id
613
+ AND lease.credential_id = OLD.id
614
+ AND lease.leased_until > now()
615
+ ) THEN
616
+ RAISE EXCEPTION 'Codex subscription cannot disconnect while active turns are using it'
617
+ USING ERRCODE = '55006';
618
+ END IF;
619
+ RETURN OLD;
620
+ END
621
+ $function$;
622
+ $ddl$, data_schema);
623
+ END
624
+ $codex_reference_guards$;
625
+
626
+ DROP TRIGGER codex_credentials_validate_user_authority_trg
627
+ ON "codex_subscription_credentials";
628
+ CREATE TRIGGER codex_credentials_validate_user_authority_trg
629
+ BEFORE INSERT OR UPDATE OF
630
+ id, account_id, workspace_id, organization_id, authority_scope,
631
+ owner_organization_membership_id, organization_user_resource_authority_id,
632
+ organization_user_resource_kind, organization_user_resource_authority_generation
633
+ ON "codex_subscription_credentials"
634
+ FOR EACH ROW EXECUTE FUNCTION validate_personal_codex_credential_authority();
635
+
636
+ CREATE TRIGGER codex_credentials_organization_runtime_update_guard
637
+ BEFORE UPDATE ON "codex_subscription_credentials"
638
+ FOR EACH ROW EXECUTE FUNCTION opengeni_private.enforce_organization_codex_runtime_update();
639
+
640
+ CREATE TRIGGER codex_credentials_organization_live_lease_disconnect_guard
641
+ BEFORE DELETE ON "codex_subscription_credentials"
642
+ FOR EACH ROW WHEN (OLD.authority_scope = 'organization')
643
+ EXECUTE FUNCTION opengeni_private.prevent_organization_codex_disconnect_with_live_leases();
644
+
645
+ CREATE TRIGGER codex_credential_leases_source_guard
646
+ BEFORE INSERT OR UPDATE OF account_id, workspace_id, credential_id
647
+ ON "codex_credential_leases"
648
+ FOR EACH ROW EXECUTE FUNCTION opengeni_private.enforce_codex_lease_source();
649
+
650
+ CREATE TRIGGER organization_codex_rotation_settings_credential_guard
651
+ BEFORE INSERT OR UPDATE OF active_credential_id, account_id
652
+ ON "organization_codex_rotation_settings"
653
+ FOR EACH ROW EXECUTE FUNCTION opengeni_private.enforce_codex_credential_workspace();
654
+
655
+ CREATE OR REPLACE FUNCTION opengeni_private.clear_workspace_codex_session_affinity()
656
+ RETURNS trigger
657
+ LANGUAGE plpgsql
658
+ SECURITY DEFINER
659
+ SET search_path FROM CURRENT
660
+ AS $body$
661
+ BEGIN
662
+ UPDATE sessions
663
+ SET codex_pinned_credential_id = NULL,
664
+ codex_pin_source = NULL,
665
+ codex_last_credential_id = NULL,
666
+ updated_at = now()
667
+ WHERE account_id = NEW.account_id AND workspace_id = NEW.workspace_id
668
+ AND (codex_pinned_credential_id IS NOT NULL OR codex_last_credential_id IS NOT NULL);
669
+ RETURN NEW;
670
+ END
671
+ $body$;
672
+ CREATE TRIGGER workspace_codex_subscription_preference_affinity_reset
673
+ AFTER INSERT OR UPDATE OF mode ON "workspace_codex_subscription_preferences"
674
+ FOR EACH ROW EXECUTE FUNCTION opengeni_private.clear_workspace_codex_session_affinity();
675
+
676
+ -- Organization credentials are intentionally excluded from workspace Apps and
677
+ -- reset-credit mutation authority. Those existing composite FKs still require
678
+ -- a non-null matching workspace_id.
679
+
680
+ DO $organization_codex_grants$
681
+ DECLARE data_schema text := current_schema();
682
+ BEGIN
683
+ REVOKE ALL ON FUNCTION opengeni_private.codex_organization_scope_visible(uuid) FROM PUBLIC;
684
+ REVOKE ALL ON FUNCTION opengeni_private.codex_organization_admin_visible(uuid) FROM PUBLIC;
685
+ REVOKE ALL ON FUNCTION opengeni_private.codex_organization_live_lease_count(uuid,uuid,uuid)
686
+ FROM PUBLIC;
687
+ REVOKE ALL ON FUNCTION opengeni_private.enforce_codex_lease_source() FROM PUBLIC;
688
+ REVOKE ALL ON FUNCTION opengeni_private.enforce_codex_credential_workspace() FROM PUBLIC;
689
+ REVOKE ALL ON FUNCTION opengeni_private.clear_workspace_codex_session_affinity() FROM PUBLIC;
690
+ REVOKE ALL ON FUNCTION opengeni_private.enforce_organization_codex_runtime_update() FROM PUBLIC;
691
+ REVOKE ALL ON FUNCTION opengeni_private.prevent_organization_codex_disconnect_with_live_leases()
692
+ FROM PUBLIC;
693
+ REVOKE ALL ON FUNCTION resolve_workspace_codex_subscription_source(uuid,uuid) FROM PUBLIC;
694
+ REVOKE ALL ON FUNCTION opengeni_private.codex_credential_serves_workspace(uuid,uuid,uuid)
695
+ FROM PUBLIC;
696
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
697
+ EXECUTE format(
698
+ 'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE %1$I.workspace_codex_subscription_preferences, %1$I.organization_codex_rotation_settings TO opengeni_app',
699
+ data_schema
700
+ );
701
+ EXECUTE format(
702
+ 'GRANT EXECUTE ON FUNCTION %1$I.resolve_workspace_codex_subscription_source(uuid,uuid) TO opengeni_app',
703
+ data_schema
704
+ );
705
+ GRANT EXECUTE ON FUNCTION opengeni_private.codex_organization_scope_visible(uuid)
706
+ TO opengeni_app;
707
+ GRANT EXECUTE ON FUNCTION opengeni_private.codex_organization_admin_visible(uuid)
708
+ TO opengeni_app;
709
+ GRANT EXECUTE ON FUNCTION opengeni_private.codex_organization_live_lease_count(uuid,uuid,uuid)
710
+ TO opengeni_app;
711
+ END IF;
712
+ END
713
+ $organization_codex_grants$;
714
+
715
+ COMMENT ON COLUMN "codex_subscription_credentials"."organization_id" IS
716
+ 'Organization owner for authority_scope=organization; workspace_id is null for these rows.';
717
+ COMMENT ON TABLE "workspace_codex_subscription_preferences" IS
718
+ 'One effective Codex source per workspace. Absent means automatic; personal workspaces remain local.';
719
+ COMMENT ON TABLE "organization_codex_rotation_settings" IS
720
+ 'Organization-wide Codex allocator serialization point and active cursor.';