@opengeni/db 3.2.2 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-reconciliation.js +2 -2
- package/dist/{chunk-V2X2NK7T.js → chunk-5MPQZI43.js} +2675 -2540
- package/dist/{chunk-V2X2NK7T.js.map → chunk-5MPQZI43.js.map} +1 -1
- package/dist/{chunk-L3NT43Z5.js → chunk-7K5AVQUZ.js} +3 -3
- package/dist/{chunk-JYPBOJ2Y.js → chunk-AAOKWNHE.js} +4 -4
- package/dist/{chunk-D7LTIG33.js → chunk-B4RMLA2X.js} +2 -2
- package/dist/{chunk-OXO32LTK.js → chunk-CEJ3NQ3B.js} +11 -1
- package/dist/chunk-CEJ3NQ3B.js.map +1 -0
- package/dist/{chunk-AYZC65QU.js → chunk-CGSINPLW.js} +2 -2
- package/dist/{chunk-VCJAYIPH.js → chunk-FX2PSMGH.js} +2 -2
- package/dist/{chunk-HMKUJ6NI.js → chunk-HQWXEF77.js} +57 -9
- package/dist/chunk-HQWXEF77.js.map +1 -0
- package/dist/{chunk-V22DUH4C.js → chunk-HWEHZKHA.js} +5 -5
- package/dist/{chunk-6UU7OVUN.js → chunk-JTBJGSUZ.js} +37 -7
- package/dist/chunk-JTBJGSUZ.js.map +1 -0
- package/dist/{chunk-YH4GWEDM.js → chunk-KPC7I5WG.js} +2 -2
- package/dist/{chunk-XQHABE23.js → chunk-OWM6XG55.js} +4 -4
- package/dist/{chunk-YWHG45TK.js → chunk-PNEJVKKV.js} +6 -6
- package/dist/{chunk-4BAKPTPG.js → chunk-S74WULCK.js} +3 -3
- package/dist/{chunk-K6NT66NP.js → chunk-SDKFRIAN.js} +4 -4
- package/dist/{chunk-RCDMYTLP.js → chunk-UWS5DJQ6.js} +2 -2
- package/dist/{chunk-LRRGVHAQ.js → chunk-VUR5U5B3.js} +2 -2
- package/dist/{chunk-IF63BST7.js → chunk-Y4ERASEM.js} +2 -2
- package/dist/{chunk-VBG4TW5C.js → chunk-ZZOEKHGU.js} +2 -2
- package/dist/connect-attempts.js +3 -3
- package/dist/database.d.ts +9 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +93 -22
- package/dist/index.js +31 -19
- package/dist/insights-site-usage.d.ts +10 -0
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/mcp-operations.js +2 -2
- package/dist/migrate.js +19 -19
- package/dist/organization-integration-policy.js +3 -3
- package/dist/provision-roles.js +1 -1
- package/dist/retained-provider-commands.js +6 -6
- package/dist/schema.d.ts +102 -0
- package/dist/schema.js +1 -1
- package/dist/session-background-commands.js +5 -5
- package/dist/session-command-output.js +5 -5
- package/dist/session-event-slices.js +3 -3
- package/dist/session-mcp-credential-rotation.js +6 -6
- package/dist/session-tenancy.js +6 -6
- package/dist/site-publishing.d.ts +11 -0
- package/dist/{subscription-core-codex-4G4CCOJU.js → subscription-core-codex-HIAP7CY2.js} +6 -6
- package/dist/{subscription-core-codex-compat-64ACIZVP.js → subscription-core-codex-compat-IBERN7DU.js} +8 -8
- package/dist/video-generation.js +3 -3
- package/dist/workspace-tool-defaults.js +5 -5
- package/drizzle/0793_private_site_sessions.sql +166 -0
- package/drizzle/0794_site_ai_insights.sql +175 -0
- package/drizzle/0795_site_lifecycle_cancellation.sql +121 -0
- package/package.json +9 -9
- package/src/database.ts +44 -3
- package/src/index.ts +142 -11
- package/src/insights-site-usage.ts +37 -0
- package/src/provision-roles.ts +15 -0
- package/src/runtime-posture.ts +76 -7
- package/src/schema.ts +10 -0
- package/src/site-publishing.ts +35 -0
- package/dist/chunk-6UU7OVUN.js.map +0 -1
- package/dist/chunk-HMKUJ6NI.js.map +0 -1
- package/dist/chunk-OXO32LTK.js.map +0 -1
- /package/dist/{chunk-L3NT43Z5.js.map → chunk-7K5AVQUZ.js.map} +0 -0
- /package/dist/{chunk-JYPBOJ2Y.js.map → chunk-AAOKWNHE.js.map} +0 -0
- /package/dist/{chunk-D7LTIG33.js.map → chunk-B4RMLA2X.js.map} +0 -0
- /package/dist/{chunk-AYZC65QU.js.map → chunk-CGSINPLW.js.map} +0 -0
- /package/dist/{chunk-VCJAYIPH.js.map → chunk-FX2PSMGH.js.map} +0 -0
- /package/dist/{chunk-V22DUH4C.js.map → chunk-HWEHZKHA.js.map} +0 -0
- /package/dist/{chunk-YH4GWEDM.js.map → chunk-KPC7I5WG.js.map} +0 -0
- /package/dist/{chunk-XQHABE23.js.map → chunk-OWM6XG55.js.map} +0 -0
- /package/dist/{chunk-YWHG45TK.js.map → chunk-PNEJVKKV.js.map} +0 -0
- /package/dist/{chunk-4BAKPTPG.js.map → chunk-S74WULCK.js.map} +0 -0
- /package/dist/{chunk-K6NT66NP.js.map → chunk-SDKFRIAN.js.map} +0 -0
- /package/dist/{chunk-RCDMYTLP.js.map → chunk-UWS5DJQ6.js.map} +0 -0
- /package/dist/{chunk-LRRGVHAQ.js.map → chunk-VUR5U5B3.js.map} +0 -0
- /package/dist/{chunk-IF63BST7.js.map → chunk-Y4ERASEM.js.map} +0 -0
- /package/dist/{chunk-VBG4TW5C.js.map → chunk-ZZOEKHGU.js.map} +0 -0
- /package/dist/{subscription-core-codex-4G4CCOJU.js.map → subscription-core-codex-HIAP7CY2.js.map} +0 -0
- /package/dist/{subscription-core-codex-compat-64ACIZVP.js.map → subscription-core-codex-compat-IBERN7DU.js.map} +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Cancel-only host lifecycle commands reuse the native session control writer.
|
|
3
|
+
-- A private transaction-local witness admits its exact Site root/subtree; it
|
|
4
|
+
-- is never a viewer identity, bearer permission, or tenancy-inventory exception.
|
|
5
|
+
SET LOCAL lock_timeout = '5s';
|
|
6
|
+
SET LOCAL statement_timeout = '5min';
|
|
7
|
+
|
|
8
|
+
CREATE INDEX site_runtime_conversations_cancel_page_idx
|
|
9
|
+
ON site_runtime_conversations(account_id, workspace_id, site_id, session_id);
|
|
10
|
+
|
|
11
|
+
CREATE TABLE opengeni_private.site_session_cancellation_capabilities (
|
|
12
|
+
capability_id uuid NOT NULL UNIQUE,
|
|
13
|
+
target_schema oid NOT NULL,
|
|
14
|
+
backend_pid integer NOT NULL,
|
|
15
|
+
transaction_id xid8 NOT NULL,
|
|
16
|
+
account_id uuid NOT NULL,
|
|
17
|
+
workspace_id uuid NOT NULL,
|
|
18
|
+
site_id uuid NOT NULL,
|
|
19
|
+
root_session_id uuid NOT NULL,
|
|
20
|
+
subject_id text,
|
|
21
|
+
initiating_human_subject_id text,
|
|
22
|
+
PRIMARY KEY (backend_pid, transaction_id)
|
|
23
|
+
);
|
|
24
|
+
REVOKE ALL ON TABLE opengeni_private.site_session_cancellation_capabilities FROM PUBLIC;
|
|
25
|
+
|
|
26
|
+
DO $functions$
|
|
27
|
+
DECLARE data_schema text := current_schema();
|
|
28
|
+
BEGIN
|
|
29
|
+
EXECUTE format($ddl$
|
|
30
|
+
CREATE FUNCTION %1$I.site_session_cancellation_capability_active(
|
|
31
|
+
a uuid,w uuid,site uuid,root uuid
|
|
32
|
+
) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path=pg_catalog AS $fn$
|
|
33
|
+
SELECT EXISTS (
|
|
34
|
+
SELECT 1 FROM opengeni_private.site_session_cancellation_capabilities c
|
|
35
|
+
WHERE c.target_schema=%2$s::oid AND c.backend_pid=pg_backend_pid()
|
|
36
|
+
AND c.transaction_id=pg_current_xact_id_if_assigned()
|
|
37
|
+
AND c.account_id=a AND c.workspace_id=w AND c.site_id=site AND c.root_session_id=root
|
|
38
|
+
AND a=nullif(current_setting('opengeni.account_id',true),'')::uuid
|
|
39
|
+
AND w=nullif(current_setting('opengeni.workspace_id',true),'')::uuid
|
|
40
|
+
AND c.subject_id IS NOT DISTINCT FROM nullif(current_setting('opengeni.subject_id',true),'')
|
|
41
|
+
AND c.initiating_human_subject_id IS NOT DISTINCT FROM nullif(current_setting('opengeni.initiating_human_subject_id',true),'')
|
|
42
|
+
)
|
|
43
|
+
$fn$;
|
|
44
|
+
|
|
45
|
+
CREATE FUNCTION opengeni_private.begin_site_session_cancellation(a uuid,w uuid,site uuid,root uuid)
|
|
46
|
+
RETURNS uuid LANGUAGE plpgsql VOLATILE SECURITY DEFINER
|
|
47
|
+
SET search_path=pg_catalog,%1$I,opengeni_private,pg_temp AS $fn$
|
|
48
|
+
DECLARE token uuid:=gen_random_uuid(); actor text:=nullif(current_setting('opengeni.subject_id',true),'');
|
|
49
|
+
human text:=nullif(current_setting('opengeni.initiating_human_subject_id',true),'');
|
|
50
|
+
BEGIN
|
|
51
|
+
IF a IS NULL OR w IS NULL OR site IS NULL OR root IS NULL
|
|
52
|
+
OR a IS DISTINCT FROM nullif(current_setting('opengeni.account_id',true),'')::uuid
|
|
53
|
+
OR w IS DISTINCT FROM nullif(current_setting('opengeni.workspace_id',true),'')::uuid
|
|
54
|
+
OR actor LIKE 'site:%%' THEN
|
|
55
|
+
RAISE EXCEPTION 'Site lifecycle cancellation requires exact host scope' USING ERRCODE='42501';
|
|
56
|
+
END IF;
|
|
57
|
+
-- Trusted application lifecycle only. The mapping proves association
|
|
58
|
+
-- without granting a service principal transcript access.
|
|
59
|
+
IF NOT EXISTS(SELECT 1 FROM %1$I.site_runtime_conversations c
|
|
60
|
+
WHERE c.account_id=a AND c.workspace_id=w AND c.site_id=site AND c.session_id=root) THEN
|
|
61
|
+
RAISE EXCEPTION 'Site cancellation target is unavailable' USING ERRCODE='42501';
|
|
62
|
+
END IF;
|
|
63
|
+
INSERT INTO opengeni_private.site_session_cancellation_capabilities
|
|
64
|
+
VALUES(token,%2$s::oid,pg_backend_pid(),pg_current_xact_id(),a,w,site,root,actor,human);
|
|
65
|
+
-- Root identity avoids the generic hidden-ancestor reader entirely.
|
|
66
|
+
IF NOT EXISTS(SELECT 1 FROM %1$I.sessions s WHERE s.account_id=a AND s.workspace_id=w
|
|
67
|
+
AND s.id=root AND s.site_id=site AND s.site_access_root_id=root
|
|
68
|
+
AND s.root_session_id=root AND s.parent_session_id IS NULL) THEN
|
|
69
|
+
DELETE FROM opengeni_private.site_session_cancellation_capabilities WHERE capability_id=token;
|
|
70
|
+
RETURN NULL;
|
|
71
|
+
END IF;
|
|
72
|
+
RETURN token;
|
|
73
|
+
END
|
|
74
|
+
$fn$;
|
|
75
|
+
|
|
76
|
+
CREATE FUNCTION opengeni_private.end_site_session_cancellation(token uuid)
|
|
77
|
+
RETURNS void LANGUAGE sql VOLATILE SECURITY DEFINER SET search_path=pg_catalog AS $fn$
|
|
78
|
+
DELETE FROM opengeni_private.site_session_cancellation_capabilities c
|
|
79
|
+
WHERE c.capability_id=token AND c.target_schema=%2$s::oid
|
|
80
|
+
AND c.backend_pid=pg_backend_pid() AND c.transaction_id=pg_current_xact_id_if_assigned()
|
|
81
|
+
$fn$;
|
|
82
|
+
$ddl$,data_schema,current_schema()::regnamespace::oid);
|
|
83
|
+
END
|
|
84
|
+
$functions$;
|
|
85
|
+
|
|
86
|
+
-- Preserve installed native/private and Site predicates. Both restrictive
|
|
87
|
+
-- gates admit only this exact command witness, never general inventory.
|
|
88
|
+
DO $policies$
|
|
89
|
+
DECLARE p record; n integer:=0;
|
|
90
|
+
allowance text:=format('%I.site_session_cancellation_capability_active(account_id,workspace_id,site_id,site_access_root_id)',current_schema());
|
|
91
|
+
BEGIN
|
|
92
|
+
FOR p IN SELECT polname,pg_get_expr(polqual,polrelid) qual,
|
|
93
|
+
pg_get_expr(polwithcheck,polrelid) check_expr,polpermissive,polcmd
|
|
94
|
+
FROM pg_policy WHERE polrelid='sessions'::regclass
|
|
95
|
+
AND polname IN ('session_visibility_isolation','site_viewer_isolation') LOOP
|
|
96
|
+
IF p.polpermissive OR p.polcmd<>'*' OR p.qual IS NULL OR p.check_expr IS NULL THEN
|
|
97
|
+
RAISE EXCEPTION 'Unexpected session cancellation policy contract' USING ERRCODE='55000';
|
|
98
|
+
END IF;
|
|
99
|
+
EXECUTE format('ALTER POLICY %I ON %I.sessions USING ((%s) OR %s) WITH CHECK ((%s) OR %s)',
|
|
100
|
+
p.polname,current_schema(),p.qual,allowance,p.check_expr,allowance);
|
|
101
|
+
n:=n+1;
|
|
102
|
+
END LOOP;
|
|
103
|
+
IF n<>2 THEN RAISE EXCEPTION 'Missing session cancellation policy contract' USING ERRCODE='55000'; END IF;
|
|
104
|
+
END
|
|
105
|
+
$policies$;
|
|
106
|
+
|
|
107
|
+
REVOKE ALL ON FUNCTION opengeni_private.begin_site_session_cancellation(uuid,uuid,uuid,uuid) FROM PUBLIC;
|
|
108
|
+
REVOKE ALL ON FUNCTION opengeni_private.end_site_session_cancellation(uuid) FROM PUBLIC;
|
|
109
|
+
-- The policy predicate is value-free; callers cannot mint its witness.
|
|
110
|
+
GRANT EXECUTE ON FUNCTION site_session_cancellation_capability_active(uuid,uuid,uuid,uuid) TO PUBLIC;
|
|
111
|
+
DO $acl$
|
|
112
|
+
DECLARE role_name text;
|
|
113
|
+
BEGIN
|
|
114
|
+
FOR role_name IN SELECT DISTINCT r.rolname FROM pg_roles r
|
|
115
|
+
JOIN jsonb_array_elements_text(current_setting('opengeni.migration_application_roles')::jsonb) configured(value)
|
|
116
|
+
ON r.rolname=configured.value LOOP
|
|
117
|
+
EXECUTE format('REVOKE ALL ON TABLE opengeni_private.site_session_cancellation_capabilities FROM %I',role_name);
|
|
118
|
+
EXECUTE format('GRANT EXECUTE ON FUNCTION opengeni_private.begin_site_session_cancellation(uuid,uuid,uuid,uuid),opengeni_private.end_site_session_cancellation(uuid) TO %I',role_name);
|
|
119
|
+
END LOOP;
|
|
120
|
+
END
|
|
121
|
+
$acl$;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/db",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
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": {
|
|
@@ -117,14 +117,14 @@
|
|
|
117
117
|
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
118
118
|
},
|
|
119
119
|
"dependencies": {
|
|
120
|
-
"@opengeni/codemode": "3.
|
|
121
|
-
"@opengeni/codex": "3.
|
|
122
|
-
"@opengeni/config": "3.
|
|
123
|
-
"@opengeni/contracts": "3.
|
|
124
|
-
"@opengeni/network": "3.
|
|
125
|
-
"@opengeni/observability": "3.
|
|
126
|
-
"@opengeni/subscriptions": "3.
|
|
127
|
-
"@opengeni/xai-subscription": "3.
|
|
120
|
+
"@opengeni/codemode": "3.3.0",
|
|
121
|
+
"@opengeni/codex": "3.3.0",
|
|
122
|
+
"@opengeni/config": "3.3.0",
|
|
123
|
+
"@opengeni/contracts": "3.3.0",
|
|
124
|
+
"@opengeni/network": "3.3.0",
|
|
125
|
+
"@opengeni/observability": "3.3.0",
|
|
126
|
+
"@opengeni/subscriptions": "3.3.0",
|
|
127
|
+
"@opengeni/xai-subscription": "3.3.0",
|
|
128
128
|
"drizzle-orm": "^0.45.2",
|
|
129
129
|
"postgres": "^3.4.7"
|
|
130
130
|
},
|
package/src/database.ts
CHANGED
|
@@ -63,8 +63,20 @@ export type SessionRlsActorContext = {
|
|
|
63
63
|
/** Host-verified personal file ownership, never a request-supplied subject. */
|
|
64
64
|
privateFileOwnerSubjectId?: string | null;
|
|
65
65
|
initiatingHumanSubjectId?: string | null;
|
|
66
|
+
/** Root reconstructed from a verified live agent attempt, never page input. */
|
|
67
|
+
agentRootSessionId?: string | null;
|
|
66
68
|
};
|
|
67
69
|
|
|
70
|
+
/** Request-local proof from the signed published-Site gateway and live viewer cookie. */
|
|
71
|
+
export type SiteViewerRlsContext = Readonly<{ siteId: string; principal: string }>;
|
|
72
|
+
const siteViewerRlsContext = new AsyncLocalStorage<SiteViewerRlsContext>();
|
|
73
|
+
export function currentSiteViewerRlsContext(): SiteViewerRlsContext | undefined {
|
|
74
|
+
return siteViewerRlsContext.getStore();
|
|
75
|
+
}
|
|
76
|
+
export function withSiteViewerRlsContext<T>(context: SiteViewerRlsContext, run: () => T): T {
|
|
77
|
+
return siteViewerRlsContext.run(Object.freeze({ ...context }), run);
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
const sessionRlsActorContext = new AsyncLocalStorage<SessionRlsActorContext>();
|
|
69
81
|
export function currentSessionAttachmentReadAccess(): SessionAttachmentReadAccess | undefined {
|
|
70
82
|
return sessionRlsActorContext.getStore()?.sessionAttachmentReadAccess;
|
|
@@ -94,6 +106,8 @@ export function currentSessionRlsActorIdentityKey(): string | null {
|
|
|
94
106
|
actor.initiatingHumanSubjectId ?? null,
|
|
95
107
|
actor.privateFileOwnerSubjectId ?? null,
|
|
96
108
|
actor.sessionAttachmentReadAccess ?? null,
|
|
109
|
+
actor.agentRootSessionId ?? null,
|
|
110
|
+
siteViewerRlsContext.getStore() ?? null,
|
|
97
111
|
]);
|
|
98
112
|
}
|
|
99
113
|
|
|
@@ -144,6 +158,9 @@ type RlsContextSettings = {
|
|
|
144
158
|
initiatingHumanSubjectId: string;
|
|
145
159
|
personalResourceHumanSubjectId: string;
|
|
146
160
|
personalResourceActorSubjectId: string;
|
|
161
|
+
agentRootSessionId: string;
|
|
162
|
+
siteId: string;
|
|
163
|
+
siteViewerPrincipal: string;
|
|
147
164
|
};
|
|
148
165
|
|
|
149
166
|
/**
|
|
@@ -475,8 +492,14 @@ export async function setRlsContext(db: Database, context: RlsContext): Promise<
|
|
|
475
492
|
set_config('opengeni.pending_tool_event_output_v1', '1', true),
|
|
476
493
|
set_config('opengeni.session_variable_set_attachments_v1', '1', true),
|
|
477
494
|
set_config('opengeni.shared_personal_choice_v1', '1', true),
|
|
495
|
+
set_config('opengeni.site_session_audience_v1', '1', true),
|
|
478
496
|
set_config('jit', 'off', true)`);
|
|
479
497
|
const sessionActor = sessionRlsActorContext.getStore();
|
|
498
|
+
const siteViewer = siteViewerRlsContext.getStore();
|
|
499
|
+
await db.execute(sql`select
|
|
500
|
+
set_config('opengeni.agent_root_session_id', ${sessionActor?.agentRootSessionId ?? ""}, true),
|
|
501
|
+
set_config('opengeni.site_id', ${siteViewer?.siteId ?? ""}, true),
|
|
502
|
+
set_config('opengeni.site_viewer_principal', ${siteViewer?.principal ?? ""}, true)`);
|
|
480
503
|
if (sessionActor) {
|
|
481
504
|
await setSubjectRlsContext(db, sessionActor.subjectId);
|
|
482
505
|
await db.execute(
|
|
@@ -498,6 +521,9 @@ async function readRlsContextSettings(db: Database): Promise<RlsContextSettings>
|
|
|
498
521
|
initiating_human_subject_id: string | null;
|
|
499
522
|
personal_resource_human_subject_id: string | null;
|
|
500
523
|
personal_resource_actor_subject_id: string | null;
|
|
524
|
+
agent_root_session_id: string | null;
|
|
525
|
+
site_id: string | null;
|
|
526
|
+
site_viewer_principal: string | null;
|
|
501
527
|
}>(
|
|
502
528
|
db,
|
|
503
529
|
sql`select
|
|
@@ -507,7 +533,10 @@ async function readRlsContextSettings(db: Database): Promise<RlsContextSettings>
|
|
|
507
533
|
current_setting('opengeni.private_file_owner', true) as private_file_owner,
|
|
508
534
|
current_setting('opengeni.initiating_human_subject_id', true) as initiating_human_subject_id,
|
|
509
535
|
current_setting('opengeni.personal_resource_human_subject_id', true) as personal_resource_human_subject_id,
|
|
510
|
-
current_setting('opengeni.personal_resource_actor_subject_id', true) as personal_resource_actor_subject_id
|
|
536
|
+
current_setting('opengeni.personal_resource_actor_subject_id', true) as personal_resource_actor_subject_id,
|
|
537
|
+
current_setting('opengeni.agent_root_session_id', true) as agent_root_session_id,
|
|
538
|
+
current_setting('opengeni.site_id', true) as site_id,
|
|
539
|
+
current_setting('opengeni.site_viewer_principal', true) as site_viewer_principal`,
|
|
511
540
|
);
|
|
512
541
|
return {
|
|
513
542
|
accountId: settings?.account_id ?? "",
|
|
@@ -517,6 +546,9 @@ async function readRlsContextSettings(db: Database): Promise<RlsContextSettings>
|
|
|
517
546
|
initiatingHumanSubjectId: settings?.initiating_human_subject_id ?? "",
|
|
518
547
|
personalResourceHumanSubjectId: settings?.personal_resource_human_subject_id ?? "",
|
|
519
548
|
personalResourceActorSubjectId: settings?.personal_resource_actor_subject_id ?? "",
|
|
549
|
+
agentRootSessionId: settings?.agent_root_session_id ?? "",
|
|
550
|
+
siteId: settings?.site_id ?? "",
|
|
551
|
+
siteViewerPrincipal: settings?.site_viewer_principal ?? "",
|
|
520
552
|
};
|
|
521
553
|
}
|
|
522
554
|
|
|
@@ -547,6 +579,9 @@ async function restoreRlsContextSettings(
|
|
|
547
579
|
initiating_human_subject_id: string;
|
|
548
580
|
personal_resource_human_subject_id: string;
|
|
549
581
|
personal_resource_actor_subject_id: string;
|
|
582
|
+
agent_root_session_id: string;
|
|
583
|
+
site_id: string;
|
|
584
|
+
site_viewer_principal: string;
|
|
550
585
|
}>(
|
|
551
586
|
db,
|
|
552
587
|
sql`select
|
|
@@ -556,7 +591,10 @@ async function restoreRlsContextSettings(
|
|
|
556
591
|
set_config('opengeni.private_file_owner', ${settings.privateFileOwnerSubjectId}, true) as private_file_owner,
|
|
557
592
|
set_config('opengeni.initiating_human_subject_id', ${settings.initiatingHumanSubjectId}, true) as initiating_human_subject_id,
|
|
558
593
|
set_config('opengeni.personal_resource_human_subject_id', ${settings.personalResourceHumanSubjectId}, true) as personal_resource_human_subject_id,
|
|
559
|
-
set_config('opengeni.personal_resource_actor_subject_id', ${settings.personalResourceActorSubjectId}, true) as personal_resource_actor_subject_id
|
|
594
|
+
set_config('opengeni.personal_resource_actor_subject_id', ${settings.personalResourceActorSubjectId}, true) as personal_resource_actor_subject_id,
|
|
595
|
+
set_config('opengeni.agent_root_session_id', ${settings.agentRootSessionId}, true) as agent_root_session_id,
|
|
596
|
+
set_config('opengeni.site_id', ${settings.siteId}, true) as site_id,
|
|
597
|
+
set_config('opengeni.site_viewer_principal', ${settings.siteViewerPrincipal}, true) as site_viewer_principal`,
|
|
560
598
|
);
|
|
561
599
|
if (
|
|
562
600
|
restored?.account_id !== settings.accountId ||
|
|
@@ -565,7 +603,10 @@ async function restoreRlsContextSettings(
|
|
|
565
603
|
restored.private_file_owner !== settings.privateFileOwnerSubjectId ||
|
|
566
604
|
restored.initiating_human_subject_id !== settings.initiatingHumanSubjectId ||
|
|
567
605
|
restored.personal_resource_human_subject_id !== settings.personalResourceHumanSubjectId ||
|
|
568
|
-
restored.personal_resource_actor_subject_id !== settings.personalResourceActorSubjectId
|
|
606
|
+
restored.personal_resource_actor_subject_id !== settings.personalResourceActorSubjectId ||
|
|
607
|
+
restored.agent_root_session_id !== settings.agentRootSessionId ||
|
|
608
|
+
restored.site_id !== settings.siteId ||
|
|
609
|
+
restored.site_viewer_principal !== settings.siteViewerPrincipal
|
|
569
610
|
) {
|
|
570
611
|
throw new Error("RLS context could not be restored after a nested scope");
|
|
571
612
|
}
|
package/src/index.ts
CHANGED
|
@@ -518,6 +518,7 @@ export * from "./site-data";
|
|
|
518
518
|
export * from "./site-publishing";
|
|
519
519
|
export { withSiteRuntimeAdmission } from "./site-runtime-admission";
|
|
520
520
|
export * from "./site-platform";
|
|
521
|
+
export * from "./insights-site-usage";
|
|
521
522
|
export * from "./scheduled-slack-bot-messages";
|
|
522
523
|
export * from "./organization-signup-use-cases";
|
|
523
524
|
export * from "./site-sql";
|
|
@@ -1011,6 +1012,7 @@ import {
|
|
|
1011
1012
|
workspaceControlLockBudget,
|
|
1012
1013
|
workspaceControlRequestLockTimeoutMs,
|
|
1013
1014
|
lockWorkspaceInferenceControl,
|
|
1015
|
+
mutateSessionControlInTransaction,
|
|
1014
1016
|
registerInternalUpdateWakeInTransaction,
|
|
1015
1017
|
registerSessionWorkflowWakeInTransaction,
|
|
1016
1018
|
SESSION_DISCOVERY_CONTROL_TITLE_MAX_CHARS,
|
|
@@ -1245,6 +1247,7 @@ export * from "./model-catalog";
|
|
|
1245
1247
|
|
|
1246
1248
|
import {
|
|
1247
1249
|
dbBindingFor,
|
|
1250
|
+
isTransactionHandle,
|
|
1248
1251
|
rawRows,
|
|
1249
1252
|
retryRlsPersistence,
|
|
1250
1253
|
retryWorkspacePersistence,
|
|
@@ -1301,6 +1304,9 @@ export {
|
|
|
1301
1304
|
} from "./database";
|
|
1302
1305
|
export {
|
|
1303
1306
|
currentSessionRlsActorIdentityKey,
|
|
1307
|
+
currentSessionRlsActorContext,
|
|
1308
|
+
currentSiteViewerRlsContext,
|
|
1309
|
+
withSiteViewerRlsContext,
|
|
1304
1310
|
currentSessionRlsActorInitiatingHumanSubjectId,
|
|
1305
1311
|
withSessionRlsActorContext,
|
|
1306
1312
|
} from "./database";
|
|
@@ -29679,7 +29685,7 @@ async function createSessionInTransaction(
|
|
|
29679
29685
|
);
|
|
29680
29686
|
const createIdempotencyKey = input.createIdempotencyKey ?? null;
|
|
29681
29687
|
const createRequestedVisibility = input.visibility ?? "workspace_shared";
|
|
29682
|
-
if (createRequestedVisibility === "user_private") {
|
|
29688
|
+
if (createRequestedVisibility === "user_private" || sessionMetadata._opengeniSiteOrigin) {
|
|
29683
29689
|
// Private creation later proves the owner's live organization membership
|
|
29684
29690
|
// and, for a fresh top-level organization session, reads the mutable
|
|
29685
29691
|
// owner/admin enablement setting. Serialize both checks with organization
|
|
@@ -30883,6 +30889,10 @@ export type SessionAuthorityProjection = SessionAccessProjection & {
|
|
|
30883
30889
|
authorityEpoch: number;
|
|
30884
30890
|
visibility: "user_private" | "workspace_shared";
|
|
30885
30891
|
ownerSubjectId: string | null;
|
|
30892
|
+
siteId: string | null;
|
|
30893
|
+
siteAccessRootId: string | null;
|
|
30894
|
+
siteViewerPrincipal: string | null;
|
|
30895
|
+
siteOwnerSubjectId: string | null;
|
|
30886
30896
|
};
|
|
30887
30897
|
|
|
30888
30898
|
type SessionAccessRow = Pick<
|
|
@@ -30924,6 +30934,10 @@ export async function getSessionAuthorityProjection(
|
|
|
30924
30934
|
visibility: schema.sessions.visibility,
|
|
30925
30935
|
authorityEpoch: schema.sessions.authorityEpoch,
|
|
30926
30936
|
ownerSubjectId: schema.sessions.ownerSubjectId,
|
|
30937
|
+
siteId: schema.sessions.siteId,
|
|
30938
|
+
siteAccessRootId: schema.sessions.siteAccessRootId,
|
|
30939
|
+
siteViewerPrincipal: schema.sessions.siteViewerPrincipal,
|
|
30940
|
+
siteOwnerSubjectId: schema.sessions.siteOwnerSubjectId,
|
|
30927
30941
|
agentAccess: schema.sessions.agentAccess,
|
|
30928
30942
|
scopeSubjectId: schema.sessions.scopeSubjectId,
|
|
30929
30943
|
memoryScope: schema.sessions.memoryScope,
|
|
@@ -30938,6 +30952,10 @@ export async function getSessionAuthorityProjection(
|
|
|
30938
30952
|
rootSessionId: row.rootSessionId,
|
|
30939
30953
|
visibility: row.visibility as SessionAuthorityProjection["visibility"],
|
|
30940
30954
|
ownerSubjectId: row.ownerSubjectId ?? null,
|
|
30955
|
+
siteId: row.siteId ?? null,
|
|
30956
|
+
siteAccessRootId: row.siteAccessRootId ?? null,
|
|
30957
|
+
siteViewerPrincipal: row.siteViewerPrincipal ?? null,
|
|
30958
|
+
siteOwnerSubjectId: row.siteOwnerSubjectId ?? null,
|
|
30941
30959
|
agentAccess: sessionAgentAccessFromRow(row),
|
|
30942
30960
|
scopeSubjectId: sessionEndUserFromRow(row),
|
|
30943
30961
|
memoryScope: sessionMemoryScopeFromRow(row),
|
|
@@ -32548,7 +32566,17 @@ function sessionFilters(
|
|
|
32548
32566
|
}
|
|
32549
32567
|
if (options.originSiteId) {
|
|
32550
32568
|
filters.push(
|
|
32551
|
-
|
|
32569
|
+
eq(schema.sessions.siteId, options.originSiteId),
|
|
32570
|
+
sql`${schema.sessions.siteAccessRootId} is not null`,
|
|
32571
|
+
);
|
|
32572
|
+
} else {
|
|
32573
|
+
// App-internal execution is not ordinary workspace conversation discovery.
|
|
32574
|
+
// This is presentation scope only: native ownership and Site RLS still apply.
|
|
32575
|
+
const ownRoot = options.authorizationScope?.agentAccessViewer?.callerRootSessionId;
|
|
32576
|
+
filters.push(
|
|
32577
|
+
ownRoot
|
|
32578
|
+
? sql`(${schema.sessions.siteAccessRootId} is null OR ${schema.sessions.rootSessionId} = ${ownRoot}::uuid)`
|
|
32579
|
+
: sql`${schema.sessions.siteAccessRootId} is null`,
|
|
32552
32580
|
);
|
|
32553
32581
|
}
|
|
32554
32582
|
const archivedRoot = sql`exists (
|
|
@@ -33280,7 +33308,7 @@ async function readSessionListForSubject(
|
|
|
33280
33308
|
throw new SessionListCursorError();
|
|
33281
33309
|
}
|
|
33282
33310
|
let nextOffset: number | null = null;
|
|
33283
|
-
|
|
33311
|
+
{
|
|
33284
33312
|
// A host may revoke rows between pages. Scan the immutable snapshot
|
|
33285
33313
|
// in bounded database-filtered batches until this page is full plus
|
|
33286
33314
|
// one authorized lookahead; never hydrate a stale broad slice and
|
|
@@ -33301,7 +33329,10 @@ async function readSessionListForSubject(
|
|
|
33301
33329
|
and(
|
|
33302
33330
|
eq(schema.sessions.workspaceId, workspaceId),
|
|
33303
33331
|
inArray(schema.sessions.id, candidates),
|
|
33304
|
-
|
|
33332
|
+
sql`${schema.sessions.siteAccessRootId} is null`,
|
|
33333
|
+
...(options.authorizationScope
|
|
33334
|
+
? [sessionAuthorizationScopeFilter(options.authorizationScope)]
|
|
33335
|
+
: []),
|
|
33305
33336
|
),
|
|
33306
33337
|
);
|
|
33307
33338
|
const allowed = new Set(allowedRows.map((row) => row.id));
|
|
@@ -33318,12 +33349,6 @@ async function readSessionListForSubject(
|
|
|
33318
33349
|
if (visible.length > limit) {
|
|
33319
33350
|
nextOffset = visible[limit - 1]!.offsetAfter;
|
|
33320
33351
|
}
|
|
33321
|
-
} else {
|
|
33322
|
-
pageIds = snapshot.ordinarySessionIds.slice(cursor.offset, cursor.offset + limit);
|
|
33323
|
-
const candidateOffset = cursor.offset + pageIds.length;
|
|
33324
|
-
if (candidateOffset < snapshot.ordinarySessionIds.length) {
|
|
33325
|
-
nextOffset = candidateOffset;
|
|
33326
|
-
}
|
|
33327
33352
|
}
|
|
33328
33353
|
if (nextOffset !== null) {
|
|
33329
33354
|
nextCursor = encodeSessionListCursor({
|
|
@@ -34755,7 +34780,15 @@ async function selectSessionDiscoveryPageRows(
|
|
|
34755
34780
|
}
|
|
34756
34781
|
if (options.filters.originSiteId) {
|
|
34757
34782
|
authorizationFilters.push(
|
|
34758
|
-
|
|
34783
|
+
eq(schema.sessions.siteId, options.filters.originSiteId),
|
|
34784
|
+
sql`${schema.sessions.siteAccessRootId} is not null`,
|
|
34785
|
+
);
|
|
34786
|
+
} else {
|
|
34787
|
+
const ownRoot = options.authorizationScope?.agentAccessViewer?.callerRootSessionId;
|
|
34788
|
+
authorizationFilters.push(
|
|
34789
|
+
ownRoot
|
|
34790
|
+
? sql`(${schema.sessions.siteAccessRootId} is null OR ${schema.sessions.rootSessionId} = ${ownRoot}::uuid)`
|
|
34791
|
+
: sql`${schema.sessions.siteAccessRootId} is null`,
|
|
34759
34792
|
);
|
|
34760
34793
|
}
|
|
34761
34794
|
if (options.filters.activeOnly) {
|
|
@@ -36813,6 +36846,104 @@ export async function getSessionEvent(
|
|
|
36813
36846
|
});
|
|
36814
36847
|
}
|
|
36815
36848
|
|
|
36849
|
+
/**
|
|
36850
|
+
* Trusted Site lifecycle only: cancel an exact published root using native
|
|
36851
|
+
* controls. No request/agent endpoint exposes this adapter or its transaction.
|
|
36852
|
+
* The host has authorized the Site mutation; its actor stays unchanged.
|
|
36853
|
+
* Only the receipt and events written by this command leave the capability.
|
|
36854
|
+
*/
|
|
36855
|
+
export async function cancelSiteRuntimeConversation(
|
|
36856
|
+
db: Database,
|
|
36857
|
+
input: {
|
|
36858
|
+
accountId: string;
|
|
36859
|
+
workspaceId: string;
|
|
36860
|
+
siteId: string;
|
|
36861
|
+
sessionId: string;
|
|
36862
|
+
operationKey: string;
|
|
36863
|
+
reason: string;
|
|
36864
|
+
},
|
|
36865
|
+
) {
|
|
36866
|
+
// Own the complete transaction, including activity finalization. A nested
|
|
36867
|
+
// activity gate could otherwise outlive the exact-root visibility witness.
|
|
36868
|
+
if (isTransactionHandle(db)) throw new Error("Site cancellation requires its own transaction");
|
|
36869
|
+
return await runIdempotentPersistenceTransaction(
|
|
36870
|
+
{
|
|
36871
|
+
stage: "site_lifecycle.cancel",
|
|
36872
|
+
eventTypes: ["session.control.paused", "turn.cancelled"],
|
|
36873
|
+
maxAttempts: 3,
|
|
36874
|
+
},
|
|
36875
|
+
() =>
|
|
36876
|
+
withRlsContext(db, input, async (scopedDb) => {
|
|
36877
|
+
const [opened] = await rawRows<{ token: string | null }>(
|
|
36878
|
+
scopedDb,
|
|
36879
|
+
sql`
|
|
36880
|
+
select opengeni_private.begin_site_session_cancellation(
|
|
36881
|
+
${input.accountId}::uuid,${input.workspaceId}::uuid,${input.siteId}::uuid,${input.sessionId}::uuid
|
|
36882
|
+
) as token`,
|
|
36883
|
+
);
|
|
36884
|
+
if (!opened?.token) return null;
|
|
36885
|
+
const value = await withRestoredSessionActivityRlsContext(scopedDb, input, async (tx) => {
|
|
36886
|
+
const [context] = await rawRows<{ actor: string | null }>(
|
|
36887
|
+
tx,
|
|
36888
|
+
sql`
|
|
36889
|
+
select nullif(current_setting('opengeni.subject_id',true),'') as actor`,
|
|
36890
|
+
);
|
|
36891
|
+
// Serialize the active-state decision with native admission/control.
|
|
36892
|
+
// Replays still enter the native receipt path after terminal settlement.
|
|
36893
|
+
await lockWorkspaceInferenceControl(tx, input.workspaceId, "update");
|
|
36894
|
+
const [candidate] = await rawRows<{ needed: boolean }>(
|
|
36895
|
+
tx,
|
|
36896
|
+
sql`
|
|
36897
|
+
select exists(select 1 from sessions s
|
|
36898
|
+
where s.workspace_id=${input.workspaceId} and s.site_access_root_id=${input.sessionId}::uuid
|
|
36899
|
+
and s.status in ('queued','running','requires_action','recovering','waiting_capacity'))
|
|
36900
|
+
or exists(select 1 from session_command_receipts r
|
|
36901
|
+
where r.workspace_id=${input.workspaceId} and r.target_session_id=${input.sessionId}::uuid
|
|
36902
|
+
and r.operation_key=${input.operationKey} and r.actor_type='service'
|
|
36903
|
+
and r.actor_subject_id=${context?.actor ?? "site-lifecycle"}) as needed`,
|
|
36904
|
+
);
|
|
36905
|
+
if (!candidate?.needed) return null;
|
|
36906
|
+
const result = await mutateSessionControlInTransaction(tx, {
|
|
36907
|
+
accountId: input.accountId,
|
|
36908
|
+
workspaceId: input.workspaceId,
|
|
36909
|
+
sessionId: input.sessionId,
|
|
36910
|
+
actor: { type: "service", subjectId: context?.actor ?? "site-lifecycle" },
|
|
36911
|
+
operationKey: input.operationKey,
|
|
36912
|
+
action: "cancel",
|
|
36913
|
+
reason: input.reason,
|
|
36914
|
+
});
|
|
36915
|
+
const events: SessionEvent[] = [];
|
|
36916
|
+
for (const affected of result.affectedSessionEvents) {
|
|
36917
|
+
for (const eventId of affected.eventIds) {
|
|
36918
|
+
const event = await getSessionEvent(tx, input.workspaceId, eventId);
|
|
36919
|
+
if (!event || event.sessionId !== affected.sessionId)
|
|
36920
|
+
throw new Error("Site cancellation lost its committed event");
|
|
36921
|
+
events.push(event);
|
|
36922
|
+
}
|
|
36923
|
+
}
|
|
36924
|
+
const workspaceEvent = result.workspaceControlEventId
|
|
36925
|
+
? await getWorkspaceControlEvent(tx, input.workspaceId, result.workspaceControlEventId)
|
|
36926
|
+
: null;
|
|
36927
|
+
return {
|
|
36928
|
+
receiptId: result.receipt.id,
|
|
36929
|
+
replay: result.replay,
|
|
36930
|
+
cancelledSessionCount: result.cancelledSessionCount,
|
|
36931
|
+
cancelledTurnCount: result.cancelledTurnCount,
|
|
36932
|
+
wakeCount: result.wakeCount,
|
|
36933
|
+
events,
|
|
36934
|
+
workspaceEvent,
|
|
36935
|
+
};
|
|
36936
|
+
});
|
|
36937
|
+
// Also covers activity-revision stamping. On error the outer transaction
|
|
36938
|
+
// rolls the witness back, without masking the original SQL diagnostic.
|
|
36939
|
+
await scopedDb.execute(
|
|
36940
|
+
sql`select opengeni_private.end_site_session_cancellation(${opened.token}::uuid)`,
|
|
36941
|
+
);
|
|
36942
|
+
return value;
|
|
36943
|
+
}),
|
|
36944
|
+
);
|
|
36945
|
+
}
|
|
36946
|
+
|
|
36816
36947
|
/** Read one durable event under the exact human subject visibility projection. */
|
|
36817
36948
|
export async function getSessionEventForSubject(
|
|
36818
36949
|
db: Database,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
InsightsSiteUsageResponse,
|
|
4
|
+
type InsightsSiteUsageQuery,
|
|
5
|
+
} from "@opengeni/contracts/insights-usage";
|
|
6
|
+
import { withRlsContext, type Database } from "./database";
|
|
7
|
+
import { insightsUsageWindow } from "./insights-unified";
|
|
8
|
+
|
|
9
|
+
/** Uses the native accounting ledger and frozen model-call price snapshots. */
|
|
10
|
+
export async function readInsightsSiteUsage(
|
|
11
|
+
db: Database,
|
|
12
|
+
input: {
|
|
13
|
+
accountId: string;
|
|
14
|
+
workspaceId: string;
|
|
15
|
+
query: InsightsSiteUsageQuery;
|
|
16
|
+
viewerSubjectId: string | null;
|
|
17
|
+
now: Date;
|
|
18
|
+
},
|
|
19
|
+
): Promise<InsightsSiteUsageResponse> {
|
|
20
|
+
const window = insightsUsageWindow(input.query.range, input.now);
|
|
21
|
+
return withRlsContext(db, input, async (tx) => {
|
|
22
|
+
const result = await tx.execute(sql`select payload from opengeni_private.insights_site_usage(
|
|
23
|
+
${input.accountId}::uuid, ${input.workspaceId}::uuid,
|
|
24
|
+
${window.since.toISOString()}::timestamptz, ${window.until.toISOString()}::timestamptz,
|
|
25
|
+
${input.viewerSubjectId}::text)`);
|
|
26
|
+
const rows = (Array.isArray(result) ? result : (result as { rows: unknown[] }).rows) as {
|
|
27
|
+
payload: unknown;
|
|
28
|
+
}[];
|
|
29
|
+
return InsightsSiteUsageResponse.parse({
|
|
30
|
+
workspaceId: input.workspaceId,
|
|
31
|
+
range: input.query.range,
|
|
32
|
+
windowStart: window.since.toISOString(),
|
|
33
|
+
windowEnd: window.until.toISOString(),
|
|
34
|
+
rows: rows.map((row) => row.payload),
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
package/src/provision-roles.ts
CHANGED
|
@@ -2517,6 +2517,21 @@ BEGIN
|
|
|
2517
2517
|
REVOKE ALL ON FUNCTION opengeni_private.insights_raw_amount_inputs(uuid,uuid,timestamptz,timestamptz) FROM PUBLIC;
|
|
2518
2518
|
REVOKE ALL ON FUNCTION opengeni_private.insights_usage_payer(text,text), opengeni_private.insights_usage_filter(jsonb,jsonb) FROM PUBLIC;
|
|
2519
2519
|
END IF;
|
|
2520
|
+
IF to_regprocedure('opengeni_private.insights_site_usage(uuid,uuid,timestamptz,timestamptz,text)') IS NOT NULL THEN
|
|
2521
|
+
REVOKE ALL ON FUNCTION opengeni_private.insights_site_usage(uuid,uuid,timestamptz,timestamptz,text) FROM PUBLIC;
|
|
2522
|
+
END IF;
|
|
2523
|
+
IF to_regclass('opengeni_private.site_session_cancellation_capabilities') IS NOT NULL THEN
|
|
2524
|
+
EXECUTE format('REVOKE ALL ON TABLE opengeni_private.site_session_cancellation_capabilities FROM %I', ${literal(role)});
|
|
2525
|
+
EXECUTE format('REVOKE ALL (%s) ON TABLE opengeni_private.site_session_cancellation_capabilities FROM %I',
|
|
2526
|
+
(SELECT string_agg(quote_ident(attname),',' ORDER BY attnum) FROM pg_attribute
|
|
2527
|
+
WHERE attrelid='opengeni_private.site_session_cancellation_capabilities'::regclass AND attnum>0 AND NOT attisdropped), ${literal(role)});
|
|
2528
|
+
REVOKE ALL ON TABLE opengeni_private.site_session_cancellation_capabilities FROM PUBLIC;
|
|
2529
|
+
EXECUTE format('REVOKE ALL (%s) ON TABLE opengeni_private.site_session_cancellation_capabilities FROM PUBLIC',
|
|
2530
|
+
(SELECT string_agg(quote_ident(attname),',' ORDER BY attnum) FROM pg_attribute
|
|
2531
|
+
WHERE attrelid='opengeni_private.site_session_cancellation_capabilities'::regclass AND attnum>0 AND NOT attisdropped));
|
|
2532
|
+
REVOKE ALL ON FUNCTION opengeni_private.begin_site_session_cancellation(uuid,uuid,uuid,uuid),
|
|
2533
|
+
opengeni_private.end_site_session_cancellation(uuid) FROM PUBLIC;
|
|
2534
|
+
END IF;
|
|
2520
2535
|
IF to_regclass('opengeni_private.usage_allowance_capabilities') IS NOT NULL THEN
|
|
2521
2536
|
EXECUTE format('REVOKE ALL ON TABLE opengeni_private.usage_allowance_capabilities FROM %I', ${literal(role)});
|
|
2522
2537
|
EXECUTE format('REVOKE ALL (backend_pid,transaction_id,data_schema,account_id,workspace_id) ON TABLE opengeni_private.usage_allowance_capabilities FROM %I', ${literal(role)});
|