@opengeni/db 0.36.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-HSOWSYOX.js → chunk-4SR4HKKA.js} +2 -2
  3. package/dist/{chunk-5KTIEDX7.js → chunk-6ZYKCRFO.js} +124 -16
  4. package/dist/chunk-6ZYKCRFO.js.map +1 -0
  5. package/dist/{chunk-VTPRIXKG.js → chunk-CUPM3FGB.js} +3 -3
  6. package/dist/{chunk-GYO7ED2Q.js → chunk-LTG3S6ZY.js} +2 -2
  7. package/dist/{chunk-VKLB2ZGI.js → chunk-NXAFLCQX.js} +81 -2
  8. package/dist/chunk-NXAFLCQX.js.map +1 -0
  9. package/dist/{chunk-FPVAD4CO.js → chunk-WD5ROSLL.js} +2 -2
  10. package/dist/{chunk-Z7VYMNPZ.js → chunk-ZWREYEWA.js} +2 -2
  11. package/dist/editable-artifact-durable-export.d.ts +10 -0
  12. package/dist/editable-artifact-durable-export.js +18 -3
  13. package/dist/editable-artifact-durable-export.js.map +1 -1
  14. package/dist/editable-artifacts.js +3 -3
  15. package/dist/index.d.ts +40 -8
  16. package/dist/index.js +509 -59
  17. package/dist/index.js.map +1 -1
  18. package/dist/knowledge-source-sync-schema.d.ts +730 -0
  19. package/dist/knowledge-source-sync.d.ts +60 -0
  20. package/dist/provision-roles.js +1 -1
  21. package/dist/runtime-posture.d.ts +3 -3
  22. package/dist/schema.d.ts +21 -4
  23. package/dist/schema.js +5 -1
  24. package/dist/session-queue-commands.d.ts +1 -1
  25. package/dist/session-realtime-ledger.d.ts +1 -0
  26. package/dist/session-tenancy.js +3 -3
  27. package/dist/video-generation.js +3 -3
  28. package/drizzle/0240_model_context_user_messages.sql +204 -0
  29. package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
  30. package/package.json +4 -4
  31. package/src/editable-artifact-durable-export.ts +27 -0
  32. package/src/index.ts +212 -13
  33. package/src/knowledge-source-sync-schema.ts +83 -0
  34. package/src/knowledge-source-sync.ts +530 -0
  35. package/src/provision-roles.ts +36 -0
  36. package/src/runtime-posture.ts +49 -1
  37. package/src/schema.ts +30 -7
  38. package/src/session-queue-commands.ts +13 -14
  39. package/src/session-realtime-context.ts +16 -0
  40. package/src/session-realtime-ledger.ts +53 -1
  41. package/dist/chunk-5KTIEDX7.js.map +0 -1
  42. package/dist/chunk-VKLB2ZGI.js.map +0 -1
  43. /package/dist/{chunk-HSOWSYOX.js.map → chunk-4SR4HKKA.js.map} +0 -0
  44. /package/dist/{chunk-VTPRIXKG.js.map → chunk-CUPM3FGB.js.map} +0 -0
  45. /package/dist/{chunk-GYO7ED2Q.js.map → chunk-LTG3S6ZY.js.map} +0 -0
  46. /package/dist/{chunk-FPVAD4CO.js.map → chunk-WD5ROSLL.js.map} +0 -0
  47. /package/dist/{chunk-Z7VYMNPZ.js.map → chunk-ZWREYEWA.js.map} +0 -0
