@opengeni/db 0.2.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/chunk-57MLICFR.js +121 -0
- package/dist/chunk-57MLICFR.js.map +1 -0
- package/dist/chunk-OGCE6O2X.js +52 -0
- package/dist/chunk-OGCE6O2X.js.map +1 -0
- package/dist/chunk-PSX56ZTL.js +1093 -0
- package/dist/chunk-PSX56ZTL.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5165 -0
- package/dist/index.js.map +1 -0
- package/dist/migrate.d.ts +40 -0
- package/dist/migrate.js +10 -0
- package/dist/migrate.js.map +1 -0
- package/dist/provision-roles.d.ts +2063 -0
- package/dist/provision-roles.js +8 -0
- package/dist/provision-roles.js.map +1 -0
- package/dist/schema-CaeZQAJQ.d.ts +9705 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.js +110 -0
- package/dist/schema.js.map +1 -0
- package/drizzle/0000_initial.sql +179 -0
- package/drizzle/0001_workspace_auth_billing.sql +590 -0
- package/drizzle/0002_packs_and_social.sql +99 -0
- package/drizzle/0003_capability_catalog.sql +73 -0
- package/drizzle/0004_workspace_environments.sql +65 -0
- package/drizzle/0005_session_goals.sql +45 -0
- package/drizzle/0006_workspace_packs.sql +31 -0
- package/drizzle/0007_session_history_items.sql +66 -0
- package/drizzle/0008_session_first_party_mcp_permissions.sql +5 -0
- package/drizzle/0009_goal_sessions_first_party_goals_manage.sql +34 -0
- package/drizzle/0010_session_parent_linkage.sql +30 -0
- package/drizzle/0011_context_compaction.sql +33 -0
- package/drizzle/0012_compaction_summary_fractional_position.sql +19 -0
- package/drizzle/0013_session_compact_requested.sql +16 -0
- package/drizzle/0014_repair_orphaned_function_call_results.sql +125 -0
- package/drizzle/0015_workspace_agent_instructions.sql +17 -0
- package/drizzle/0016_session_create_idempotency.sql +27 -0
- package/drizzle/0017_sandbox_leases.sql +313 -0
- package/drizzle/0018_sandbox_os.sql +89 -0
- package/drizzle/0019_session_stream_acknowledgments.sql +94 -0
- package/drizzle/0020_session_recordings.sql +88 -0
- package/drizzle/0021_sandbox_pty_sessions.sql +70 -0
- package/drizzle/0022_sandbox_lease_terminal_url.sql +32 -0
- package/drizzle/0023_session_title.sql +19 -0
- package/drizzle/0024_codex_subscription_credentials.sql +51 -0
- package/drizzle/0024_sandboxes_enrollments_metrics.sql +262 -0
- package/drizzle/0025_device_enrollment_requests.sql +142 -0
- package/drizzle/0026_device_enrollment_user_code_resolver.sql +47 -0
- package/drizzle/0027_session_working_dir.sql +24 -0
- package/drizzle/0028_codex_multi_account.sql +85 -0
- package/drizzle/0029_session_history_item_producer.sql +31 -0
- package/drizzle/0030_agent_run_state_frozen_codex.sql +35 -0
- package/drizzle/0031_codex_usage_cache.sql +21 -0
- package/drizzle/0032_codex_account_cooldown.sql +18 -0
- package/drizzle/0033_codex_connector_cache.sql +20 -0
- package/drizzle/0034_sandbox_lease_image.sql +21 -0
- package/drizzle/meta/_journal.json +167 -0
- package/package.json +66 -0
- package/src/codex-token-resolver.ts +247 -0
- package/src/environment-crypto.ts +51 -0
- package/src/event-payload-sanitizer.ts +89 -0
- package/src/index.ts +7776 -0
- package/src/migrate.ts +95 -0
- package/src/provision-roles.ts +198 -0
- package/src/schema.ts +1110 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
-- Workspace auth + managed billing control plane.
|
|
2
|
+
-- Upgrades pre-workspace databases in place: new auth/account/billing tables,
|
|
3
|
+
-- account_id/workspace_id scoping on all existing tables (backfilled into a
|
|
4
|
+
-- default account/workspace when rows exist), workspace-scoped indexes, and RLS.
|
|
5
|
+
-- Every statement is idempotent so the file is safe to re-run.
|
|
6
|
+
|
|
7
|
+
CREATE TABLE IF NOT EXISTS "auth_users" (
|
|
8
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
9
|
+
"name" text NOT NULL,
|
|
10
|
+
"email" text NOT NULL,
|
|
11
|
+
"email_verified" boolean NOT NULL DEFAULT false,
|
|
12
|
+
"image" text,
|
|
13
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
14
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
15
|
+
);
|
|
16
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "auth_users_email_idx" ON "auth_users" (lower("email"));
|
|
17
|
+
|
|
18
|
+
CREATE TABLE IF NOT EXISTS "auth_sessions" (
|
|
19
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
20
|
+
"user_id" text NOT NULL REFERENCES "auth_users"("id") ON DELETE CASCADE,
|
|
21
|
+
"token" text NOT NULL,
|
|
22
|
+
"expires_at" timestamptz NOT NULL,
|
|
23
|
+
"ip_address" text,
|
|
24
|
+
"user_agent" text,
|
|
25
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
26
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
27
|
+
);
|
|
28
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "auth_sessions_token_idx" ON "auth_sessions" ("token");
|
|
29
|
+
CREATE INDEX IF NOT EXISTS "auth_sessions_user_id_idx" ON "auth_sessions" ("user_id");
|
|
30
|
+
|
|
31
|
+
CREATE TABLE IF NOT EXISTS "auth_identities" (
|
|
32
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
33
|
+
"user_id" text NOT NULL REFERENCES "auth_users"("id") ON DELETE CASCADE,
|
|
34
|
+
"account_id" text NOT NULL,
|
|
35
|
+
"provider_id" text NOT NULL,
|
|
36
|
+
"access_token" text,
|
|
37
|
+
"refresh_token" text,
|
|
38
|
+
"id_token" text,
|
|
39
|
+
"access_token_expires_at" timestamptz,
|
|
40
|
+
"refresh_token_expires_at" timestamptz,
|
|
41
|
+
"scope" text,
|
|
42
|
+
"password" text,
|
|
43
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
44
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
45
|
+
);
|
|
46
|
+
CREATE INDEX IF NOT EXISTS "auth_identities_user_id_idx" ON "auth_identities" ("user_id");
|
|
47
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "auth_identities_provider_account_idx" ON "auth_identities" ("provider_id", "account_id");
|
|
48
|
+
|
|
49
|
+
CREATE TABLE IF NOT EXISTS "auth_verifications" (
|
|
50
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
51
|
+
"identifier" text NOT NULL,
|
|
52
|
+
"value" text NOT NULL,
|
|
53
|
+
"expires_at" timestamptz NOT NULL,
|
|
54
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
55
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
56
|
+
);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS "auth_verifications_identifier_idx" ON "auth_verifications" ("identifier");
|
|
58
|
+
|
|
59
|
+
CREATE TABLE IF NOT EXISTS "auth_rate_limits" (
|
|
60
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
61
|
+
"key" text NOT NULL,
|
|
62
|
+
"count" integer NOT NULL,
|
|
63
|
+
"last_request" bigint NOT NULL
|
|
64
|
+
);
|
|
65
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "auth_rate_limits_key_idx" ON "auth_rate_limits" ("key");
|
|
66
|
+
|
|
67
|
+
CREATE TABLE IF NOT EXISTS "managed_accounts" (
|
|
68
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
69
|
+
"name" text NOT NULL,
|
|
70
|
+
"external_source" text,
|
|
71
|
+
"external_id" text,
|
|
72
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
73
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
74
|
+
);
|
|
75
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "managed_accounts_external_idx" ON "managed_accounts" ("external_source", "external_id");
|
|
76
|
+
|
|
77
|
+
CREATE TABLE IF NOT EXISTS "workspaces" (
|
|
78
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
79
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
80
|
+
"name" text NOT NULL,
|
|
81
|
+
"slug" text,
|
|
82
|
+
"external_source" text,
|
|
83
|
+
"external_id" text,
|
|
84
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
85
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
86
|
+
);
|
|
87
|
+
CREATE INDEX IF NOT EXISTS "workspaces_account_idx" ON "workspaces" ("account_id");
|
|
88
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "workspaces_account_slug_idx" ON "workspaces" ("account_id", "slug") WHERE "slug" IS NOT NULL;
|
|
89
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "workspaces_external_idx" ON "workspaces" ("external_source", "external_id");
|
|
90
|
+
|
|
91
|
+
CREATE TABLE IF NOT EXISTS "workspace_memberships" (
|
|
92
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
93
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
94
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
95
|
+
"subject_id" text NOT NULL,
|
|
96
|
+
"subject_label" text,
|
|
97
|
+
"role" text NOT NULL DEFAULT 'member',
|
|
98
|
+
"permissions" jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
99
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
100
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
101
|
+
);
|
|
102
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "workspace_memberships_subject_workspace_idx" ON "workspace_memberships" ("subject_id", "workspace_id");
|
|
103
|
+
CREATE INDEX IF NOT EXISTS "workspace_memberships_subject_idx" ON "workspace_memberships" ("subject_id");
|
|
104
|
+
CREATE INDEX IF NOT EXISTS "workspace_memberships_account_idx" ON "workspace_memberships" ("account_id");
|
|
105
|
+
|
|
106
|
+
CREATE TABLE IF NOT EXISTS "api_keys" (
|
|
107
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
108
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
109
|
+
"workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
110
|
+
"name" text NOT NULL,
|
|
111
|
+
"prefix" text NOT NULL,
|
|
112
|
+
"key_hash" text NOT NULL,
|
|
113
|
+
"permissions" jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
114
|
+
"expires_at" timestamptz,
|
|
115
|
+
"revoked_at" timestamptz,
|
|
116
|
+
"last_used_at" timestamptz,
|
|
117
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
118
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
119
|
+
);
|
|
120
|
+
CREATE INDEX IF NOT EXISTS "api_keys_prefix_idx" ON "api_keys" ("prefix");
|
|
121
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "api_keys_key_hash_idx" ON "api_keys" ("key_hash");
|
|
122
|
+
CREATE INDEX IF NOT EXISTS "api_keys_account_idx" ON "api_keys" ("account_id");
|
|
123
|
+
CREATE INDEX IF NOT EXISTS "api_keys_workspace_idx" ON "api_keys" ("workspace_id");
|
|
124
|
+
|
|
125
|
+
CREATE TABLE IF NOT EXISTS "github_installations" (
|
|
126
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
127
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
128
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
129
|
+
"installation_id" integer NOT NULL,
|
|
130
|
+
"account_login" text,
|
|
131
|
+
"account_type" text,
|
|
132
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
133
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
134
|
+
);
|
|
135
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "github_installations_workspace_installation_idx" ON "github_installations" ("workspace_id", "installation_id");
|
|
136
|
+
CREATE INDEX IF NOT EXISTS "github_installations_installation_idx" ON "github_installations" ("installation_id");
|
|
137
|
+
CREATE INDEX IF NOT EXISTS "github_installations_workspace_idx" ON "github_installations" ("workspace_id");
|
|
138
|
+
|
|
139
|
+
CREATE TABLE IF NOT EXISTS "usage_events" (
|
|
140
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
141
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
142
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
143
|
+
"subject_id" text,
|
|
144
|
+
"event_type" text NOT NULL,
|
|
145
|
+
"quantity" bigint NOT NULL,
|
|
146
|
+
"unit" text NOT NULL,
|
|
147
|
+
"source_resource_type" text,
|
|
148
|
+
"source_resource_id" text,
|
|
149
|
+
"idempotency_key" text NOT NULL,
|
|
150
|
+
"occurred_at" timestamptz NOT NULL,
|
|
151
|
+
"recorded_at" timestamptz NOT NULL DEFAULT now(),
|
|
152
|
+
"exported_to_billing_at" timestamptz,
|
|
153
|
+
"billing_provider_event_id" text
|
|
154
|
+
);
|
|
155
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "usage_events_idempotency_idx" ON "usage_events" ("idempotency_key");
|
|
156
|
+
CREATE INDEX IF NOT EXISTS "usage_events_workspace_metric_idx" ON "usage_events" ("workspace_id", "event_type", "occurred_at");
|
|
157
|
+
CREATE INDEX IF NOT EXISTS "usage_events_account_metric_idx" ON "usage_events" ("account_id", "event_type", "occurred_at");
|
|
158
|
+
|
|
159
|
+
CREATE TABLE IF NOT EXISTS "credit_ledger_entries" (
|
|
160
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
161
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
162
|
+
"workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE SET NULL,
|
|
163
|
+
"type" text NOT NULL,
|
|
164
|
+
"amount_micros" bigint NOT NULL,
|
|
165
|
+
"currency" text NOT NULL DEFAULT 'usd',
|
|
166
|
+
"source_type" text,
|
|
167
|
+
"source_id" text,
|
|
168
|
+
"idempotency_key" text NOT NULL,
|
|
169
|
+
"metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
170
|
+
"occurred_at" timestamptz NOT NULL DEFAULT now(),
|
|
171
|
+
"created_at" timestamptz NOT NULL DEFAULT now()
|
|
172
|
+
);
|
|
173
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "credit_ledger_entries_idempotency_idx" ON "credit_ledger_entries" ("idempotency_key");
|
|
174
|
+
CREATE INDEX IF NOT EXISTS "credit_ledger_entries_account_created_idx" ON "credit_ledger_entries" ("account_id", "created_at");
|
|
175
|
+
|
|
176
|
+
CREATE TABLE IF NOT EXISTS "billing_customers" (
|
|
177
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
178
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
179
|
+
"provider" text NOT NULL DEFAULT 'stripe',
|
|
180
|
+
"provider_customer_id" text NOT NULL,
|
|
181
|
+
"email" text,
|
|
182
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
183
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
184
|
+
);
|
|
185
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "billing_customers_account_provider_idx" ON "billing_customers" ("account_id", "provider");
|
|
186
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "billing_customers_provider_customer_idx" ON "billing_customers" ("provider", "provider_customer_id");
|
|
187
|
+
|
|
188
|
+
CREATE TABLE IF NOT EXISTS "stripe_webhook_events" (
|
|
189
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
190
|
+
"type" text NOT NULL,
|
|
191
|
+
"livemode" text NOT NULL DEFAULT 'false',
|
|
192
|
+
"payload" jsonb NOT NULL,
|
|
193
|
+
"processed_at" timestamptz,
|
|
194
|
+
"created_at" timestamptz NOT NULL DEFAULT now()
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
CREATE TABLE IF NOT EXISTS "audit_events" (
|
|
198
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
199
|
+
"account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE SET NULL,
|
|
200
|
+
"workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE SET NULL,
|
|
201
|
+
"subject_id" text,
|
|
202
|
+
"action" text NOT NULL,
|
|
203
|
+
"target_type" text,
|
|
204
|
+
"target_id" text,
|
|
205
|
+
"metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
206
|
+
"occurred_at" timestamptz NOT NULL DEFAULT now()
|
|
207
|
+
);
|
|
208
|
+
CREATE INDEX IF NOT EXISTS "audit_events_account_created_idx" ON "audit_events" ("account_id", "occurred_at");
|
|
209
|
+
CREATE INDEX IF NOT EXISTS "audit_events_workspace_created_idx" ON "audit_events" ("workspace_id", "occurred_at");
|
|
210
|
+
|
|
211
|
+
-- Scope all pre-existing tables to an account and workspace. Columns start
|
|
212
|
+
-- nullable so existing rows survive; they are backfilled below and then locked
|
|
213
|
+
-- down with SET NOT NULL.
|
|
214
|
+
|
|
215
|
+
ALTER TABLE "sessions" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
216
|
+
ALTER TABLE "sessions" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
217
|
+
ALTER TABLE "files" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
218
|
+
ALTER TABLE "files" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
219
|
+
ALTER TABLE "file_uploads" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
220
|
+
ALTER TABLE "file_uploads" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
221
|
+
ALTER TABLE "document_bases" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
222
|
+
ALTER TABLE "document_bases" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
223
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
224
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
225
|
+
ALTER TABLE "document_chunks" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
226
|
+
ALTER TABLE "document_chunks" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
227
|
+
ALTER TABLE "session_turns" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
228
|
+
ALTER TABLE "session_turns" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
229
|
+
ALTER TABLE "session_events" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
230
|
+
ALTER TABLE "session_events" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
231
|
+
ALTER TABLE "agent_run_states" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
232
|
+
ALTER TABLE "agent_run_states" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
233
|
+
ALTER TABLE "scheduled_tasks" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
234
|
+
ALTER TABLE "scheduled_tasks" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
235
|
+
ALTER TABLE "scheduled_task_runs" ADD COLUMN IF NOT EXISTS "account_id" uuid REFERENCES "managed_accounts"("id") ON DELETE CASCADE;
|
|
236
|
+
ALTER TABLE "scheduled_task_runs" ADD COLUMN IF NOT EXISTS "workspace_id" uuid REFERENCES "workspaces"("id") ON DELETE CASCADE;
|
|
237
|
+
|
|
238
|
+
-- Backfill: rows created before workspaces existed are adopted by a default
|
|
239
|
+
-- account/workspace, created on demand and marked with a stable external id so
|
|
240
|
+
-- re-runs find it again.
|
|
241
|
+
DO $$
|
|
242
|
+
DECLARE
|
|
243
|
+
v_account_id uuid;
|
|
244
|
+
v_workspace_id uuid;
|
|
245
|
+
BEGIN
|
|
246
|
+
IF EXISTS (SELECT 1 FROM "sessions" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
247
|
+
OR EXISTS (SELECT 1 FROM "files" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
248
|
+
OR EXISTS (SELECT 1 FROM "file_uploads" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
249
|
+
OR EXISTS (SELECT 1 FROM "document_bases" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
250
|
+
OR EXISTS (SELECT 1 FROM "documents" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
251
|
+
OR EXISTS (SELECT 1 FROM "document_chunks" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
252
|
+
OR EXISTS (SELECT 1 FROM "session_turns" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
253
|
+
OR EXISTS (SELECT 1 FROM "session_events" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
254
|
+
OR EXISTS (SELECT 1 FROM "agent_run_states" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
255
|
+
OR EXISTS (SELECT 1 FROM "scheduled_tasks" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
256
|
+
OR EXISTS (SELECT 1 FROM "scheduled_task_runs" WHERE "workspace_id" IS NULL OR "account_id" IS NULL)
|
|
257
|
+
THEN
|
|
258
|
+
SELECT "id" INTO v_account_id
|
|
259
|
+
FROM "managed_accounts"
|
|
260
|
+
WHERE "external_source" = 'opengeni-migration' AND "external_id" = '0001-default-account';
|
|
261
|
+
IF v_account_id IS NULL THEN
|
|
262
|
+
INSERT INTO "managed_accounts" ("name", "external_source", "external_id")
|
|
263
|
+
VALUES ('Default Account', 'opengeni-migration', '0001-default-account')
|
|
264
|
+
RETURNING "id" INTO v_account_id;
|
|
265
|
+
END IF;
|
|
266
|
+
|
|
267
|
+
SELECT "id" INTO v_workspace_id
|
|
268
|
+
FROM "workspaces"
|
|
269
|
+
WHERE "external_source" = 'opengeni-migration' AND "external_id" = '0001-default-workspace';
|
|
270
|
+
IF v_workspace_id IS NULL THEN
|
|
271
|
+
INSERT INTO "workspaces" ("account_id", "name", "slug", "external_source", "external_id")
|
|
272
|
+
VALUES (v_account_id, 'Default Workspace', 'default', 'opengeni-migration', '0001-default-workspace')
|
|
273
|
+
RETURNING "id" INTO v_workspace_id;
|
|
274
|
+
END IF;
|
|
275
|
+
|
|
276
|
+
UPDATE "sessions" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
277
|
+
UPDATE "files" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
278
|
+
UPDATE "file_uploads" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
279
|
+
UPDATE "document_bases" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
280
|
+
UPDATE "documents" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
281
|
+
UPDATE "document_chunks" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
282
|
+
UPDATE "session_turns" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
283
|
+
UPDATE "session_events" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
284
|
+
UPDATE "agent_run_states" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
285
|
+
UPDATE "scheduled_tasks" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
286
|
+
UPDATE "scheduled_task_runs" SET "account_id" = v_account_id, "workspace_id" = v_workspace_id WHERE "workspace_id" IS NULL OR "account_id" IS NULL;
|
|
287
|
+
END IF;
|
|
288
|
+
END $$;
|
|
289
|
+
|
|
290
|
+
ALTER TABLE "sessions" ALTER COLUMN "account_id" SET NOT NULL;
|
|
291
|
+
ALTER TABLE "sessions" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
292
|
+
ALTER TABLE "files" ALTER COLUMN "account_id" SET NOT NULL;
|
|
293
|
+
ALTER TABLE "files" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
294
|
+
ALTER TABLE "file_uploads" ALTER COLUMN "account_id" SET NOT NULL;
|
|
295
|
+
ALTER TABLE "file_uploads" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
296
|
+
ALTER TABLE "document_bases" ALTER COLUMN "account_id" SET NOT NULL;
|
|
297
|
+
ALTER TABLE "document_bases" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
298
|
+
ALTER TABLE "documents" ALTER COLUMN "account_id" SET NOT NULL;
|
|
299
|
+
ALTER TABLE "documents" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
300
|
+
ALTER TABLE "document_chunks" ALTER COLUMN "account_id" SET NOT NULL;
|
|
301
|
+
ALTER TABLE "document_chunks" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
302
|
+
ALTER TABLE "session_turns" ALTER COLUMN "account_id" SET NOT NULL;
|
|
303
|
+
ALTER TABLE "session_turns" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
304
|
+
ALTER TABLE "session_events" ALTER COLUMN "account_id" SET NOT NULL;
|
|
305
|
+
ALTER TABLE "session_events" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
306
|
+
ALTER TABLE "agent_run_states" ALTER COLUMN "account_id" SET NOT NULL;
|
|
307
|
+
ALTER TABLE "agent_run_states" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
308
|
+
ALTER TABLE "scheduled_tasks" ALTER COLUMN "account_id" SET NOT NULL;
|
|
309
|
+
ALTER TABLE "scheduled_tasks" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
310
|
+
ALTER TABLE "scheduled_task_runs" ALTER COLUMN "account_id" SET NOT NULL;
|
|
311
|
+
ALTER TABLE "scheduled_task_runs" ALTER COLUMN "workspace_id" SET NOT NULL;
|
|
312
|
+
|
|
313
|
+
-- session_turns columns are always written explicitly now; drop the legacy
|
|
314
|
+
-- placeholder defaults so the schema matches a fresh install.
|
|
315
|
+
ALTER TABLE "session_turns" ALTER COLUMN "position" DROP DEFAULT;
|
|
316
|
+
ALTER TABLE "session_turns" ALTER COLUMN "prompt" DROP DEFAULT;
|
|
317
|
+
ALTER TABLE "session_turns" ALTER COLUMN "model" DROP DEFAULT;
|
|
318
|
+
ALTER TABLE "session_turns" ALTER COLUMN "reasoning_effort" DROP DEFAULT;
|
|
319
|
+
ALTER TABLE "session_turns" ALTER COLUMN "sandbox_backend" DROP DEFAULT;
|
|
320
|
+
|
|
321
|
+
-- Replace session-scoped indexes with workspace-scoped equivalents.
|
|
322
|
+
DROP INDEX IF EXISTS "documents_base_file_idx";
|
|
323
|
+
DROP INDEX IF EXISTS "documents_base_status_idx";
|
|
324
|
+
DROP INDEX IF EXISTS "document_chunks_document_index_idx";
|
|
325
|
+
DROP INDEX IF EXISTS "document_chunks_base_idx";
|
|
326
|
+
DROP INDEX IF EXISTS "session_events_session_sequence_idx";
|
|
327
|
+
DROP INDEX IF EXISTS "session_events_client_event_idx";
|
|
328
|
+
DROP INDEX IF EXISTS "session_events_producer_idx";
|
|
329
|
+
DROP INDEX IF EXISTS "session_events_session_created_idx";
|
|
330
|
+
DROP INDEX IF EXISTS "session_turns_queue_idx";
|
|
331
|
+
DROP INDEX IF EXISTS "scheduled_tasks_temporal_schedule_id_idx";
|
|
332
|
+
DROP INDEX IF EXISTS "scheduled_tasks_status_idx";
|
|
333
|
+
DROP INDEX IF EXISTS "scheduled_task_runs_task_created_idx";
|
|
334
|
+
DROP INDEX IF EXISTS "scheduled_task_runs_session_idx";
|
|
335
|
+
|
|
336
|
+
CREATE INDEX IF NOT EXISTS "sessions_workspace_created_idx" ON "sessions" ("workspace_id", "created_at");
|
|
337
|
+
CREATE INDEX IF NOT EXISTS "files_workspace_created_idx" ON "files" ("workspace_id", "created_at");
|
|
338
|
+
CREATE INDEX IF NOT EXISTS "file_uploads_workspace_idx" ON "file_uploads" ("workspace_id");
|
|
339
|
+
CREATE INDEX IF NOT EXISTS "document_bases_workspace_created_idx" ON "document_bases" ("workspace_id", "created_at");
|
|
340
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "documents_workspace_base_file_idx" ON "documents" ("workspace_id", "base_id", "file_id");
|
|
341
|
+
CREATE INDEX IF NOT EXISTS "documents_workspace_base_status_idx" ON "documents" ("workspace_id", "base_id", "status");
|
|
342
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "document_chunks_workspace_document_index_idx" ON "document_chunks" ("workspace_id", "document_id", "chunk_index");
|
|
343
|
+
CREATE INDEX IF NOT EXISTS "document_chunks_workspace_base_idx" ON "document_chunks" ("workspace_id", "base_id");
|
|
344
|
+
CREATE INDEX IF NOT EXISTS "session_turns_workspace_queue_idx" ON "session_turns" ("workspace_id", "session_id", "status", "position");
|
|
345
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "session_events_workspace_session_sequence_idx" ON "session_events" ("workspace_id", "session_id", "sequence");
|
|
346
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "session_events_workspace_client_event_idx" ON "session_events" ("workspace_id", "session_id", "client_event_id") WHERE "client_event_id" IS NOT NULL;
|
|
347
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "session_events_workspace_producer_idx" ON "session_events" ("workspace_id", "session_id", "producer_id", "producer_seq") WHERE "producer_id" IS NOT NULL AND "producer_seq" IS NOT NULL;
|
|
348
|
+
CREATE INDEX IF NOT EXISTS "session_events_workspace_session_created_idx" ON "session_events" ("workspace_id", "session_id", "created_at");
|
|
349
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "scheduled_tasks_workspace_temporal_schedule_id_idx" ON "scheduled_tasks" ("workspace_id", "temporal_schedule_id");
|
|
350
|
+
CREATE INDEX IF NOT EXISTS "scheduled_tasks_workspace_status_idx" ON "scheduled_tasks" ("workspace_id", "status");
|
|
351
|
+
CREATE INDEX IF NOT EXISTS "scheduled_task_runs_workspace_task_created_idx" ON "scheduled_task_runs" ("workspace_id", "task_id", "created_at");
|
|
352
|
+
CREATE INDEX IF NOT EXISTS "scheduled_task_runs_workspace_session_idx" ON "scheduled_task_runs" ("workspace_id", "session_id");
|
|
353
|
+
|
|
354
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "workspaces_id_account_idx" ON "workspaces" ("id", "account_id");
|
|
355
|
+
|
|
356
|
+
DO $$
|
|
357
|
+
BEGIN
|
|
358
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'workspace_memberships_workspace_account_fk') THEN
|
|
359
|
+
ALTER TABLE "workspace_memberships" ADD CONSTRAINT "workspace_memberships_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
360
|
+
END IF;
|
|
361
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'api_keys_workspace_account_fk') THEN
|
|
362
|
+
ALTER TABLE "api_keys" ADD CONSTRAINT "api_keys_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
363
|
+
END IF;
|
|
364
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'sessions_workspace_account_fk') THEN
|
|
365
|
+
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
366
|
+
END IF;
|
|
367
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'files_workspace_account_fk') THEN
|
|
368
|
+
ALTER TABLE "files" ADD CONSTRAINT "files_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
369
|
+
END IF;
|
|
370
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'file_uploads_workspace_account_fk') THEN
|
|
371
|
+
ALTER TABLE "file_uploads" ADD CONSTRAINT "file_uploads_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
372
|
+
END IF;
|
|
373
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'document_bases_workspace_account_fk') THEN
|
|
374
|
+
ALTER TABLE "document_bases" ADD CONSTRAINT "document_bases_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
375
|
+
END IF;
|
|
376
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'documents_workspace_account_fk') THEN
|
|
377
|
+
ALTER TABLE "documents" ADD CONSTRAINT "documents_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
378
|
+
END IF;
|
|
379
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'document_chunks_workspace_account_fk') THEN
|
|
380
|
+
ALTER TABLE "document_chunks" ADD CONSTRAINT "document_chunks_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
381
|
+
END IF;
|
|
382
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'session_turns_workspace_account_fk') THEN
|
|
383
|
+
ALTER TABLE "session_turns" ADD CONSTRAINT "session_turns_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
384
|
+
END IF;
|
|
385
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'session_events_workspace_account_fk') THEN
|
|
386
|
+
ALTER TABLE "session_events" ADD CONSTRAINT "session_events_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
387
|
+
END IF;
|
|
388
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'agent_run_states_workspace_account_fk') THEN
|
|
389
|
+
ALTER TABLE "agent_run_states" ADD CONSTRAINT "agent_run_states_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
390
|
+
END IF;
|
|
391
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'scheduled_tasks_workspace_account_fk') THEN
|
|
392
|
+
ALTER TABLE "scheduled_tasks" ADD CONSTRAINT "scheduled_tasks_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
393
|
+
END IF;
|
|
394
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'scheduled_task_runs_workspace_account_fk') THEN
|
|
395
|
+
ALTER TABLE "scheduled_task_runs" ADD CONSTRAINT "scheduled_task_runs_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
396
|
+
END IF;
|
|
397
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'github_installations_workspace_account_fk') THEN
|
|
398
|
+
ALTER TABLE "github_installations" ADD CONSTRAINT "github_installations_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
399
|
+
END IF;
|
|
400
|
+
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'usage_events_workspace_account_fk') THEN
|
|
401
|
+
ALTER TABLE "usage_events" ADD CONSTRAINT "usage_events_workspace_account_fk" FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
402
|
+
END IF;
|
|
403
|
+
END $$;
|
|
404
|
+
|
|
405
|
+
CREATE SCHEMA IF NOT EXISTS opengeni_private;
|
|
406
|
+
|
|
407
|
+
CREATE OR REPLACE FUNCTION opengeni_private.current_workspace_id()
|
|
408
|
+
RETURNS uuid
|
|
409
|
+
LANGUAGE sql
|
|
410
|
+
STABLE
|
|
411
|
+
AS $$
|
|
412
|
+
SELECT nullif(current_setting('opengeni.workspace_id', true), '')::uuid;
|
|
413
|
+
$$;
|
|
414
|
+
|
|
415
|
+
CREATE OR REPLACE FUNCTION opengeni_private.current_account_id()
|
|
416
|
+
RETURNS uuid
|
|
417
|
+
LANGUAGE sql
|
|
418
|
+
STABLE
|
|
419
|
+
AS $$
|
|
420
|
+
SELECT nullif(current_setting('opengeni.account_id', true), '')::uuid;
|
|
421
|
+
$$;
|
|
422
|
+
|
|
423
|
+
CREATE OR REPLACE FUNCTION opengeni_private.workspace_rls_visible(account_id uuid, workspace_id uuid)
|
|
424
|
+
RETURNS boolean
|
|
425
|
+
LANGUAGE sql
|
|
426
|
+
STABLE
|
|
427
|
+
AS $$
|
|
428
|
+
SELECT account_id = opengeni_private.current_account_id()
|
|
429
|
+
AND workspace_id = opengeni_private.current_workspace_id();
|
|
430
|
+
$$;
|
|
431
|
+
|
|
432
|
+
CREATE OR REPLACE FUNCTION opengeni_private.account_rls_visible(account_id uuid)
|
|
433
|
+
RETURNS boolean
|
|
434
|
+
LANGUAGE sql
|
|
435
|
+
STABLE
|
|
436
|
+
AS $$
|
|
437
|
+
SELECT account_id = opengeni_private.current_account_id();
|
|
438
|
+
$$;
|
|
439
|
+
|
|
440
|
+
CREATE OR REPLACE FUNCTION opengeni_private.optional_workspace_rls_visible(account_id uuid, workspace_id uuid)
|
|
441
|
+
RETURNS boolean
|
|
442
|
+
LANGUAGE sql
|
|
443
|
+
STABLE
|
|
444
|
+
AS $$
|
|
445
|
+
SELECT account_id = opengeni_private.current_account_id()
|
|
446
|
+
AND (
|
|
447
|
+
opengeni_private.current_workspace_id() IS NULL
|
|
448
|
+
OR workspace_id IS NULL
|
|
449
|
+
OR workspace_id = opengeni_private.current_workspace_id()
|
|
450
|
+
);
|
|
451
|
+
$$;
|
|
452
|
+
|
|
453
|
+
CREATE OR REPLACE FUNCTION opengeni_private.current_api_key_hash()
|
|
454
|
+
RETURNS text
|
|
455
|
+
LANGUAGE sql
|
|
456
|
+
STABLE
|
|
457
|
+
AS $$
|
|
458
|
+
SELECT nullif(current_setting('opengeni.api_key_hash', true), '');
|
|
459
|
+
$$;
|
|
460
|
+
|
|
461
|
+
DO $$
|
|
462
|
+
DECLARE
|
|
463
|
+
table_name text;
|
|
464
|
+
BEGIN
|
|
465
|
+
FOREACH table_name IN ARRAY ARRAY[
|
|
466
|
+
'sessions',
|
|
467
|
+
'session_events',
|
|
468
|
+
'session_turns',
|
|
469
|
+
'agent_run_states',
|
|
470
|
+
'files',
|
|
471
|
+
'file_uploads',
|
|
472
|
+
'document_bases',
|
|
473
|
+
'documents',
|
|
474
|
+
'document_chunks',
|
|
475
|
+
'scheduled_tasks',
|
|
476
|
+
'scheduled_task_runs',
|
|
477
|
+
'github_installations'
|
|
478
|
+
]
|
|
479
|
+
LOOP
|
|
480
|
+
EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', table_name);
|
|
481
|
+
EXECUTE format('ALTER TABLE %I FORCE ROW LEVEL SECURITY', table_name);
|
|
482
|
+
IF EXISTS (
|
|
483
|
+
SELECT 1 FROM pg_policies
|
|
484
|
+
WHERE schemaname = current_schema() AND tablename = table_name AND policyname = 'workspace_isolation'
|
|
485
|
+
) THEN
|
|
486
|
+
EXECUTE format('DROP POLICY workspace_isolation ON %I', table_name);
|
|
487
|
+
END IF;
|
|
488
|
+
EXECUTE format(
|
|
489
|
+
'CREATE POLICY workspace_isolation ON %I USING (opengeni_private.workspace_rls_visible(account_id, workspace_id)) WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id))',
|
|
490
|
+
table_name
|
|
491
|
+
);
|
|
492
|
+
END LOOP;
|
|
493
|
+
END $$;
|
|
494
|
+
|
|
495
|
+
ALTER TABLE "api_keys" ENABLE ROW LEVEL SECURITY;
|
|
496
|
+
ALTER TABLE "api_keys" FORCE ROW LEVEL SECURITY;
|
|
497
|
+
DO $$
|
|
498
|
+
BEGIN
|
|
499
|
+
IF EXISTS (
|
|
500
|
+
SELECT 1 FROM pg_policies
|
|
501
|
+
WHERE schemaname = current_schema() AND tablename = 'api_keys' AND policyname = 'api_keys_account_workspace_or_hash_isolation'
|
|
502
|
+
) THEN
|
|
503
|
+
DROP POLICY "api_keys_account_workspace_or_hash_isolation" ON "api_keys";
|
|
504
|
+
END IF;
|
|
505
|
+
END $$;
|
|
506
|
+
CREATE POLICY "api_keys_account_workspace_or_hash_isolation" ON "api_keys"
|
|
507
|
+
USING (
|
|
508
|
+
opengeni_private.optional_workspace_rls_visible(account_id, workspace_id)
|
|
509
|
+
OR key_hash = opengeni_private.current_api_key_hash()
|
|
510
|
+
)
|
|
511
|
+
WITH CHECK (
|
|
512
|
+
opengeni_private.optional_workspace_rls_visible(account_id, workspace_id)
|
|
513
|
+
OR key_hash = opengeni_private.current_api_key_hash()
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
ALTER TABLE "usage_events" ENABLE ROW LEVEL SECURITY;
|
|
517
|
+
ALTER TABLE "usage_events" FORCE ROW LEVEL SECURITY;
|
|
518
|
+
DO $$
|
|
519
|
+
BEGIN
|
|
520
|
+
IF EXISTS (
|
|
521
|
+
SELECT 1 FROM pg_policies
|
|
522
|
+
WHERE schemaname = current_schema() AND tablename = 'usage_events' AND policyname = 'usage_events_account_workspace_isolation'
|
|
523
|
+
) THEN
|
|
524
|
+
DROP POLICY "usage_events_account_workspace_isolation" ON "usage_events";
|
|
525
|
+
END IF;
|
|
526
|
+
END $$;
|
|
527
|
+
CREATE POLICY "usage_events_account_workspace_isolation" ON "usage_events"
|
|
528
|
+
USING (opengeni_private.optional_workspace_rls_visible(account_id, workspace_id))
|
|
529
|
+
WITH CHECK (opengeni_private.optional_workspace_rls_visible(account_id, workspace_id));
|
|
530
|
+
|
|
531
|
+
ALTER TABLE "credit_ledger_entries" ENABLE ROW LEVEL SECURITY;
|
|
532
|
+
ALTER TABLE "credit_ledger_entries" FORCE ROW LEVEL SECURITY;
|
|
533
|
+
DO $$
|
|
534
|
+
BEGIN
|
|
535
|
+
IF EXISTS (
|
|
536
|
+
SELECT 1 FROM pg_policies
|
|
537
|
+
WHERE schemaname = current_schema() AND tablename = 'credit_ledger_entries' AND policyname = 'credit_ledger_account_workspace_isolation'
|
|
538
|
+
) THEN
|
|
539
|
+
DROP POLICY "credit_ledger_account_workspace_isolation" ON "credit_ledger_entries";
|
|
540
|
+
END IF;
|
|
541
|
+
END $$;
|
|
542
|
+
CREATE POLICY "credit_ledger_account_workspace_isolation" ON "credit_ledger_entries"
|
|
543
|
+
USING (opengeni_private.optional_workspace_rls_visible(account_id, workspace_id))
|
|
544
|
+
WITH CHECK (opengeni_private.optional_workspace_rls_visible(account_id, workspace_id));
|
|
545
|
+
|
|
546
|
+
ALTER TABLE "billing_customers" ENABLE ROW LEVEL SECURITY;
|
|
547
|
+
ALTER TABLE "billing_customers" FORCE ROW LEVEL SECURITY;
|
|
548
|
+
DO $$
|
|
549
|
+
BEGIN
|
|
550
|
+
IF EXISTS (
|
|
551
|
+
SELECT 1 FROM pg_policies
|
|
552
|
+
WHERE schemaname = current_schema() AND tablename = 'billing_customers' AND policyname = 'billing_customers_account_isolation'
|
|
553
|
+
) THEN
|
|
554
|
+
DROP POLICY "billing_customers_account_isolation" ON "billing_customers";
|
|
555
|
+
END IF;
|
|
556
|
+
END $$;
|
|
557
|
+
CREATE POLICY "billing_customers_account_isolation" ON "billing_customers"
|
|
558
|
+
USING (opengeni_private.account_rls_visible(account_id))
|
|
559
|
+
WITH CHECK (opengeni_private.account_rls_visible(account_id));
|
|
560
|
+
|
|
561
|
+
ALTER TABLE "audit_events" ENABLE ROW LEVEL SECURITY;
|
|
562
|
+
ALTER TABLE "audit_events" FORCE ROW LEVEL SECURITY;
|
|
563
|
+
DO $$
|
|
564
|
+
BEGIN
|
|
565
|
+
IF EXISTS (
|
|
566
|
+
SELECT 1 FROM pg_policies
|
|
567
|
+
WHERE schemaname = current_schema() AND tablename = 'audit_events' AND policyname = 'audit_events_account_workspace_isolation'
|
|
568
|
+
) THEN
|
|
569
|
+
DROP POLICY "audit_events_account_workspace_isolation" ON "audit_events";
|
|
570
|
+
END IF;
|
|
571
|
+
END $$;
|
|
572
|
+
CREATE POLICY "audit_events_account_workspace_isolation" ON "audit_events"
|
|
573
|
+
USING (
|
|
574
|
+
account_id IS NULL
|
|
575
|
+
OR opengeni_private.optional_workspace_rls_visible(account_id, workspace_id)
|
|
576
|
+
)
|
|
577
|
+
WITH CHECK (
|
|
578
|
+
account_id IS NULL
|
|
579
|
+
OR opengeni_private.optional_workspace_rls_visible(account_id, workspace_id)
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
DO $$
|
|
583
|
+
BEGIN
|
|
584
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
585
|
+
GRANT USAGE ON SCHEMA public TO opengeni_app;
|
|
586
|
+
GRANT USAGE ON SCHEMA opengeni_private TO opengeni_app;
|
|
587
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
|
|
588
|
+
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA opengeni_private TO opengeni_app;
|
|
589
|
+
END IF;
|
|
590
|
+
END $$;
|