@opengeni/db 4.4.1 → 4.5.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/capability-reconciliation.js +2 -2
- package/dist/{chunk-T7GDRZOH.js → chunk-4LVV4R4F.js} +2 -2
- package/dist/{chunk-NQWVBQFK.js → chunk-575FUJE2.js} +3 -3
- package/dist/{chunk-K2XOMTAG.js → chunk-7LFHUC35.js} +2 -2
- package/dist/{chunk-JC43DLHB.js → chunk-7P67EF5K.js} +5 -5
- package/dist/{chunk-XWANFAN4.js → chunk-BH2HBICR.js} +4 -4
- package/dist/{chunk-PB73JQOI.js → chunk-C3FI3DJ5.js} +2 -2
- package/dist/{chunk-LLQLCFCT.js → chunk-GSZZDYPV.js} +2 -2
- package/dist/{chunk-B4DWUU4Y.js → chunk-GYAQYECK.js} +2 -2
- package/dist/{chunk-GYHXV2LR.js → chunk-K2YN562I.js} +2 -2
- package/dist/{chunk-6UJX2OXO.js → chunk-KMBU4KDY.js} +25 -1
- package/dist/chunk-KMBU4KDY.js.map +1 -0
- package/dist/{chunk-JN2DIKGW.js → chunk-M6TNKUGE.js} +3 -1
- package/dist/chunk-M6TNKUGE.js.map +1 -0
- package/dist/{chunk-SSCUP23X.js → chunk-MSAWMGWJ.js} +6 -6
- package/dist/{chunk-T5RZ3HWS.js → chunk-OFQDECMZ.js} +4 -4
- package/dist/{chunk-7UA4WUGK.js → chunk-RRZO5XRA.js} +2671 -2335
- package/dist/{chunk-7UA4WUGK.js.map → chunk-RRZO5XRA.js.map} +1 -1
- package/dist/{chunk-72JNABPO.js → chunk-TIF52FMJ.js} +3 -3
- package/dist/{chunk-67VNEM5N.js → chunk-TLCTS7CZ.js} +4 -4
- package/dist/{chunk-VFQI3CDL.js → chunk-VXCIFQX7.js} +2 -2
- package/dist/{chunk-5H6FHFHD.js → chunk-XX5M3TJJ.js} +2 -2
- package/dist/{chunk-LUO43IZE.js → chunk-YOFYG5ZI.js} +2 -2
- package/dist/connect-attempts.js +3 -3
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +21 -0
- package/dist/index.js +25 -19
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/mcp-operations.js +2 -2
- package/dist/migrate.js +19 -19
- package/dist/organization-integration-policy.js +3 -3
- package/dist/provision-roles.js +1 -1
- package/dist/retained-provider-commands.js +6 -6
- package/dist/runtime-posture.d.ts +2 -2
- package/dist/schema.d.ts +93 -0
- package/dist/schema.js +3 -1
- package/dist/session-background-commands.js +5 -5
- package/dist/session-command-output.js +5 -5
- package/dist/session-event-slices.js +3 -3
- package/dist/session-history-tool-identities.d.ts +11 -0
- package/dist/session-mcp-credential-rotation.js +6 -6
- package/dist/session-message-search.d.ts +21 -0
- package/dist/session-tenancy.js +6 -6
- package/dist/{subscription-core-codex-SUO2TISD.js → subscription-core-codex-L7NPFWAH.js} +6 -6
- package/dist/{subscription-core-codex-compat-SDHM4XG4.js → subscription-core-codex-compat-AK2UMLE3.js} +8 -8
- package/dist/subscription-usage-pool.d.ts +1 -1
- package/dist/video-generation.js +3 -3
- package/dist/workspace-artifacts.d.ts +13 -0
- package/dist/workspace-tool-defaults.js +5 -5
- package/drizzle/0907_subscription_connection_one_owner.sql +339 -209
- package/drizzle/0908_site_opens.sql +33 -0
- package/package.json +9 -9
- package/src/index.ts +304 -44
- package/src/runtime-posture.ts +2 -0
- package/src/schema.ts +24 -0
- package/src/session-history-tool-identities.ts +55 -0
- package/src/session-message-search.ts +188 -33
- package/src/subscription-core/administered-connections.ts +7 -5
- package/src/subscription-usage-pool.ts +7 -5
- package/src/workspace-artifacts.ts +45 -1
- package/dist/chunk-6UJX2OXO.js.map +0 -1
- package/dist/chunk-JN2DIKGW.js.map +0 -1
- /package/dist/{chunk-T7GDRZOH.js.map → chunk-4LVV4R4F.js.map} +0 -0
- /package/dist/{chunk-NQWVBQFK.js.map → chunk-575FUJE2.js.map} +0 -0
- /package/dist/{chunk-K2XOMTAG.js.map → chunk-7LFHUC35.js.map} +0 -0
- /package/dist/{chunk-JC43DLHB.js.map → chunk-7P67EF5K.js.map} +0 -0
- /package/dist/{chunk-XWANFAN4.js.map → chunk-BH2HBICR.js.map} +0 -0
- /package/dist/{chunk-PB73JQOI.js.map → chunk-C3FI3DJ5.js.map} +0 -0
- /package/dist/{chunk-LLQLCFCT.js.map → chunk-GSZZDYPV.js.map} +0 -0
- /package/dist/{chunk-B4DWUU4Y.js.map → chunk-GYAQYECK.js.map} +0 -0
- /package/dist/{chunk-GYHXV2LR.js.map → chunk-K2YN562I.js.map} +0 -0
- /package/dist/{chunk-SSCUP23X.js.map → chunk-MSAWMGWJ.js.map} +0 -0
- /package/dist/{chunk-T5RZ3HWS.js.map → chunk-OFQDECMZ.js.map} +0 -0
- /package/dist/{chunk-72JNABPO.js.map → chunk-TIF52FMJ.js.map} +0 -0
- /package/dist/{chunk-67VNEM5N.js.map → chunk-TLCTS7CZ.js.map} +0 -0
- /package/dist/{chunk-VFQI3CDL.js.map → chunk-VXCIFQX7.js.map} +0 -0
- /package/dist/{chunk-5H6FHFHD.js.map → chunk-XX5M3TJJ.js.map} +0 -0
- /package/dist/{chunk-LUO43IZE.js.map → chunk-YOFYG5ZI.js.map} +0 -0
- /package/dist/{subscription-core-codex-SUO2TISD.js.map → subscription-core-codex-L7NPFWAH.js.map} +0 -0
- /package/dist/{subscription-core-codex-compat-SDHM4XG4.js.map → subscription-core-codex-compat-AK2UMLE3.js.map} +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
-- deployment-mode:
|
|
2
|
-
--
|
|
3
|
-
-- online-safety-exception: unbatched-data: every
|
|
4
|
-
-- online-safety-exception: constraint-validation: the validated table holds a handful of subscription connection rows per organization, so validating under the same lock finishes instantly
|
|
1
|
+
-- deployment-mode: maintenance
|
|
2
|
+
-- maintenance-justification: The fold holds ACCESS EXCLUSIVE on the four subscription tables until commit, measured at 6.1s for 30k connections with 100k workspaces on PostgreSQL 18, and serving clients would wait that long behind it; production counts are not yet known, so the release parks clients for it. An expand/contract split would need a binary that reads both the pool-row model and the one-owner model, which this release does not ship; shrinking this window is a follow-up.
|
|
3
|
+
-- online-safety-exception: maintenance-unbatched-data: every UPDATE, DELETE and INSERT here is one set-based statement over the subscription connection, reach, policy, auto-assignment and settings rows, never a per-connection loop; the whole migration measured 0.07s at 300 connections, 0.44s at 3k, 1.2s at 9k and 5.2s at 30k connections with 100k workspaces on PostgreSQL 18, growing linearly
|
|
5
4
|
-- contract-step: nothing in this release reads or writes subscription_connection_assignment_policies; a later contract migration drops it. A previous binary that straddles the commit reads no policy rows, so it classifies every shared connection by its manager and the stripped settings (automatic source), which is exactly the reach written here.
|
|
6
5
|
--
|
|
7
6
|
-- Migration 0907: every subscription connection has one owner and serves
|
|
@@ -40,13 +39,31 @@
|
|
|
40
39
|
-- owner window (docs/force-rls-migration-backfills.md); workspaces and
|
|
41
40
|
-- memberships are read through the organization-lifecycle marker branch.
|
|
42
41
|
-- No advisory fence is taken.
|
|
42
|
+
--
|
|
43
|
+
-- Locks: this is a maintenance migration, so the production release parks
|
|
44
|
+
-- database clients before it runs. Each LOCK statement still waits at most 5s
|
|
45
|
+
-- in total, by statement_timeout (not 5s per table), for anything left
|
|
46
|
+
-- running. First SHARE ROW EXCLUSIVE on the five tables: it waits only for
|
|
47
|
+
-- writers and never blocks readers. Then ACCESS EXCLUSIVE on the four whose
|
|
48
|
+
-- row security the owner window relaxes (ALTER ... NO FORCE needs it anyway):
|
|
49
|
+
-- with writers already excluded it waits only for reads in progress, and
|
|
50
|
+
-- readers that arrive meanwhile queue behind it for at most those 5s. Once
|
|
51
|
+
-- granted, the locks are held until commit, for as long as the set-based fold
|
|
52
|
+
-- below takes (6.1s measured at 30k connections and 100k workspaces), and any
|
|
53
|
+
-- reader or writer still connected waits for that too. SHARE ROW EXCLUSIVE
|
|
54
|
+
-- then ACCESS EXCLUSIVE can exclude writers for two acquisitions (up to 5s
|
|
55
|
+
-- each) plus that hold. The workspace-owner CHECK added below is validated by
|
|
56
|
+
-- one scan under the same lock, under 40ms at 30k connections.
|
|
43
57
|
SET LOCAL lock_timeout = '5s';
|
|
44
|
-
SET LOCAL statement_timeout = '
|
|
45
|
-
|
|
58
|
+
SET LOCAL statement_timeout = '5s';
|
|
46
59
|
LOCK TABLE subscription_connections, subscription_connection_workspaces,
|
|
47
60
|
subscription_connection_assignment_policies, subscription_settings,
|
|
48
61
|
opengeni_private.subscription_core_auto_assignments
|
|
49
62
|
IN SHARE ROW EXCLUSIVE MODE;
|
|
63
|
+
LOCK TABLE subscription_connections, subscription_connection_workspaces,
|
|
64
|
+
subscription_connection_assignment_policies, subscription_settings
|
|
65
|
+
IN ACCESS EXCLUSIVE MODE;
|
|
66
|
+
SET LOCAL statement_timeout = '5min';
|
|
50
67
|
|
|
51
68
|
ALTER TABLE subscription_connections NO FORCE ROW LEVEL SECURITY;
|
|
52
69
|
ALTER TABLE subscription_connection_workspaces NO FORCE ROW LEVEL SECURITY;
|
|
@@ -59,226 +76,301 @@ ALTER TABLE subscription_connections DISABLE TRIGGER subscription_connections_sc
|
|
|
59
76
|
SELECT pg_catalog.set_config('opengeni.organization_tenancy_lifecycle',
|
|
60
77
|
'organization_membership_lifecycle', true);
|
|
61
78
|
|
|
79
|
+
-- Every step below is one set-based statement over the whole chain, never a
|
|
80
|
+
-- per-connection or per-workspace loop, so its cost grows with the rows it
|
|
81
|
+
-- reads rather than with connections times workspaces.
|
|
82
|
+
--
|
|
83
|
+
-- The shared connections this folds, as they stood when the lock was taken.
|
|
84
|
+
CREATE TEMP TABLE subscription_one_owner_connection ON COMMIT DROP AS
|
|
85
|
+
SELECT connection.id, connection.account_id, connection.provider, connection.scope_kind,
|
|
86
|
+
connection.allow_personal_workspaces, connection.managed_by_workspace_id
|
|
87
|
+
FROM subscription_connections connection
|
|
88
|
+
WHERE connection.ownership = 'shared' AND connection.disconnected_at IS NULL
|
|
89
|
+
AND connection.scope_kind IN ('organization', 'workspaces');
|
|
90
|
+
CREATE UNIQUE INDEX ON subscription_one_owner_connection (id);
|
|
91
|
+
CREATE INDEX ON subscription_one_owner_connection (account_id);
|
|
92
|
+
ANALYZE subscription_one_owner_connection;
|
|
93
|
+
|
|
94
|
+
-- Every workspace of those organizations, and whether it is someone's Personal one.
|
|
95
|
+
CREATE TEMP TABLE subscription_one_owner_workspace ON COMMIT DROP AS
|
|
96
|
+
SELECT workspace.account_id, workspace.id, personal.workspace_id IS NOT NULL AS personal
|
|
97
|
+
FROM workspaces workspace
|
|
98
|
+
LEFT JOIN (SELECT DISTINCT membership.account_id, membership.personal_workspace_id AS workspace_id
|
|
99
|
+
FROM organization_memberships membership
|
|
100
|
+
WHERE membership.personal_workspace_id IS NOT NULL) personal
|
|
101
|
+
ON personal.account_id = workspace.account_id AND personal.workspace_id = workspace.id
|
|
102
|
+
WHERE workspace.account_id IN (SELECT account_id FROM subscription_one_owner_connection);
|
|
103
|
+
CREATE UNIQUE INDEX ON subscription_one_owner_workspace (account_id, id);
|
|
104
|
+
ANALYZE subscription_one_owner_workspace;
|
|
105
|
+
|
|
106
|
+
-- The source each workspace used per provider: exactly the inferenceSource
|
|
107
|
+
-- subscription_effective_settings() reported (or the useOrganizationAccounts
|
|
108
|
+
-- it derived), computed in one join instead of one call per workspace. With
|
|
109
|
+
-- no organization settings row that function returns nothing: automatic.
|
|
110
|
+
CREATE TEMP TABLE subscription_one_owner_source ON COMMIT DROP AS
|
|
111
|
+
SELECT workspace.account_id, workspace.id AS workspace_id, provider.provider,
|
|
112
|
+
CASE WHEN org.account_id IS NULL THEN 'automatic' ELSE coalesce(
|
|
113
|
+
CASE
|
|
114
|
+
WHEN entry.workspace_setting ? 'inferenceSource' THEN entry.workspace_setting->>'inferenceSource'
|
|
115
|
+
WHEN entry.workspace_setting ? 'useOrganizationAccounts'
|
|
116
|
+
THEN CASE WHEN entry.workspace_setting->>'useOrganizationAccounts' = 'false'
|
|
117
|
+
THEN 'workspace' ELSE 'automatic' END
|
|
118
|
+
WHEN entry.organization_setting ? 'inferenceSource'
|
|
119
|
+
THEN entry.organization_setting->>'inferenceSource'
|
|
120
|
+
WHEN entry.organization_setting ? 'useOrganizationAccounts'
|
|
121
|
+
THEN CASE WHEN entry.organization_setting->>'useOrganizationAccounts' = 'false'
|
|
122
|
+
THEN 'workspace' ELSE 'automatic' END
|
|
123
|
+
ELSE 'automatic'
|
|
124
|
+
END, 'automatic') END AS inference_source
|
|
125
|
+
FROM subscription_one_owner_workspace workspace
|
|
126
|
+
JOIN (SELECT DISTINCT account_id, provider FROM subscription_one_owner_connection) provider
|
|
127
|
+
ON provider.account_id = workspace.account_id
|
|
128
|
+
LEFT JOIN subscription_settings org
|
|
129
|
+
ON org.account_id = workspace.account_id AND org.workspace_id IS NULL
|
|
130
|
+
LEFT JOIN subscription_settings ws
|
|
131
|
+
ON ws.account_id = workspace.account_id AND ws.workspace_id = workspace.id
|
|
132
|
+
CROSS JOIN LATERAL (SELECT
|
|
133
|
+
coalesce(org.providers->provider.provider, '{}'::jsonb) AS organization_setting,
|
|
134
|
+
CASE WHEN ws.providers ? provider.provider
|
|
135
|
+
AND NOT ('providers' = ANY(coalesce(org.locked_settings, '{}')))
|
|
136
|
+
THEN ws.providers->provider.provider ELSE '{}'::jsonb END AS workspace_setting) entry;
|
|
137
|
+
CREATE UNIQUE INDEX ON subscription_one_owner_source (account_id, workspace_id, provider);
|
|
138
|
+
ANALYZE subscription_one_owner_source;
|
|
139
|
+
|
|
140
|
+
-- The pool rows per connection and workspace.
|
|
141
|
+
CREATE TEMP TABLE subscription_one_owner_policy ON COMMIT DROP AS
|
|
142
|
+
SELECT policy.connection_id, policy.workspace_id,
|
|
143
|
+
bool_or(policy.inference_pool = 'workspace') AS workspace_pool,
|
|
144
|
+
coalesce(array_agg(DISTINCT policy.inference_pool) FILTER (WHERE policy.allocator_enabled),
|
|
145
|
+
'{}') AS enabled_pools
|
|
146
|
+
FROM subscription_connection_assignment_policies policy
|
|
147
|
+
GROUP BY policy.connection_id, policy.workspace_id;
|
|
148
|
+
CREATE UNIQUE INDEX ON subscription_one_owner_policy (connection_id, workspace_id);
|
|
149
|
+
ANALYZE subscription_one_owner_policy;
|
|
150
|
+
|
|
151
|
+
-- 1. Where each connection is in scope, and whether it is used there.
|
|
62
152
|
CREATE TEMP TABLE subscription_one_owner_use ON COMMIT DROP AS
|
|
63
|
-
WITH
|
|
64
|
-
SELECT connection.id,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
WHERE connection.ownership = 'shared' AND connection.disconnected_at IS NULL
|
|
68
|
-
AND connection.scope_kind IN ('organization', 'workspaces')
|
|
69
|
-
), workspace AS (
|
|
70
|
-
SELECT workspace.account_id, workspace.id,
|
|
71
|
-
EXISTS (SELECT 1 FROM organization_memberships membership
|
|
72
|
-
WHERE membership.account_id = workspace.account_id
|
|
73
|
-
AND membership.personal_workspace_id = workspace.id) AS personal
|
|
74
|
-
FROM workspaces workspace
|
|
75
|
-
WHERE workspace.account_id IN (SELECT account_id FROM connection)
|
|
76
|
-
), source AS (
|
|
77
|
-
SELECT workspace.account_id, workspace.id AS workspace_id, provider.provider,
|
|
78
|
-
coalesce(effective->'values'->'providers'->provider.provider->>'inferenceSource',
|
|
79
|
-
CASE WHEN effective->'values'->'providers'->provider.provider->>'useOrganizationAccounts' = 'false'
|
|
80
|
-
THEN 'workspace' ELSE 'automatic' END) AS inference_source
|
|
81
|
-
FROM workspace
|
|
82
|
-
CROSS JOIN LATERAL (SELECT DISTINCT connection.provider FROM connection
|
|
83
|
-
WHERE connection.account_id = workspace.account_id) provider
|
|
84
|
-
CROSS JOIN LATERAL (SELECT subscription_effective_settings(workspace.account_id, workspace.id)
|
|
85
|
-
AS effective) settings
|
|
86
|
-
), in_scope AS (
|
|
87
|
-
SELECT connection.id AS connection_id, workspace.id AS workspace_id, workspace.personal,
|
|
88
|
-
EXISTS (SELECT 1 FROM subscription_connection_workspaces assignment
|
|
89
|
-
WHERE assignment.account_id = connection.account_id
|
|
90
|
-
AND assignment.connection_id = connection.id
|
|
91
|
-
AND assignment.workspace_id = workspace.id) AS assigned
|
|
92
|
-
FROM connection JOIN workspace ON workspace.account_id = connection.account_id
|
|
153
|
+
WITH in_scope AS (
|
|
154
|
+
SELECT connection.id AS connection_id, workspace.id AS workspace_id, workspace.personal
|
|
155
|
+
FROM subscription_one_owner_connection connection
|
|
156
|
+
JOIN subscription_one_owner_workspace workspace ON workspace.account_id = connection.account_id
|
|
93
157
|
WHERE connection.scope_kind = 'organization'
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
158
|
+
UNION
|
|
159
|
+
SELECT connection.id, workspace.id, workspace.personal
|
|
160
|
+
FROM subscription_one_owner_connection connection
|
|
161
|
+
JOIN subscription_connection_workspaces assignment
|
|
162
|
+
ON assignment.account_id = connection.account_id AND assignment.connection_id = connection.id
|
|
163
|
+
JOIN subscription_one_owner_workspace workspace
|
|
164
|
+
ON workspace.account_id = connection.account_id AND workspace.id = assignment.workspace_id
|
|
165
|
+
WHERE connection.scope_kind = 'workspaces'
|
|
166
|
+
UNION
|
|
167
|
+
SELECT connection.id, workspace.id, workspace.personal
|
|
168
|
+
FROM subscription_one_owner_connection connection
|
|
169
|
+
JOIN subscription_one_owner_workspace workspace
|
|
170
|
+
ON workspace.account_id = connection.account_id AND workspace.personal
|
|
171
|
+
WHERE connection.scope_kind = 'workspaces' AND connection.allow_personal_workspaces
|
|
99
172
|
)
|
|
100
|
-
SELECT in_scope.connection_id, in_scope.workspace_id, in_scope.personal,
|
|
101
|
-
source.inference_source,
|
|
173
|
+
SELECT in_scope.connection_id, in_scope.workspace_id, in_scope.personal,
|
|
174
|
+
assignment.connection_id IS NOT NULL AS assigned, source.inference_source,
|
|
102
175
|
CASE
|
|
103
|
-
WHEN
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
THEN EXISTS (SELECT 1 FROM subscription_connection_assignment_policies policy
|
|
107
|
-
WHERE policy.connection_id = in_scope.connection_id
|
|
108
|
-
AND policy.workspace_id = in_scope.workspace_id
|
|
109
|
-
AND policy.allocator_enabled
|
|
110
|
-
AND (source.inference_source = 'automatic'
|
|
111
|
-
OR policy.inference_pool = source.inference_source))
|
|
176
|
+
WHEN policy.connection_id IS NOT NULL
|
|
177
|
+
THEN coalesce((source.inference_source = 'automatic' AND cardinality(policy.enabled_pools) > 0)
|
|
178
|
+
OR source.inference_source = ANY(policy.enabled_pools), false)
|
|
112
179
|
WHEN source.inference_source = 'workspace'
|
|
113
180
|
THEN connection.managed_by_workspace_id IS NOT DISTINCT FROM in_scope.workspace_id
|
|
114
181
|
WHEN source.inference_source = 'organization'
|
|
115
182
|
THEN connection.managed_by_workspace_id IS DISTINCT FROM in_scope.workspace_id
|
|
116
183
|
ELSE true
|
|
117
184
|
END AS used,
|
|
118
|
-
(
|
|
119
|
-
|
|
120
|
-
AND policy.workspace_id = in_scope.workspace_id
|
|
121
|
-
AND policy.inference_pool = 'workspace')
|
|
122
|
-
OR (in_scope.assigned
|
|
185
|
+
coalesce(policy.workspace_pool, false)
|
|
186
|
+
OR (assignment.connection_id IS NOT NULL
|
|
123
187
|
AND connection.managed_by_workspace_id IS NOT DISTINCT FROM in_scope.workspace_id
|
|
124
|
-
AND
|
|
125
|
-
WHERE policy.connection_id = in_scope.connection_id
|
|
126
|
-
AND policy.workspace_id = in_scope.workspace_id))) AS local
|
|
188
|
+
AND policy.connection_id IS NULL) AS local
|
|
127
189
|
FROM in_scope
|
|
128
|
-
JOIN connection ON connection.id = in_scope.connection_id
|
|
129
|
-
JOIN source ON source.account_id = connection.account_id
|
|
130
|
-
AND source.workspace_id = in_scope.workspace_id AND source.provider = connection.provider
|
|
190
|
+
JOIN subscription_one_owner_connection connection ON connection.id = in_scope.connection_id
|
|
191
|
+
JOIN subscription_one_owner_source source ON source.account_id = connection.account_id
|
|
192
|
+
AND source.workspace_id = in_scope.workspace_id AND source.provider = connection.provider
|
|
193
|
+
LEFT JOIN subscription_connection_workspaces assignment
|
|
194
|
+
ON assignment.account_id = connection.account_id AND assignment.connection_id = connection.id
|
|
195
|
+
AND assignment.workspace_id = in_scope.workspace_id
|
|
196
|
+
LEFT JOIN subscription_one_owner_policy policy
|
|
197
|
+
ON policy.connection_id = in_scope.connection_id AND policy.workspace_id = in_scope.workspace_id;
|
|
198
|
+
CREATE UNIQUE INDEX ON subscription_one_owner_use (connection_id, workspace_id);
|
|
199
|
+
ANALYZE subscription_one_owner_use;
|
|
131
200
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
201
|
+
-- 2-4. Per connection: where it reaches, its owner, its model list and which
|
|
202
|
+
-- rewrite applies. A connection in scope nowhere keeps the defaults of an
|
|
203
|
+
-- empty aggregate (used nowhere, used everywhere it is in scope).
|
|
204
|
+
CREATE TEMP TABLE subscription_one_owner_plan ON COMMIT DROP AS
|
|
205
|
+
WITH aggregate AS (
|
|
206
|
+
SELECT use.connection_id,
|
|
207
|
+
array_agg(use.workspace_id ORDER BY use.workspace_id) FILTER (WHERE use.used) AS used_ids,
|
|
208
|
+
array_agg(use.workspace_id ORDER BY use.workspace_id) FILTER (WHERE use.assigned) AS assigned_ids,
|
|
209
|
+
array_agg(use.workspace_id ORDER BY use.workspace_id) FILTER (WHERE use.local) AS local_ids,
|
|
210
|
+
bool_and(use.used) FILTER (WHERE use.personal) AS personal_used,
|
|
211
|
+
bool_or(use.personal) AS personal_any,
|
|
212
|
+
bool_and(use.used) AS everywhere
|
|
213
|
+
FROM subscription_one_owner_use use
|
|
214
|
+
GROUP BY use.connection_id
|
|
215
|
+
), models AS (
|
|
216
|
+
-- A model list the admitting policies narrowed in every workspace that
|
|
217
|
+
-- used the connection becomes the connection's own (their union, so no
|
|
218
|
+
-- workspace loses a model it had). Policies never stored exclusions.
|
|
219
|
+
SELECT use.connection_id,
|
|
220
|
+
bool_or(policy.connection_id IS NULL OR policy.allowed_model_ids IS NULL) AS unrestricted,
|
|
221
|
+
coalesce(array_agg(DISTINCT model.id ORDER BY model.id)
|
|
222
|
+
FILTER (WHERE model.id IS NOT NULL), '{}') AS policy_models
|
|
223
|
+
FROM subscription_one_owner_use use
|
|
224
|
+
LEFT JOIN subscription_connection_assignment_policies policy
|
|
225
|
+
ON policy.connection_id = use.connection_id AND policy.workspace_id = use.workspace_id
|
|
226
|
+
AND policy.allocator_enabled
|
|
227
|
+
AND (use.inference_source = 'automatic' OR policy.inference_pool = use.inference_source)
|
|
228
|
+
LEFT JOIN LATERAL unnest(policy.allowed_model_ids) AS model(id) ON true
|
|
229
|
+
WHERE use.used
|
|
230
|
+
GROUP BY use.connection_id
|
|
231
|
+
), shaped AS (
|
|
232
|
+
SELECT connection.*,
|
|
233
|
+
coalesce(aggregate.used_ids, '{}') AS used_ids,
|
|
234
|
+
coalesce(aggregate.assigned_ids, '{}') AS assigned_ids,
|
|
235
|
+
coalesce(aggregate.local_ids, '{}') AS local_ids,
|
|
236
|
+
coalesce(aggregate.personal_used, true) AS personal_used,
|
|
237
|
+
coalesce(aggregate.personal_any, false) AS personal_any,
|
|
238
|
+
coalesce(aggregate.everywhere, true) AS everywhere,
|
|
239
|
+
coalesce(models.unrestricted, true) AS models_unrestricted,
|
|
240
|
+
coalesce(models.policy_models, '{}') AS policy_models
|
|
241
|
+
FROM subscription_one_owner_connection connection
|
|
242
|
+
LEFT JOIN aggregate ON aggregate.connection_id = connection.id
|
|
243
|
+
LEFT JOIN models ON models.connection_id = connection.id
|
|
244
|
+
), reached AS (
|
|
245
|
+
-- 2. What it reaches: where it was used, or, used nowhere, where it is
|
|
246
|
+
-- listed (switched off below).
|
|
247
|
+
SELECT shaped.*,
|
|
248
|
+
CASE WHEN cardinality(shaped.used_ids) > 0 THEN shaped.used_ids
|
|
249
|
+
ELSE shaped.assigned_ids END AS reach_ids
|
|
250
|
+
FROM shaped
|
|
251
|
+
), owned AS (
|
|
252
|
+
-- 3. Its owner.
|
|
253
|
+
SELECT reached.*,
|
|
254
|
+
CASE
|
|
255
|
+
WHEN reached.managed_by_workspace_id IS NOT NULL
|
|
256
|
+
AND reached.reach_ids <@ ARRAY[reached.managed_by_workspace_id]
|
|
257
|
+
THEN reached.managed_by_workspace_id
|
|
258
|
+
WHEN reached.managed_by_workspace_id IS NULL AND reached.scope_kind = 'workspaces'
|
|
259
|
+
AND cardinality(reached.local_ids) = 1 AND reached.reach_ids = reached.local_ids
|
|
260
|
+
AND NOT (reached.allow_personal_workspaces AND reached.personal_any)
|
|
261
|
+
THEN reached.local_ids[1]
|
|
262
|
+
END AS owner_workspace
|
|
263
|
+
FROM reached
|
|
264
|
+
)
|
|
265
|
+
SELECT owned.*,
|
|
266
|
+
cardinality(owned.used_ids) > 0 AS used_somewhere,
|
|
267
|
+
CASE
|
|
268
|
+
WHEN owned.owner_workspace IS NOT NULL THEN 'owner'
|
|
269
|
+
WHEN owned.scope_kind = 'organization' THEN CASE
|
|
270
|
+
WHEN owned.everywhere THEN 'unchanged'
|
|
271
|
+
WHEN cardinality(owned.used_ids) = 0 THEN 'switched_off'
|
|
272
|
+
ELSE 'listed' END
|
|
273
|
+
WHEN owned.managed_by_workspace_id IS NULL AND owned.everywhere THEN 'unchanged'
|
|
274
|
+
ELSE 'chosen'
|
|
275
|
+
END AS rewrite
|
|
276
|
+
FROM owned;
|
|
277
|
+
CREATE UNIQUE INDEX ON subscription_one_owner_plan (id);
|
|
167
278
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
SELECT
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
LEFT JOIN subscription_connection_assignment_policies policy
|
|
177
|
-
ON policy.connection_id = use.connection_id AND policy.workspace_id = use.workspace_id
|
|
178
|
-
AND policy.allocator_enabled
|
|
179
|
-
AND (use.inference_source = 'automatic' OR policy.inference_pool = use.inference_source)
|
|
180
|
-
LEFT JOIN LATERAL unnest(policy.allowed_model_ids) AS model(id) ON true
|
|
181
|
-
WHERE use.connection_id = target.id AND use.used;
|
|
182
|
-
IF NOT models_unrestricted THEN
|
|
183
|
-
UPDATE subscription_connections SET allowed_model_ids = CASE
|
|
184
|
-
WHEN allowed_model_ids IS NULL THEN policy_models
|
|
185
|
-
ELSE ARRAY(SELECT unnest(allowed_model_ids) INTERSECT SELECT unnest(policy_models)
|
|
186
|
-
ORDER BY 1) END,
|
|
187
|
-
access_version = access_version + 1, updated_at = clock_timestamp()
|
|
188
|
-
WHERE id = target.id;
|
|
189
|
-
END IF;
|
|
279
|
+
-- 4. The narrowed model lists.
|
|
280
|
+
UPDATE subscription_connections connection SET allowed_model_ids = CASE
|
|
281
|
+
WHEN connection.allowed_model_ids IS NULL THEN plan.policy_models
|
|
282
|
+
ELSE ARRAY(SELECT unnest(connection.allowed_model_ids) INTERSECT SELECT unnest(plan.policy_models)
|
|
283
|
+
ORDER BY 1) END,
|
|
284
|
+
access_version = connection.access_version + 1, updated_at = clock_timestamp()
|
|
285
|
+
FROM subscription_one_owner_plan plan
|
|
286
|
+
WHERE connection.id = plan.id AND NOT plan.models_unrestricted;
|
|
190
287
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
288
|
+
-- One workspace's own: it reaches only that workspace.
|
|
289
|
+
UPDATE subscription_connections connection SET managed_by_workspace_id = plan.owner_workspace,
|
|
290
|
+
scope_kind = 'workspaces', allow_personal_workspaces = false,
|
|
291
|
+
allocator_enabled = connection.allocator_enabled AND plan.used_somewhere,
|
|
292
|
+
access_version = connection.access_version + 1, updated_at = clock_timestamp()
|
|
293
|
+
FROM subscription_one_owner_plan plan
|
|
294
|
+
WHERE connection.id = plan.id AND plan.rewrite = 'owner';
|
|
295
|
+
DELETE FROM subscription_connection_workspaces assignment
|
|
296
|
+
USING subscription_one_owner_plan plan
|
|
297
|
+
WHERE plan.rewrite = 'owner' AND assignment.connection_id = plan.id
|
|
298
|
+
AND assignment.workspace_id <> ALL(plan.reach_ids);
|
|
299
|
+
INSERT INTO subscription_connection_workspaces (account_id, connection_id, workspace_id)
|
|
300
|
+
SELECT plan.account_id, plan.id, plan.owner_workspace
|
|
301
|
+
FROM subscription_one_owner_plan plan
|
|
302
|
+
WHERE plan.rewrite = 'owner' AND plan.used_somewhere
|
|
303
|
+
ON CONFLICT DO NOTHING;
|
|
304
|
+
DELETE FROM opengeni_private.subscription_core_auto_assignments auto
|
|
305
|
+
USING subscription_one_owner_plan plan
|
|
306
|
+
WHERE plan.rewrite = 'owner' AND auto.connection_id = plan.id;
|
|
198
307
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
ELSIF target.managed_by_workspace_id IS NULL AND target.scope_kind = 'workspaces'
|
|
205
|
-
AND cardinality(local_ids) = 1 AND reach_ids = local_ids
|
|
206
|
-
AND NOT (target.allow_personal_workspaces AND personal_any) THEN
|
|
207
|
-
owner_workspace := local_ids[1];
|
|
208
|
-
END IF;
|
|
308
|
+
-- Organization-wide and used nowhere: keep reaching everyone, switched off.
|
|
309
|
+
UPDATE subscription_connections connection SET allocator_enabled = false,
|
|
310
|
+
access_version = connection.access_version + 1, updated_at = clock_timestamp()
|
|
311
|
+
FROM subscription_one_owner_plan plan
|
|
312
|
+
WHERE connection.id = plan.id AND plan.rewrite = 'switched_off' AND connection.allocator_enabled;
|
|
209
313
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
IF target.allow_personal_workspaces AND NOT personal_used THEN
|
|
271
|
-
INSERT INTO subscription_connection_workspaces (account_id, connection_id, workspace_id)
|
|
272
|
-
SELECT target.account_id, target.id, use.workspace_id
|
|
273
|
-
FROM subscription_one_owner_use use
|
|
274
|
-
WHERE use.connection_id = target.id AND use.used AND use.personal
|
|
275
|
-
ON CONFLICT DO NOTHING;
|
|
276
|
-
END IF;
|
|
277
|
-
END IF;
|
|
278
|
-
END IF;
|
|
279
|
-
END LOOP;
|
|
280
|
-
END
|
|
281
|
-
$one_owner$;
|
|
314
|
+
-- Organization-wide but not used everywhere: every workspace that used it,
|
|
315
|
+
-- still reaching shared workspaces created later (and Personal ones when
|
|
316
|
+
-- every Personal one used it).
|
|
317
|
+
UPDATE subscription_connections connection SET managed_by_workspace_id = NULL,
|
|
318
|
+
scope_kind = 'workspaces', allow_personal_workspaces = plan.personal_used,
|
|
319
|
+
access_version = connection.access_version + 1, updated_at = clock_timestamp()
|
|
320
|
+
FROM subscription_one_owner_plan plan
|
|
321
|
+
WHERE connection.id = plan.id AND plan.rewrite = 'listed';
|
|
322
|
+
DELETE FROM subscription_connection_workspaces assignment
|
|
323
|
+
USING subscription_one_owner_plan plan
|
|
324
|
+
WHERE plan.rewrite = 'listed' AND assignment.connection_id = plan.id;
|
|
325
|
+
INSERT INTO subscription_connection_workspaces (account_id, connection_id, workspace_id)
|
|
326
|
+
SELECT plan.account_id, plan.id, use.workspace_id
|
|
327
|
+
FROM subscription_one_owner_plan plan
|
|
328
|
+
JOIN subscription_one_owner_use use ON use.connection_id = plan.id
|
|
329
|
+
WHERE plan.rewrite = 'listed' AND use.used AND NOT (use.personal AND plan.personal_used);
|
|
330
|
+
INSERT INTO opengeni_private.subscription_core_auto_assignments AS auto (
|
|
331
|
+
account_id, provider, connection_id, shared_workspaces, personal_workspaces,
|
|
332
|
+
allocator_enabled, allowed_model_ids
|
|
333
|
+
)
|
|
334
|
+
SELECT plan.account_id, plan.provider, plan.id, true, plan.personal_used,
|
|
335
|
+
true, connection.allowed_model_ids
|
|
336
|
+
FROM subscription_one_owner_plan plan
|
|
337
|
+
JOIN subscription_connections connection ON connection.id = plan.id
|
|
338
|
+
WHERE plan.rewrite = 'listed'
|
|
339
|
+
ON CONFLICT (connection_id) DO UPDATE SET shared_workspaces = true,
|
|
340
|
+
personal_workspaces = excluded.personal_workspaces;
|
|
341
|
+
|
|
342
|
+
-- Chosen workspaces, owned by the organization.
|
|
343
|
+
UPDATE subscription_connections connection SET managed_by_workspace_id = NULL,
|
|
344
|
+
allow_personal_workspaces = connection.allow_personal_workspaces
|
|
345
|
+
AND (NOT plan.used_somewhere OR plan.personal_used),
|
|
346
|
+
allocator_enabled = connection.allocator_enabled AND plan.used_somewhere,
|
|
347
|
+
access_version = connection.access_version + 1, updated_at = clock_timestamp()
|
|
348
|
+
FROM subscription_one_owner_plan plan
|
|
349
|
+
WHERE connection.id = plan.id AND plan.rewrite = 'chosen';
|
|
350
|
+
DELETE FROM subscription_connection_workspaces assignment
|
|
351
|
+
USING subscription_one_owner_plan plan
|
|
352
|
+
WHERE plan.rewrite = 'chosen' AND plan.used_somewhere AND assignment.connection_id = plan.id
|
|
353
|
+
AND assignment.workspace_id <> ALL(plan.used_ids);
|
|
354
|
+
INSERT INTO subscription_connection_workspaces (account_id, connection_id, workspace_id)
|
|
355
|
+
SELECT plan.account_id, plan.id, use.workspace_id
|
|
356
|
+
FROM subscription_one_owner_plan plan
|
|
357
|
+
JOIN subscription_one_owner_use use ON use.connection_id = plan.id
|
|
358
|
+
WHERE plan.rewrite = 'chosen' AND plan.used_somewhere
|
|
359
|
+
AND plan.allow_personal_workspaces AND NOT plan.personal_used
|
|
360
|
+
AND use.used AND use.personal
|
|
361
|
+
ON CONFLICT DO NOTHING;
|
|
362
|
+
|
|
363
|
+
-- A disconnected connection serves nowhere and is folded nowhere above, but
|
|
364
|
+
-- it keeps its reach rows. One a workspace manages that still lists another
|
|
365
|
+
-- workspace becomes the organization's (as in 3), so the reach check below
|
|
366
|
+
-- holds instead of failing the migration.
|
|
367
|
+
UPDATE subscription_connections connection SET managed_by_workspace_id = NULL,
|
|
368
|
+
access_version = connection.access_version + 1, updated_at = clock_timestamp()
|
|
369
|
+
WHERE connection.disconnected_at IS NOT NULL AND connection.managed_by_workspace_id IS NOT NULL
|
|
370
|
+
AND EXISTS (SELECT 1 FROM subscription_connection_workspaces assignment
|
|
371
|
+
WHERE assignment.account_id = connection.account_id
|
|
372
|
+
AND assignment.connection_id = connection.id
|
|
373
|
+
AND assignment.workspace_id <> connection.managed_by_workspace_id);
|
|
282
374
|
|
|
283
375
|
-- Only a connection serving chosen workspaces can be one workspace's own.
|
|
284
376
|
UPDATE subscription_connections SET managed_by_workspace_id = NULL,
|
|
@@ -293,6 +385,35 @@ DELETE FROM subscription_connection_assignment_policies;
|
|
|
293
385
|
|
|
294
386
|
-- 5. The per-workspace preference is gone; an entry left empty is no
|
|
295
387
|
-- override at all.
|
|
388
|
+
--
|
|
389
|
+
-- The 0724 lock guard would check every stripped workspace row one at a
|
|
390
|
+
-- time. It can object to exactly one thing here: a provider entry that keeps
|
|
391
|
+
-- other values after the strip, in a workspace whose organization locks
|
|
392
|
+
-- `providers` (an entry left empty is removed, which only clears). That is
|
|
393
|
+
-- checked once for the whole table with the guard's own error, and the guard
|
|
394
|
+
-- is off for this one statement only. Where the guard is not installed there
|
|
395
|
+
-- is nothing to check, exactly as a row-by-row strip would find.
|
|
396
|
+
DO $locked_providers$
|
|
397
|
+
BEGIN
|
|
398
|
+
IF NOT EXISTS (SELECT 1 FROM pg_trigger
|
|
399
|
+
WHERE tgrelid = 'subscription_settings'::regclass
|
|
400
|
+
AND tgname = 'subscription_settings_locked_overrides_guard') THEN
|
|
401
|
+
RETURN;
|
|
402
|
+
END IF;
|
|
403
|
+
IF EXISTS (SELECT 1 FROM subscription_settings settings
|
|
404
|
+
JOIN subscription_settings organization ON organization.account_id = settings.account_id
|
|
405
|
+
AND organization.workspace_id IS NULL
|
|
406
|
+
WHERE settings.workspace_id IS NOT NULL
|
|
407
|
+
AND 'providers' = ANY(organization.locked_settings)
|
|
408
|
+
AND EXISTS (SELECT 1 FROM jsonb_each(settings.providers) entry
|
|
409
|
+
WHERE (entry.value ? 'inferenceSource' OR entry.value ? 'useOrganizationAccounts')
|
|
410
|
+
AND entry.value - 'inferenceSource' - 'useOrganizationAccounts' <> '{}'::jsonb)) THEN
|
|
411
|
+
RAISE EXCEPTION 'subscription setting % is locked by the organization', 'providers'
|
|
412
|
+
USING ERRCODE = '42501', DETAIL = 'subscription_setting_locked:providers';
|
|
413
|
+
END IF;
|
|
414
|
+
ALTER TABLE subscription_settings DISABLE TRIGGER subscription_settings_locked_overrides_guard;
|
|
415
|
+
END
|
|
416
|
+
$locked_providers$;
|
|
296
417
|
UPDATE subscription_settings settings SET providers = coalesce((
|
|
297
418
|
SELECT jsonb_object_agg(entry.key, entry.value - 'inferenceSource' - 'useOrganizationAccounts')
|
|
298
419
|
FROM jsonb_each(settings.providers) entry
|
|
@@ -300,6 +421,15 @@ UPDATE subscription_settings settings SET providers = coalesce((
|
|
|
300
421
|
), '{}'::jsonb)
|
|
301
422
|
WHERE EXISTS (SELECT 1 FROM jsonb_each(settings.providers) entry
|
|
302
423
|
WHERE entry.value ? 'inferenceSource' OR entry.value ? 'useOrganizationAccounts');
|
|
424
|
+
DO $locked_providers_on$
|
|
425
|
+
BEGIN
|
|
426
|
+
IF EXISTS (SELECT 1 FROM pg_trigger
|
|
427
|
+
WHERE tgrelid = 'subscription_settings'::regclass
|
|
428
|
+
AND tgname = 'subscription_settings_locked_overrides_guard') THEN
|
|
429
|
+
ALTER TABLE subscription_settings ENABLE TRIGGER subscription_settings_locked_overrides_guard;
|
|
430
|
+
END IF;
|
|
431
|
+
END
|
|
432
|
+
$locked_providers_on$;
|
|
303
433
|
|
|
304
434
|
-- A workspace's own connection reaches only that workspace.
|
|
305
435
|
ALTER TABLE subscription_connections
|