@@ -0,0 +1,554 @@
1
+ -- deployment-mode: rolling
2
+ -- Google Drive retrieval is provider-authorized per object, not merely by the
3
+ -- destination document's organization/workspace/personal visibility. Persist
4
+ -- append-only, freshness-bounded ACL observations and expose one fail-closed
5
+ -- SECURITY DEFINER predicate so cross-workspace organization reads do not need
6
+ -- direct access to source-workspace ACL rows. Principal values are stored only
7
+ -- as domain-separated SHA-256 hashes; credentials remain in connections.
8
+
9
+ SET LOCAL lock_timeout = '5s';
10
+ SET LOCAL statement_timeout = '30min';
11
+
12
+ CREATE TABLE opengeni_private.google_drive_object_acl_runtime_capabilities (
13
+ "backend_pid" integer NOT NULL,
14
+ "transaction_id" xid8 NOT NULL,
15
+ "capability_kind" text NOT NULL,
16
+ "created_at" timestamptz NOT NULL DEFAULT clock_timestamp(),
17
+ CONSTRAINT "google_drive_object_acl_runtime_capabilities_kind_chk" CHECK (
18
+ "capability_kind" IN ('authorize', 'citation')
19
+ ),
20
+ CONSTRAINT "google_drive_object_acl_runtime_capabilities_pk" PRIMARY KEY (
21
+ "backend_pid", "transaction_id", "capability_kind"
22
+ )
23
+ );
24
+ REVOKE ALL ON TABLE opengeni_private.google_drive_object_acl_runtime_capabilities FROM PUBLIC;
25
+
26
+ CREATE OR REPLACE FUNCTION opengeni_private.google_drive_object_acl_capability_active()
27
+ RETURNS boolean
28
+ LANGUAGE sql STABLE SECURITY DEFINER
29
+ SET search_path = opengeni_private, pg_catalog
30
+ AS $$
31
+ SELECT EXISTS (
32
+ SELECT 1
33
+ FROM google_drive_object_acl_runtime_capabilities capability
34
+ WHERE capability.backend_pid = pg_catalog.pg_backend_pid()
35
+ AND capability.transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
36
+ AND capability.capability_kind IN ('authorize', 'citation')
37
+ );
38
+ $$;
39
+ REVOKE ALL ON FUNCTION opengeni_private.google_drive_object_acl_capability_active() FROM PUBLIC;
40
+
41
+ DO $google_drive_capability_revoke$
42
+ BEGIN
43
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
44
+ REVOKE ALL ON TABLE opengeni_private.google_drive_object_acl_runtime_capabilities
45
+ FROM opengeni_app;
46
+ GRANT EXECUTE ON FUNCTION opengeni_private.google_drive_object_acl_capability_active()
47
+ TO opengeni_app;
48
+ END IF;
49
+ END
50
+ $google_drive_capability_revoke$;
51
+
52
+ CREATE TABLE "google_drive_object_acl_evidence" (
53
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
54
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
55
+ "workspace_id" uuid NOT NULL,
56
+ "source_id" uuid NOT NULL REFERENCES "knowledge_sources"("id") ON DELETE CASCADE,
57
+ "knowledge_source_object_id" uuid NOT NULL
58
+ REFERENCES "knowledge_source_objects"("id") ON DELETE CASCADE,
59
+ "knowledge_document_version_id" uuid NOT NULL
60
+ REFERENCES "knowledge_document_versions"("id") ON DELETE CASCADE,
61
+ "document_id" uuid NOT NULL REFERENCES "documents"("id") ON DELETE CASCADE,
62
+ "file_id" uuid NOT NULL REFERENCES "files"("id") ON DELETE RESTRICT,
63
+ "index_obligation_id" uuid NOT NULL
64
+ REFERENCES "knowledge_source_sync_index_obligations"("id") ON DELETE CASCADE,
65
+ "connection_id" uuid NOT NULL REFERENCES "connections"("id") ON DELETE RESTRICT,
66
+ "connection_version" bigint NOT NULL,
67
+ "source_principal_hash" text NOT NULL,
68
+ "source_sync_generation" bigint NOT NULL,
69
+ "source_config_generation" bigint NOT NULL,
70
+ "source_lifecycle_generation" bigint NOT NULL,
71
+ "object_lifecycle_generation" bigint NOT NULL,
72
+ "object_version_generation" bigint NOT NULL,
73
+ "provider_revision" text,
74
+ "drive_id" text,
75
+ "acl_revision" text NOT NULL,
76
+ "acl_hash" text NOT NULL,
77
+ "eligibility" text NOT NULL,
78
+ "observed_at" timestamptz NOT NULL,
79
+ "expires_at" timestamptz NOT NULL,
80
+ "citation_locator" jsonb NOT NULL,
81
+ "operation_id" text NOT NULL,
82
+ "input_hash" text NOT NULL,
83
+ "created_at" timestamptz NOT NULL DEFAULT now(),
84
+ CONSTRAINT "google_drive_object_acl_evidence_workspace_fk"
85
+ FOREIGN KEY ("workspace_id", "account_id")
86
+ REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE,
87
+ CONSTRAINT "google_drive_object_acl_evidence_obligation_uq"
88
+ UNIQUE ("index_obligation_id", "operation_id"),
89
+ CONSTRAINT "google_drive_object_acl_evidence_identity_uq"
90
+ UNIQUE ("id", "index_obligation_id"),
91
+ CONSTRAINT "google_drive_object_acl_evidence_bounds_chk" CHECK (
92
+ "connection_version" > 0
93
+ AND "source_sync_generation" >= 0
94
+ AND "source_config_generation" > 0
95
+ AND "source_lifecycle_generation" > 0
96
+ AND "object_lifecycle_generation" > 0
97
+ AND "object_version_generation" > 0
98
+ AND "source_principal_hash" ~ '^[0-9a-f]{64}$'
99
+ AND ("provider_revision" IS NULL OR length("provider_revision") BETWEEN 1 AND 1024)
100
+ AND ("drive_id" IS NULL OR length("drive_id") BETWEEN 1 AND 1024)
101
+ AND length(btrim("acl_revision")) BETWEEN 1 AND 1024
102
+ AND "acl_hash" ~ '^[0-9a-f]{64}$'
103
+ AND "eligibility" IN ('eligible', 'denied')
104
+ AND "expires_at" > "observed_at"
105
+ AND jsonb_typeof("citation_locator") = 'object'
106
+ AND octet_length(convert_to("citation_locator"::text, 'UTF8')) <= 16384
107
+ AND length(btrim("operation_id")) BETWEEN 1 AND 256
108
+ AND "input_hash" ~ '^[0-9a-f]{64}$'
109
+ )
110
+ );
111
+
112
+ CREATE INDEX "google_drive_object_acl_evidence_version_idx"
113
+ ON "google_drive_object_acl_evidence" (
114
+ "knowledge_document_version_id", "expires_at" DESC, "created_at" DESC
115
+ );
116
+ CREATE INDEX "google_drive_object_acl_evidence_file_idx"
117
+ ON "google_drive_object_acl_evidence" ("account_id", "file_id", "expires_at" DESC);
118
+
119
+ CREATE TABLE "google_drive_object_acl_principals" (
120
+ "evidence_id" uuid NOT NULL
121
+ REFERENCES "google_drive_object_acl_evidence"("id") ON DELETE CASCADE,
122
+ "ordinal" integer NOT NULL,
123
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
124
+ "workspace_id" uuid NOT NULL,
125
+ "principal_type" text NOT NULL,
126
+ "permission_id_hash" text,
127
+ "email_hash" text,
128
+ "domain_hash" text,
129
+ "role" text NOT NULL,
130
+ "inherited" boolean NOT NULL DEFAULT false,
131
+ "allow_file_discovery" boolean,
132
+ "expiration_time" timestamptz,
133
+ "created_at" timestamptz NOT NULL DEFAULT now(),
134
+ PRIMARY KEY ("evidence_id", "ordinal"),
135
+ CONSTRAINT "google_drive_object_acl_principals_workspace_fk"
136
+ FOREIGN KEY ("workspace_id", "account_id")
137
+ REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE,
138
+ CONSTRAINT "google_drive_object_acl_principals_bounds_chk" CHECK (
139
+ "ordinal" >= 0 AND "ordinal" < 10000
140
+ AND "principal_type" IN ('user', 'group', 'domain', 'anyone')
141
+ AND ("permission_id_hash" IS NULL OR "permission_id_hash" ~ '^[0-9a-f]{64}$')
142
+ AND ("email_hash" IS NULL OR "email_hash" ~ '^[0-9a-f]{64}$')
143
+ AND ("domain_hash" IS NULL OR "domain_hash" ~ '^[0-9a-f]{64}$')
144
+ AND "role" IN ('owner', 'organizer', 'fileOrganizer', 'writer', 'commenter', 'reader')
145
+ AND (
146
+ ("principal_type" = 'user' AND ("permission_id_hash" IS NOT NULL OR "email_hash" IS NOT NULL))
147
+ OR ("principal_type" = 'group' AND ("permission_id_hash" IS NOT NULL OR "email_hash" IS NOT NULL))
148
+ OR ("principal_type" = 'domain' AND "domain_hash" IS NOT NULL)
149
+ OR ("principal_type" = 'anyone'
150
+ AND "permission_id_hash" IS NULL AND "email_hash" IS NULL AND "domain_hash" IS NULL)
151
+ )
152
+ )
153
+ );
154
+
155
+ CREATE INDEX "google_drive_object_acl_principals_match_idx"
156
+ ON "google_drive_object_acl_principals" (
157
+ "evidence_id", "principal_type", "permission_id_hash", "email_hash", "domain_hash"
158
+ );
159
+
160
+ ALTER TABLE "knowledge_source_sync_index_obligations"
161
+ ADD COLUMN "google_drive_acl_evidence_id" uuid;
162
+
163
+ ALTER TABLE "knowledge_source_sync_index_obligations"
164
+ ADD CONSTRAINT "knowledge_source_sync_index_obligations_drive_acl_fk"
165
+ FOREIGN KEY ("google_drive_acl_evidence_id")
166
+ REFERENCES "google_drive_object_acl_evidence"("id")
167
+ ON DELETE SET NULL NOT VALID;
168
+
169
+ ALTER TABLE "knowledge_source_sync_index_obligations"
170
+ VALIDATE CONSTRAINT "knowledge_source_sync_index_obligations_drive_acl_fk";
171
+
172
+ ALTER TABLE "google_drive_object_acl_evidence" ENABLE ROW LEVEL SECURITY;
173
+ ALTER TABLE "google_drive_object_acl_evidence" FORCE ROW LEVEL SECURITY;
174
+ ALTER TABLE "google_drive_object_acl_principals" ENABLE ROW LEVEL SECURITY;
175
+ ALTER TABLE "google_drive_object_acl_principals" FORCE ROW LEVEL SECURITY;
176
+
177
+ CREATE POLICY "google_drive_object_acl_evidence_workspace_isolation"
178
+ ON "google_drive_object_acl_evidence"
179
+ USING (
180
+ "account_id" = nullif(current_setting('opengeni.account_id', true), '')::uuid
181
+ AND "workspace_id" = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
182
+ )
183
+ WITH CHECK (
184
+ "account_id" = nullif(current_setting('opengeni.account_id', true), '')::uuid
185
+ AND "workspace_id" = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
186
+ );
187
+
188
+ CREATE POLICY "google_drive_object_acl_principals_workspace_isolation"
189
+ ON "google_drive_object_acl_principals"
190
+ USING (
191
+ "account_id" = nullif(current_setting('opengeni.account_id', true), '')::uuid
192
+ AND "workspace_id" = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
193
+ )
194
+ WITH CHECK (
195
+ "account_id" = nullif(current_setting('opengeni.account_id', true), '')::uuid
196
+ AND "workspace_id" = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
197
+ );
198
+
199
+ -- Every joined authority table is FORCE-RLS. The exact SECURITY DEFINER
200
+ -- routines below need a complete all-protectors view even when the requesting
201
+ -- workspace/subject cannot directly see a source row. A transaction-local row
202
+ -- in the private capability table opens only SELECT, only for a routine whose
203
+ -- effective role is the table owner. opengeni_app has no capability-table
204
+ -- privileges and cannot forge this path through a custom GUC.
205
+ DO $google_drive_capability_policies$
206
+ DECLARE table_name text;
207
+ DECLARE data_schema text := current_schema();
208
+ BEGIN
209
+ FOREACH table_name IN ARRAY ARRAY[
210
+ 'connections',
211
+ 'files',
212
+ 'google_drive_object_acl_evidence',
213
+ 'google_drive_object_acl_principals',
214
+ 'knowledge_document_versions',
215
+ 'knowledge_providers',
216
+ 'knowledge_source_objects',
217
+ 'knowledge_source_sync_index_obligations',
218
+ 'knowledge_source_sync_states',
219
+ 'knowledge_sources'
220
+ ] LOOP
221
+ EXECUTE format(
222
+ 'DROP POLICY IF EXISTS google_drive_object_acl_capability_read ON %I.%I',
223
+ data_schema,
224
+ table_name
225
+ );
226
+ EXECUTE format($policy$
227
+ CREATE POLICY google_drive_object_acl_capability_read ON %1$I.%2$I
228
+ FOR SELECT USING (
229
+ current_user = pg_catalog.pg_get_userbyid(
230
+ (SELECT relation.relowner
231
+ FROM pg_catalog.pg_class relation
232
+ WHERE relation.oid = %3$L::pg_catalog.regclass)
233
+ )
234
+ AND opengeni_private.google_drive_object_acl_capability_active()
235
+ )
236
+ $policy$, data_schema, table_name, data_schema || '.' || table_name);
237
+ END LOOP;
238
+ END
239
+ $google_drive_capability_policies$;
240
+
241
+ DO $google_drive_file_authority$
242
+ DECLARE data_schema text := current_schema();
243
+ BEGIN
244
+ EXECUTE format($ddl$
245
+ CREATE OR REPLACE FUNCTION %1$I.google_drive_file_authorized(
246
+ p_account_id uuid,
247
+ p_request_workspace_id uuid,
248
+ p_subject_id text,
249
+ p_file_id uuid
250
+ ) RETURNS boolean
251
+ LANGUAGE plpgsql SECURITY DEFINER
252
+ SET search_path = %1$I, pg_catalog
253
+ AS $body$
254
+ DECLARE file_exists boolean := false;
255
+ DECLARE protected boolean := false;
256
+ DECLARE authorized boolean := false;
257
+ BEGIN
258
+ IF p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
259
+ OR p_request_workspace_id IS DISTINCT FROM
260
+ nullif(pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
261
+ OR p_subject_id IS DISTINCT FROM opengeni_private.current_subject_id()
262
+ OR p_file_id IS NULL
263
+ THEN
264
+ RETURN false;
265
+ END IF;
266
+
267
+ INSERT INTO opengeni_private.google_drive_object_acl_runtime_capabilities (
268
+ backend_pid, transaction_id, capability_kind
269
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'authorize')
270
+ ON CONFLICT DO NOTHING;
271
+ BEGIN
272
+ SELECT EXISTS (
273
+ SELECT 1 FROM files file_row
274
+ WHERE file_row.id = p_file_id AND file_row.account_id = p_account_id
275
+ ) INTO file_exists;
276
+ IF file_exists THEN
277
+ SELECT EXISTS (
278
+ SELECT 1
279
+ FROM knowledge_document_versions version_row
280
+ JOIN knowledge_sources source_row ON source_row.id = version_row.source_id
281
+ JOIN knowledge_providers provider_row ON provider_row.id = source_row.provider_id
282
+ WHERE version_row.account_id = p_account_id
283
+ AND version_row.file_id = p_file_id
284
+ AND provider_row.provider_key = 'google-drive'
285
+ ) INTO protected;
286
+ END IF;
287
+
288
+ IF file_exists AND NOT protected THEN
289
+ authorized := true;
290
+ ELSIF file_exists AND p_subject_id IS NULL THEN
291
+ authorized := false;
292
+ ELSIF file_exists THEN
293
+ -- Every Google Drive object that has ever protected these exact bytes
294
+ -- must still point at those bytes and carry current, fresh evidence for
295
+ -- this subject. This all-protectors rule prevents a non-Google document
296
+ -- or a second allowed Drive mapping from overriding one denied mapping.
297
+ SELECT NOT EXISTS (
298
+ SELECT 1
299
+ FROM (
300
+ SELECT DISTINCT version_row.object_id
301
+ FROM knowledge_document_versions version_row
302
+ JOIN knowledge_sources source_row ON source_row.id = version_row.source_id
303
+ JOIN knowledge_providers provider_row ON provider_row.id = source_row.provider_id
304
+ WHERE version_row.account_id = p_account_id
305
+ AND version_row.file_id = p_file_id
306
+ AND provider_row.provider_key = 'google-drive'
307
+ ) protector
308
+ WHERE NOT EXISTS (
309
+ SELECT 1
310
+ FROM knowledge_source_objects object_row
311
+ JOIN knowledge_document_versions current_version
312
+ ON current_version.id = object_row.current_version_id
313
+ AND current_version.object_id = object_row.id
314
+ JOIN knowledge_sources source_row ON source_row.id = object_row.source_id
315
+ JOIN knowledge_providers provider_row ON provider_row.id = source_row.provider_id
316
+ JOIN knowledge_source_sync_index_obligations obligation
317
+ ON obligation.knowledge_document_version_id = current_version.id
318
+ AND obligation.knowledge_source_object_id = object_row.id
319
+ AND obligation.document_id = current_version.document_id
320
+ JOIN knowledge_source_sync_states sync_state
321
+ ON sync_state.source_id = source_row.id
322
+ JOIN google_drive_object_acl_evidence evidence
323
+ ON evidence.id = obligation.google_drive_acl_evidence_id
324
+ AND evidence.index_obligation_id = obligation.id
325
+ JOIN connections source_connection ON source_connection.id = evidence.connection_id
326
+ WHERE object_row.id = protector.object_id
327
+ AND object_row.account_id = p_account_id
328
+ AND object_row.lifecycle_state = 'active'
329
+ AND current_version.file_id = p_file_id
330
+ AND current_version.version_generation = object_row.version_generation
331
+ AND source_row.lifecycle_state = 'active'
332
+ AND source_row.current_acl_generation = current_version.acl_generation
333
+ AND provider_row.lifecycle_state = 'active'
334
+ AND provider_row.provider_key = 'google-drive'
335
+ AND obligation.status = 'indexed'
336
+ AND obligation.acl_eligibility = 'eligible'
337
+ AND obligation.source_lifecycle_generation = source_row.lifecycle_generation
338
+ AND obligation.object_lifecycle_generation = object_row.lifecycle_generation
339
+ AND obligation.object_version_generation = object_row.version_generation
340
+ AND sync_state.account_id = p_account_id
341
+ AND sync_state.source_sync_generation >= obligation.source_sync_generation
342
+ AND sync_state.source_config_generation = obligation.source_config_generation
343
+ AND sync_state.source_lifecycle_generation = obligation.source_lifecycle_generation
344
+ AND sync_state.connection_id = evidence.connection_id
345
+ AND sync_state.connection_provider_domain = 'googleapis.com'
346
+ AND sync_state.connection_kind = 'oauth2'
347
+ AND sync_state.connection_owner_subject_id = source_connection.subject_id
348
+ AND sync_state.reconnect_required = false
349
+ AND evidence.account_id = p_account_id
350
+ AND evidence.knowledge_document_version_id = current_version.id
351
+ AND evidence.document_id = current_version.document_id
352
+ AND evidence.file_id = p_file_id
353
+ AND evidence.source_lifecycle_generation = source_row.lifecycle_generation
354
+ AND evidence.object_lifecycle_generation = object_row.lifecycle_generation
355
+ AND evidence.object_version_generation = object_row.version_generation
356
+ AND evidence.provider_revision IS NOT DISTINCT FROM
357
+ current_version.source_metadata->>'providerRevision'
358
+ AND evidence.eligibility = 'eligible'
359
+ AND evidence.observed_at <= pg_catalog.statement_timestamp()
360
+ AND evidence.expires_at > pg_catalog.statement_timestamp()
361
+ AND source_connection.account_id = p_account_id
362
+ AND source_connection.subject_id IS NOT NULL
363
+ AND source_connection.provider_domain = 'googleapis.com'
364
+ AND source_connection.kind = 'oauth2'
365
+ AND source_connection.status = 'active'
366
+ AND source_connection.version >= evidence.connection_version
367
+ AND coalesce(source_connection.metadata #>> '{lifecycle,state}', 'active') = 'active'
368
+ AND source_connection.metadata->>'accessMode' = 'readonly'
369
+ AND encode(sha256(convert_to(
370
+ 'permission:' || lower(btrim(source_connection.metadata->>'googlePermissionId')),
371
+ 'UTF8'
372
+ )), 'hex') = evidence.source_principal_hash
373
+ AND (
374
+ source_connection.granted_scopes ? 'https://www.googleapis.com/auth/drive'
375
+ OR source_connection.granted_scopes ? 'https://www.googleapis.com/auth/drive.readonly'
376
+ )
377
+ AND (
378
+ source_connection.subject_id = p_subject_id
379
+ OR EXISTS (
380
+ SELECT 1
381
+ FROM connections viewer_connection
382
+ JOIN google_drive_object_acl_principals principal
383
+ ON principal.evidence_id = evidence.id
384
+ WHERE viewer_connection.account_id = p_account_id
385
+ AND viewer_connection.subject_id = p_subject_id
386
+ AND viewer_connection.provider_domain = 'googleapis.com'
387
+ AND viewer_connection.kind = 'oauth2'
388
+ AND viewer_connection.status = 'active'
389
+ AND coalesce(viewer_connection.metadata #>> '{lifecycle,state}', 'active') = 'active'
390
+ AND viewer_connection.metadata->>'accessMode' = 'readonly'
391
+ AND (
392
+ viewer_connection.granted_scopes ? 'https://www.googleapis.com/auth/drive'
393
+ OR viewer_connection.granted_scopes ? 'https://www.googleapis.com/auth/drive.readonly'
394
+ )
395
+ AND (principal.expiration_time IS NULL
396
+ OR principal.expiration_time > pg_catalog.statement_timestamp())
397
+ AND (
398
+ principal.principal_type = 'anyone'
399
+ OR (
400
+ principal.principal_type = 'user'
401
+ AND (
402
+ principal.permission_id_hash = encode(sha256(convert_to(
403
+ 'permission:' || lower(btrim(
404
+ viewer_connection.metadata->>'googlePermissionId'
405
+ )), 'UTF8'
406
+ )), 'hex')
407
+ OR principal.email_hash = encode(sha256(convert_to(
408
+ 'email:' || lower(btrim(viewer_connection.metadata->>'googleEmail')),
409
+ 'UTF8'
410
+ )), 'hex')
411
+ )
412
+ )
413
+ OR (
414
+ principal.principal_type = 'domain'
415
+ AND principal.domain_hash = encode(sha256(convert_to(
416
+ 'domain:' || split_part(
417
+ lower(btrim(viewer_connection.metadata->>'googleEmail')), '@', 2
418
+ ), 'UTF8'
419
+ )), 'hex')
420
+ )
421
+ )
422
+ )
423
+ )
424
+ )
425
+ ) INTO authorized;
426
+ END IF;
427
+
428
+ DELETE FROM opengeni_private.google_drive_object_acl_runtime_capabilities
429
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
430
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
431
+ AND capability_kind = 'authorize';
432
+ RETURN authorized;
433
+ EXCEPTION WHEN OTHERS THEN
434
+ DELETE FROM opengeni_private.google_drive_object_acl_runtime_capabilities
435
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
436
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
437
+ AND capability_kind = 'authorize';
438
+ RAISE;
439
+ END;
440
+ END;
441
+ $body$;
442
+ $ddl$, data_schema);
443
+
444
+ EXECUTE format($ddl$
445
+ CREATE OR REPLACE FUNCTION %1$I.google_drive_document_citation(
446
+ p_account_id uuid,
447
+ p_request_workspace_id uuid,
448
+ p_subject_id text,
449
+ p_document_id uuid,
450
+ p_file_id uuid
451
+ ) RETURNS jsonb
452
+ LANGUAGE plpgsql SECURITY DEFINER
453
+ SET search_path = %1$I, pg_catalog
454
+ AS $body$
455
+ DECLARE citation jsonb;
456
+ BEGIN
457
+ INSERT INTO opengeni_private.google_drive_object_acl_runtime_capabilities (
458
+ backend_pid, transaction_id, capability_kind
459
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'citation')
460
+ ON CONFLICT DO NOTHING;
461
+ BEGIN
462
+ IF NOT %1$I.google_drive_file_authorized(
463
+ p_account_id, p_request_workspace_id, p_subject_id, p_file_id
464
+ ) THEN
465
+ DELETE FROM opengeni_private.google_drive_object_acl_runtime_capabilities
466
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
467
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
468
+ AND capability_kind = 'citation';
469
+ RETURN NULL;
470
+ END IF;
471
+ SELECT jsonb_strip_nulls(jsonb_build_object(
472
+ 'provider', 'google_drive',
473
+ 'externalObjectId', obligation.external_object_id,
474
+ 'providerRevision', evidence.provider_revision,
475
+ 'sourceVersion', current_version.external_version_id,
476
+ 'driveId', evidence.drive_id,
477
+ 'deepLink', obligation.citation_locator->>'sourceUri',
478
+ 'aclRevision', evidence.acl_revision,
479
+ 'authorizationObservedAt', evidence.observed_at,
480
+ 'authorizationExpiresAt', evidence.expires_at,
481
+ 'reauthorizedAt', pg_catalog.statement_timestamp()
482
+ ))
483
+ FROM knowledge_source_objects object_row
484
+ JOIN knowledge_document_versions current_version
485
+ ON current_version.id = object_row.current_version_id
486
+ AND current_version.object_id = object_row.id
487
+ JOIN knowledge_sources source_row ON source_row.id = object_row.source_id
488
+ JOIN knowledge_providers provider_row ON provider_row.id = source_row.provider_id
489
+ JOIN knowledge_source_sync_index_obligations obligation
490
+ ON obligation.knowledge_document_version_id = current_version.id
491
+ AND obligation.document_id = p_document_id
492
+ JOIN google_drive_object_acl_evidence evidence
493
+ ON evidence.id = obligation.google_drive_acl_evidence_id
494
+ AND evidence.index_obligation_id = obligation.id
495
+ WHERE current_version.account_id = p_account_id
496
+ AND current_version.document_id = p_document_id
497
+ AND current_version.file_id = p_file_id
498
+ AND provider_row.provider_key = 'google-drive'
499
+ AND object_row.lifecycle_state = 'active'
500
+ AND source_row.lifecycle_state = 'active'
501
+ AND obligation.status = 'indexed'
502
+ AND obligation.acl_eligibility = 'eligible'
503
+ AND evidence.eligibility = 'eligible'
504
+ AND evidence.expires_at > pg_catalog.statement_timestamp()
505
+ ORDER BY evidence.created_at DESC, evidence.id DESC
506
+ LIMIT 1
507
+ INTO citation;
508
+ DELETE FROM opengeni_private.google_drive_object_acl_runtime_capabilities
509
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
510
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
511
+ AND capability_kind = 'citation';
512
+ RETURN citation;
513
+ EXCEPTION WHEN OTHERS THEN
514
+ DELETE FROM opengeni_private.google_drive_object_acl_runtime_capabilities
515
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
516
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
517
+ AND capability_kind = 'citation';
518
+ RAISE;
519
+ END;
520
+ END;
521
+ $body$;
522
+ $ddl$, data_schema);
523
+
524
+ EXECUTE format(
525
+ 'REVOKE ALL ON FUNCTION %I.google_drive_file_authorized(uuid,uuid,text,uuid) FROM PUBLIC',
526
+ data_schema
527
+ );
528
+ EXECUTE format(
529
+ 'REVOKE ALL ON FUNCTION %I.google_drive_document_citation(uuid,uuid,text,uuid,uuid) FROM PUBLIC',
530
+ data_schema
531
+ );
532
+ END
533
+ $google_drive_file_authority$;
534
+
535
+ DO $runtime_grants$
536
+ DECLARE data_schema text := current_schema();
537
+ BEGIN
538
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
539
+ GRANT SELECT, INSERT ON "google_drive_object_acl_evidence" TO opengeni_app;
540
+ GRANT SELECT, INSERT ON "google_drive_object_acl_principals" TO opengeni_app;
541
+ EXECUTE format(
542
+ 'GRANT EXECUTE ON FUNCTION %I.google_drive_file_authorized(uuid,uuid,text,uuid) TO opengeni_app',
543
+ data_schema
544
+ );
545
+ EXECUTE format(
546
+ 'GRANT EXECUTE ON FUNCTION %I.google_drive_document_citation(uuid,uuid,text,uuid,uuid) TO opengeni_app',
547
+ data_schema
548
+ );
549
+ END IF;
550
+ END
551
+ $runtime_grants$;
552
+
553
+ RESET statement_timeout;
554
+ RESET lock_timeout;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/db",
3
- "version": "0.36.1",
3
+ "version": "1.0.1",
4
4
  "description": "OpenGeni persistence: Drizzle schema, RLS-scoped query layer, the SQL migration runner, and role provisioning.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -70,10 +70,10 @@
70
70
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
71
71
  },
72
72
  "dependencies": {
73
- "@opengeni/codemode": "^0.4.2",
73
+ "@opengeni/codemode": "^0.4.4",
74
74
  "@opengeni/codex": "^0.2.17",
75
- "@opengeni/config": "^0.16.2",
76
- "@opengeni/contracts": "^0.50.0",
75
+ "@opengeni/config": "^0.16.4",
76
+ "@opengeni/contracts": "^1.0.1",
77
77
  "@opengeni/network": "^0.2.2",
78
78
  "drizzle-orm": "^0.45.2",
79
79
  "postgres": "^3.4.7"
@@ -91,6 +91,9 @@ export type PersistedEditableArtifactMaterializationJob = Readonly<{
91
91
  result: PersistedEditableArtifactMaterializationResult | null;
92
92
  }>;
93
93
 
94
+ export type ReadAuthorizedEditableArtifactMaterializationRequest = ExportContext &
95
+ Readonly<{ jobId: string }>;
96
+
94
97
  export type PersistedEditableArtifactExportSnapshot = Readonly<{
95
98
  modality: PersistedEditableArtifactExportModality;
96
99
  snapshotId: string;
@@ -490,6 +493,30 @@ export class PostgresEditableArtifactDurableExportStore {
490
493
  }
491
494
  }
492
495
 
496
+ /**
497
+ * Reads one canonical materialization through the same exact actor authority
498
+ * used by editable-artifact export. This is intentionally narrower than the
499
+ * general store API: publication may verify an already-returned immutable
500
+ * receipt, but it cannot manufacture or widen artifact authority.
501
+ */
502
+ export async function readAuthorizedEditableArtifactMaterialization(
503
+ db: Database,
504
+ input: ReadAuthorizedEditableArtifactMaterializationRequest,
505
+ ): Promise<PersistedEditableArtifactMaterializationJob | null> {
506
+ const context = validateContext(input);
507
+ const jobId = stableId(input.jobId, "job id");
508
+ return await withRlsContext(db, context.scope, async (tx) => {
509
+ const artifact = await lockArtifact(tx, context.scope, context.artifactId);
510
+ if (!artifact) return null;
511
+ const authorization = await authorize(tx, context);
512
+ if (!authorization.allowed || authorization.revision !== artifact.authorizationRevision) {
513
+ return null;
514
+ }
515
+ const loaded = await loadJob(tx, context.scope, context.artifactId, jobId, false);
516
+ return loaded?.job ?? null;
517
+ });
518
+ }
519
+
493
520
  async function authorize(
494
521
  tx: Database,
495
522
  request: ExportContext,