@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.
- package/dist/canonical-human-identities.js +3 -3
- package/dist/{chunk-744DFC65.js → chunk-4NAR7FBA.js} +92 -6
- package/dist/chunk-4NAR7FBA.js.map +1 -0
- package/dist/{chunk-IW6O6G7R.js → chunk-5NNCGFQY.js} +2 -2
- package/dist/{chunk-G3732M3T.js → chunk-DZCYW2WT.js} +2 -2
- package/dist/{chunk-WW7AJ5IC.js → chunk-F6PBS6WE.js} +5 -7
- package/dist/chunk-F6PBS6WE.js.map +1 -0
- package/dist/{chunk-UJ2EW3QI.js → chunk-O56DM5GZ.js} +340 -85
- package/dist/chunk-O56DM5GZ.js.map +1 -0
- package/dist/{chunk-CDMMSUWJ.js → chunk-S3TDDCS2.js} +3 -3
- package/dist/{chunk-Q5YUGQVK.js → chunk-SZAWDXQC.js} +3 -3
- package/dist/{chunk-UGDVSQ6U.js → chunk-U4WPPEBH.js} +2 -2
- package/dist/{chunk-2NT476HD.js → chunk-US4IS6IV.js} +2 -2
- package/dist/codex-token-resolver.d.ts +12 -1
- package/dist/company-profile-agent-admin.d.ts +4 -2
- package/dist/company-profile-agent-policy.d.ts +20 -0
- package/dist/company-profile-schema.d.ts +573 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +382 -18
- package/dist/index.js +4513 -2065
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/managed-human-provisioning.d.ts +3 -3
- package/dist/memory-domain.d.ts +5 -3
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +5 -5
- package/dist/schema.d.ts +725 -4
- package/dist/schema.js +13 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-control.d.ts +40 -5
- package/dist/session-queue-commands.d.ts +2 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/user-resource-authority.d.ts +8 -0
- package/dist/video-generation.js +3 -3
- package/drizzle/0369_local_human_personal_authority.sql +350 -0
- package/drizzle/0370_workspace_member_management_scope.sql +98 -0
- package/drizzle/0371_workspace_member_candidate_inventory.sql +128 -0
- package/drizzle/0372_ordered_variable_set_runtime_authority.sql +287 -0
- package/drizzle/0373_sandbox_shared_preparation.sql +59 -0
- package/drizzle/0374_session_event_cursors.sql +315 -0
- package/drizzle/0375_session_recovery_observability.sql +73 -0
- package/drizzle/0376_organization_workspace_inventory.sql +88 -0
- package/drizzle/0377_scoped_rig_health_projection.sql +80 -0
- package/drizzle/0378_scoped_rig_health_audit_timestamp.sql +77 -0
- package/drizzle/0379_session_event_raw_lane_activation.sql +518 -0
- package/drizzle/0380_autonomous_company_profile_agent_policy.sql +829 -0
- package/drizzle/0381_organization_codex_subscription_inheritance.sql +720 -0
- package/drizzle/0382_organization_api_key_provenance.sql +91 -0
- package/drizzle/0383_codex_cooldown_reconciliation.sql +51 -0
- package/drizzle/0384_codex_cooldown_revision_guard_privileges.sql +6 -0
- package/drizzle/0385_connected_machine_legacy_tilde_workdirs.sql +25 -0
- package/drizzle/0386_local_organization_administration.sql +157 -0
- package/package.json +6 -6
- package/src/codex-token-resolver.ts +26 -1
- package/src/company-brain-governed-writes.ts +30 -1
- package/src/company-profile-agent-admin.ts +68 -1
- package/src/company-profile-agent-policy.ts +126 -0
- package/src/company-profile-schema.ts +115 -1
- package/src/database.ts +3 -5
- package/src/index.ts +3626 -456
- package/src/managed-human-provisioning.ts +3 -3
- package/src/memory-domain.ts +9 -4
- package/src/organization-membership-lifecycle.ts +0 -1
- package/src/provision-roles.ts +83 -4
- package/src/runtime-posture.ts +22 -0
- package/src/schema.ts +161 -8
- package/src/session-control.ts +177 -59
- package/src/session-queue-commands.ts +146 -40
- package/src/session-tool-call-settlement.ts +34 -7
- package/src/user-resource-authority.ts +56 -0
- package/dist/chunk-744DFC65.js.map +0 -1
- package/dist/chunk-UJ2EW3QI.js.map +0 -1
- package/dist/chunk-WW7AJ5IC.js.map +0 -1
- /package/dist/{chunk-IW6O6G7R.js.map → chunk-5NNCGFQY.js.map} +0 -0
- /package/dist/{chunk-G3732M3T.js.map → chunk-DZCYW2WT.js.map} +0 -0
- /package/dist/{chunk-CDMMSUWJ.js.map → chunk-S3TDDCS2.js.map} +0 -0
- /package/dist/{chunk-Q5YUGQVK.js.map → chunk-SZAWDXQC.js.map} +0 -0
- /package/dist/{chunk-UGDVSQ6U.js.map → chunk-U4WPPEBH.js.map} +0 -0
- /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.';
|