@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.
- package/dist/canonical-human-identities.js +3 -3
- package/dist/{chunk-HSOWSYOX.js → chunk-4SR4HKKA.js} +2 -2
- package/dist/{chunk-5KTIEDX7.js → chunk-6ZYKCRFO.js} +124 -16
- package/dist/chunk-6ZYKCRFO.js.map +1 -0
- package/dist/{chunk-VTPRIXKG.js → chunk-CUPM3FGB.js} +3 -3
- package/dist/{chunk-GYO7ED2Q.js → chunk-LTG3S6ZY.js} +2 -2
- package/dist/{chunk-VKLB2ZGI.js → chunk-NXAFLCQX.js} +81 -2
- package/dist/chunk-NXAFLCQX.js.map +1 -0
- package/dist/{chunk-FPVAD4CO.js → chunk-WD5ROSLL.js} +2 -2
- package/dist/{chunk-Z7VYMNPZ.js → chunk-ZWREYEWA.js} +2 -2
- package/dist/editable-artifact-durable-export.d.ts +10 -0
- package/dist/editable-artifact-durable-export.js +18 -3
- package/dist/editable-artifact-durable-export.js.map +1 -1
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +40 -8
- package/dist/index.js +509 -59
- package/dist/index.js.map +1 -1
- package/dist/knowledge-source-sync-schema.d.ts +730 -0
- package/dist/knowledge-source-sync.d.ts +60 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +3 -3
- package/dist/schema.d.ts +21 -4
- package/dist/schema.js +5 -1
- package/dist/session-queue-commands.d.ts +1 -1
- package/dist/session-realtime-ledger.d.ts +1 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/drizzle/0240_model_context_user_messages.sql +204 -0
- package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
- package/package.json +4 -4
- package/src/editable-artifact-durable-export.ts +27 -0
- package/src/index.ts +212 -13
- package/src/knowledge-source-sync-schema.ts +83 -0
- package/src/knowledge-source-sync.ts +530 -0
- package/src/provision-roles.ts +36 -0
- package/src/runtime-posture.ts +49 -1
- package/src/schema.ts +30 -7
- package/src/session-queue-commands.ts +13 -14
- package/src/session-realtime-context.ts +16 -0
- package/src/session-realtime-ledger.ts +53 -1
- package/dist/chunk-5KTIEDX7.js.map +0 -1
- package/dist/chunk-VKLB2ZGI.js.map +0 -1
- /package/dist/{chunk-HSOWSYOX.js.map → chunk-4SR4HKKA.js.map} +0 -0
- /package/dist/{chunk-VTPRIXKG.js.map → chunk-CUPM3FGB.js.map} +0 -0
- /package/dist/{chunk-GYO7ED2Q.js.map → chunk-LTG3S6ZY.js.map} +0 -0
- /package/dist/{chunk-FPVAD4CO.js.map → chunk-WD5ROSLL.js.map} +0 -0
- /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.
|
|
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.
|
|
73
|
+
"@opengeni/codemode": "^0.4.4",
|
|
74
74
|
"@opengeni/codex": "^0.2.17",
|
|
75
|
-
"@opengeni/config": "^0.16.
|
|
76
|
-
"@opengeni/contracts": "^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,
|