@opengeni/db 0.31.1 → 0.36.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/browser-auth.d.ts +209 -1
- package/dist/browser-downloads.d.ts +51 -0
- package/dist/browser-identities.d.ts +11 -2
- package/dist/browser-sessions.d.ts +83 -1
- package/dist/browser-state-artifacts.d.ts +75 -1
- package/dist/canonical-human-identities.d.ts +48 -0
- package/dist/canonical-human-identities.js +28 -0
- package/dist/canonical-human-identities.js.map +1 -0
- package/dist/capability-integrations.d.ts +8 -6
- package/dist/{chunk-MWDVXQOL.js → chunk-5KTIEDX7.js} +5773 -4212
- package/dist/chunk-5KTIEDX7.js.map +1 -0
- package/dist/chunk-FPVAD4CO.js +117 -0
- package/dist/chunk-FPVAD4CO.js.map +1 -0
- package/dist/chunk-GYO7ED2Q.js +259 -0
- package/dist/chunk-GYO7ED2Q.js.map +1 -0
- package/dist/{chunk-F5FT7BEZ.js → chunk-HSOWSYOX.js} +2 -2
- package/dist/{chunk-YHZXQ7HP.js → chunk-VKLB2ZGI.js} +446 -19
- package/dist/chunk-VKLB2ZGI.js.map +1 -0
- package/dist/{chunk-NBE6CHRI.js → chunk-VTPRIXKG.js} +49 -9
- package/dist/chunk-VTPRIXKG.js.map +1 -0
- package/dist/{chunk-ISI2TIUG.js → chunk-Z7VYMNPZ.js} +76 -4
- package/dist/chunk-Z7VYMNPZ.js.map +1 -0
- package/dist/database.d.ts +5 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +467 -29
- package/dist/index.js +23247 -16232
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +23 -7
- package/dist/integration-bindings.d.ts +24 -24
- package/dist/integration-facets.d.ts +99 -0
- package/dist/interaction-revisions.d.ts +11 -0
- package/dist/interaction-schema.d.ts +698 -34
- package/dist/persistence-errors.d.ts +8 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +8 -7
- package/dist/schema.d.ts +9464 -5412
- package/dist/schema.js +51 -9
- package/dist/session-control.d.ts +29 -3
- package/dist/session-tenancy.d.ts +44 -0
- package/dist/session-tenancy.js +16 -0
- package/dist/session-tenancy.js.map +1 -0
- package/dist/slack-task-policy-schema.d.ts +847 -0
- package/dist/slack-task-policy.d.ts +65 -0
- package/dist/task-notes-schema.d.ts +924 -0
- package/dist/task-notes.d.ts +85 -0
- package/dist/video-generation.d.ts +9 -0
- package/dist/video-generation.js +5 -3
- package/dist/xai-subscription.d.ts +326 -0
- package/drizzle/0212_browser_state_transfer_hardening.sql +560 -0
- package/drizzle/0213_browser_interaction_authority.sql +67 -0
- package/drizzle/0214_browser_download_saves.sql +34 -0
- package/drizzle/0215_browser_controller_host.sql +385 -0
- package/drizzle/0216_browser_auth_health_evidence.sql +137 -0
- package/drizzle/0217_external_browser_auth_operations.sql +22 -0
- package/drizzle/0218_organization_tenancy_foundation.sql +299 -0
- package/drizzle/0219_organization_tenancy_managed_human_provisioning.sql +317 -0
- package/drizzle/0219_site_auth_maintenance_sessions.sql +234 -0
- package/drizzle/0220_memory_slack_append_only_cascade.sql +38 -0
- package/drizzle/0220_session_channels.sql +54 -0
- package/drizzle/0221_sessions_channel_index.sql +5 -0
- package/drizzle/0222_session_visibility_authority_epochs.sql +158 -0
- package/drizzle/0222_sessions_channel_fk.sql +89 -0
- package/drizzle/0223_pending_tool_event_output.sql +55 -0
- package/drizzle/0223_sessions_channel_fk_validate.sql +118 -0
- package/drizzle/0224_slack_post_outcome_reconciliation.sql +123 -0
- package/drizzle/0225_session_visibility_fork_activation.sql +1363 -0
- package/drizzle/0226_personal_codex_authority_foundation.sql +365 -0
- package/drizzle/0227_slack_native_actions.sql +145 -0
- package/drizzle/0228_interaction_controller_data_plane.sql +14 -0
- package/drizzle/0228_slack_task_policy.sql +400 -0
- package/drizzle/0229_slack_inbox_file_fact.sql +10 -0
- package/drizzle/0230_user_scoped_variable_sets_rigs.sql +84 -0
- package/drizzle/0231_integration_definition_identity_cutover.sql +271 -0
- package/drizzle/0232_integration_facet_authority_cutover.sql +610 -0
- package/drizzle/0233_skill_and_integration_authority_cutover.sql +1162 -0
- package/drizzle/0234_xai_subscription_authority.sql +1139 -0
- package/drizzle/0235_canonical_human_login_bindings.sql +920 -0
- package/drizzle/0236_browser_identity_lifecycle.sql +39 -0
- package/drizzle/0236_session_visibility_slack_policy.sql +72 -0
- package/drizzle/0237_interaction_transition_reaper.sql +263 -0
- package/drizzle/0238_goal_persistence_policy.sql +471 -0
- package/drizzle/0238_recover_unclaimed_session_turns.sql +307 -0
- package/drizzle/0238_supergrok_realtime_model.sql +29 -0
- package/drizzle/0239_supergrok_video_funding.sql +50 -0
- package/drizzle/0239_task_tree_notes.sql +990 -0
- package/package.json +13 -5
- package/src/browser-auth.ts +2600 -123
- package/src/browser-downloads.ts +517 -0
- package/src/browser-identities.ts +220 -3
- package/src/browser-sessions.ts +334 -45
- package/src/browser-state-artifacts.ts +402 -12
- package/src/canonical-human-identities.ts +317 -0
- package/src/capability-integrations.ts +121 -213
- package/src/database.ts +41 -1
- package/src/index.ts +4625 -411
- package/src/insights.ts +109 -28
- package/src/integration-bindings.ts +101 -101
- package/src/{integration-features.ts → integration-facets.ts} +187 -184
- package/src/interaction-revisions.ts +33 -3
- package/src/interaction-schema.ts +311 -8
- package/src/pack-components.ts +43 -43
- package/src/pack-installations.ts +0 -43
- package/src/persistence-errors.ts +60 -1
- package/src/plugin-packages.ts +9 -9
- package/src/provision-roles.ts +232 -0
- package/src/runtime-posture.ts +227 -14
- package/src/schema.ts +1188 -75
- package/src/session-control.ts +122 -37
- package/src/session-queue-commands.ts +78 -1
- package/src/session-tenancy.ts +188 -0
- package/src/session-tool-call-settlement.ts +9 -3
- package/src/slack-task-policy-schema.ts +130 -0
- package/src/slack-task-policy.ts +341 -0
- package/src/task-notes-schema.ts +135 -0
- package/src/task-notes.ts +178 -0
- package/src/video-generation.ts +90 -12
- package/src/workspace-artifacts.ts +1 -1
- package/src/xai-subscription.ts +1887 -0
- package/dist/chunk-ISI2TIUG.js.map +0 -1
- package/dist/chunk-MWDVXQOL.js.map +0 -1
- package/dist/chunk-NBE6CHRI.js.map +0 -1
- package/dist/chunk-YHZXQ7HP.js.map +0 -1
- package/dist/integration-features.d.ts +0 -99
- /package/dist/{chunk-F5FT7BEZ.js.map → chunk-HSOWSYOX.js.map} +0 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Add an immutable, workspace-owned authority for shared Slack conversation
|
|
3
|
+
-- participation and result publication. No existing non-shared Slack path is
|
|
4
|
+
-- changed by this migration.
|
|
5
|
+
|
|
6
|
+
SET LOCAL lock_timeout = '5s';
|
|
7
|
+
SET LOCAL statement_timeout = '10min';
|
|
8
|
+
|
|
9
|
+
CREATE SEQUENCE slack_task_policy_revision_seq AS bigint;
|
|
10
|
+
|
|
11
|
+
CREATE OR REPLACE FUNCTION slack_task_policy_valid(value jsonb)
|
|
12
|
+
RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$
|
|
13
|
+
DECLARE
|
|
14
|
+
key text;
|
|
15
|
+
ids jsonb;
|
|
16
|
+
BEGIN
|
|
17
|
+
IF jsonb_typeof(value) IS DISTINCT FROM 'object'
|
|
18
|
+
OR (SELECT count(*) FROM jsonb_object_keys(value)) <> 7
|
|
19
|
+
OR NOT (
|
|
20
|
+
value ? 'allowedTeamIds'
|
|
21
|
+
AND value ? 'allowedConversationIds'
|
|
22
|
+
AND value ? 'allowGuestInitiators'
|
|
23
|
+
AND value ? 'allowExternalInitiators'
|
|
24
|
+
AND value ? 'allowMpim'
|
|
25
|
+
AND value ? 'sharedConversationMode'
|
|
26
|
+
AND value ? 'resultPublicationMode'
|
|
27
|
+
)
|
|
28
|
+
OR jsonb_typeof(value->'allowedTeamIds') IS DISTINCT FROM 'array'
|
|
29
|
+
OR jsonb_typeof(value->'allowedConversationIds') IS DISTINCT FROM 'array'
|
|
30
|
+
OR jsonb_array_length(value->'allowedTeamIds') > 256
|
|
31
|
+
OR jsonb_array_length(value->'allowedConversationIds') > 256
|
|
32
|
+
OR jsonb_typeof(value->'allowGuestInitiators') IS DISTINCT FROM 'boolean'
|
|
33
|
+
OR jsonb_typeof(value->'allowExternalInitiators') IS DISTINCT FROM 'boolean'
|
|
34
|
+
OR jsonb_typeof(value->'allowMpim') IS DISTINCT FROM 'boolean'
|
|
35
|
+
OR value->>'sharedConversationMode' NOT IN ('deny', 'private_handoff')
|
|
36
|
+
OR value->>'resultPublicationMode' NOT IN ('never', 'approval_required', 'allow')
|
|
37
|
+
OR octet_length(convert_to(value::text, 'UTF8')) > 65536
|
|
38
|
+
THEN
|
|
39
|
+
RETURN false;
|
|
40
|
+
END IF;
|
|
41
|
+
|
|
42
|
+
FOREACH key IN ARRAY ARRAY['allowedTeamIds', 'allowedConversationIds'] LOOP
|
|
43
|
+
ids := value->key;
|
|
44
|
+
IF EXISTS (
|
|
45
|
+
SELECT 1 FROM jsonb_array_elements(ids) item
|
|
46
|
+
WHERE jsonb_typeof(item) IS DISTINCT FROM 'string'
|
|
47
|
+
OR length(btrim(item #>> '{}')) NOT BETWEEN 1 AND 128
|
|
48
|
+
OR item #>> '{}' IS DISTINCT FROM btrim(item #>> '{}')
|
|
49
|
+
) OR (
|
|
50
|
+
SELECT count(DISTINCT item #>> '{}') FROM jsonb_array_elements(ids) item
|
|
51
|
+
) <> jsonb_array_length(ids) THEN
|
|
52
|
+
RETURN false;
|
|
53
|
+
END IF;
|
|
54
|
+
END LOOP;
|
|
55
|
+
RETURN true;
|
|
56
|
+
END;
|
|
57
|
+
$$;
|
|
58
|
+
|
|
59
|
+
CREATE OR REPLACE FUNCTION slack_task_policy_hash(policy jsonb)
|
|
60
|
+
RETURNS text LANGUAGE sql IMMUTABLE AS $$
|
|
61
|
+
SELECT encode(sha256(convert_to(jsonb_build_array('slack_task_policy', 1, policy)::text, 'UTF8')), 'hex');
|
|
62
|
+
$$;
|
|
63
|
+
|
|
64
|
+
REVOKE ALL ON FUNCTION slack_task_policy_valid(jsonb) FROM PUBLIC;
|
|
65
|
+
REVOKE ALL ON FUNCTION slack_task_policy_hash(jsonb) FROM PUBLIC;
|
|
66
|
+
|
|
67
|
+
CREATE TABLE slack_task_policy_revisions (
|
|
68
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
69
|
+
operation_id uuid NOT NULL,
|
|
70
|
+
request_fingerprint text NOT NULL,
|
|
71
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
72
|
+
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
73
|
+
revision bigint NOT NULL DEFAULT nextval('slack_task_policy_revision_seq'),
|
|
74
|
+
policy jsonb NOT NULL,
|
|
75
|
+
policy_hash text NOT NULL,
|
|
76
|
+
supersedes_revision_id uuid,
|
|
77
|
+
created_by_subject_id text NOT NULL,
|
|
78
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
79
|
+
CONSTRAINT slack_task_policy_revisions_revision_chk CHECK (revision > 0),
|
|
80
|
+
CONSTRAINT slack_task_policy_revisions_policy_chk CHECK (
|
|
81
|
+
slack_task_policy_valid(policy) AND policy_hash = slack_task_policy_hash(policy)
|
|
82
|
+
),
|
|
83
|
+
CONSTRAINT slack_task_policy_revisions_receipt_chk CHECK (request_fingerprint ~ '^[0-9a-f]{64}$'),
|
|
84
|
+
CONSTRAINT slack_task_policy_revisions_actor_chk CHECK (
|
|
85
|
+
length(btrim(created_by_subject_id)) BETWEEN 1 AND 1024
|
|
86
|
+
),
|
|
87
|
+
CONSTRAINT slack_task_policy_revisions_workspace_operation_uq UNIQUE (workspace_id, operation_id),
|
|
88
|
+
CONSTRAINT slack_task_policy_revisions_workspace_revision_uq UNIQUE (workspace_id, revision),
|
|
89
|
+
CONSTRAINT slack_task_policy_revisions_workspace_identity_uq UNIQUE (account_id, workspace_id, id),
|
|
90
|
+
CONSTRAINT slack_task_policy_revisions_supersedes_fk
|
|
91
|
+
FOREIGN KEY (account_id, workspace_id, supersedes_revision_id)
|
|
92
|
+
REFERENCES slack_task_policy_revisions(account_id, workspace_id, id) ON DELETE RESTRICT
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
CREATE INDEX slack_task_policy_revisions_workspace_history_idx
|
|
96
|
+
ON slack_task_policy_revisions(workspace_id, revision DESC);
|
|
97
|
+
|
|
98
|
+
CREATE TABLE slack_task_policy_heads (
|
|
99
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
100
|
+
workspace_id uuid PRIMARY KEY REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
101
|
+
revision_id uuid NOT NULL,
|
|
102
|
+
revision bigint NOT NULL,
|
|
103
|
+
policy_hash text NOT NULL,
|
|
104
|
+
activation_version bigint NOT NULL,
|
|
105
|
+
activated_at timestamptz NOT NULL DEFAULT now(),
|
|
106
|
+
CONSTRAINT slack_task_policy_heads_revision_fk
|
|
107
|
+
FOREIGN KEY (account_id, workspace_id, revision_id)
|
|
108
|
+
REFERENCES slack_task_policy_revisions(account_id, workspace_id, id) ON DELETE RESTRICT,
|
|
109
|
+
CONSTRAINT slack_task_policy_heads_version_chk CHECK (
|
|
110
|
+
revision > 0 AND activation_version > 0 AND policy_hash ~ '^[0-9a-f]{64}$'
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
CREATE INDEX slack_task_policy_heads_account_idx ON slack_task_policy_heads(account_id);
|
|
115
|
+
|
|
116
|
+
CREATE TABLE slack_task_policy_activation_events (
|
|
117
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
118
|
+
operation_id uuid NOT NULL,
|
|
119
|
+
request_fingerprint text NOT NULL,
|
|
120
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
121
|
+
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
122
|
+
activation_version bigint NOT NULL,
|
|
123
|
+
old_revision_id uuid,
|
|
124
|
+
old_revision bigint,
|
|
125
|
+
old_policy_hash text,
|
|
126
|
+
new_revision_id uuid NOT NULL,
|
|
127
|
+
new_revision bigint NOT NULL,
|
|
128
|
+
new_policy_hash text NOT NULL,
|
|
129
|
+
actor_subject_id text NOT NULL,
|
|
130
|
+
reason text NOT NULL,
|
|
131
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
132
|
+
CONSTRAINT slack_task_policy_events_old_revision_chk CHECK (
|
|
133
|
+
(old_revision_id IS NULL AND old_revision IS NULL AND old_policy_hash IS NULL)
|
|
134
|
+
OR (old_revision_id IS NOT NULL AND old_revision > 0 AND old_policy_hash ~ '^[0-9a-f]{64}$')
|
|
135
|
+
),
|
|
136
|
+
CONSTRAINT slack_task_policy_events_new_revision_chk CHECK (
|
|
137
|
+
new_revision > 0 AND new_policy_hash ~ '^[0-9a-f]{64}$' AND activation_version > 0
|
|
138
|
+
),
|
|
139
|
+
CONSTRAINT slack_task_policy_events_receipt_chk CHECK (request_fingerprint ~ '^[0-9a-f]{64}$'),
|
|
140
|
+
CONSTRAINT slack_task_policy_events_audit_chk CHECK (
|
|
141
|
+
length(btrim(actor_subject_id)) BETWEEN 1 AND 1024
|
|
142
|
+
AND length(btrim(reason)) BETWEEN 1 AND 4096
|
|
143
|
+
),
|
|
144
|
+
CONSTRAINT slack_task_policy_events_workspace_operation_uq UNIQUE (workspace_id, operation_id),
|
|
145
|
+
CONSTRAINT slack_task_policy_events_workspace_version_uq UNIQUE (workspace_id, activation_version),
|
|
146
|
+
CONSTRAINT slack_task_policy_events_new_revision_fk
|
|
147
|
+
FOREIGN KEY (account_id, workspace_id, new_revision_id)
|
|
148
|
+
REFERENCES slack_task_policy_revisions(account_id, workspace_id, id) ON DELETE RESTRICT
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
CREATE INDEX slack_task_policy_events_workspace_time_idx
|
|
152
|
+
ON slack_task_policy_activation_events(workspace_id, created_at DESC, id);
|
|
153
|
+
|
|
154
|
+
CREATE TABLE slack_shared_task_origins (
|
|
155
|
+
interaction_id uuid PRIMARY KEY,
|
|
156
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
157
|
+
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
158
|
+
connection_id uuid NOT NULL REFERENCES connections(id) ON DELETE CASCADE,
|
|
159
|
+
session_id uuid NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
160
|
+
slack_team_id text NOT NULL,
|
|
161
|
+
source_channel_id text NOT NULL,
|
|
162
|
+
source_thread_ts text NOT NULL,
|
|
163
|
+
initiating_slack_user_id text NOT NULL,
|
|
164
|
+
policy_revision_id uuid NOT NULL,
|
|
165
|
+
policy_hash text NOT NULL,
|
|
166
|
+
policy_activation_version bigint NOT NULL,
|
|
167
|
+
publication_mode text NOT NULL,
|
|
168
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
169
|
+
CONSTRAINT slack_shared_task_origins_interaction_fk
|
|
170
|
+
FOREIGN KEY (account_id, workspace_id, interaction_id)
|
|
171
|
+
REFERENCES slack_interactions(account_id, workspace_id, id) ON DELETE CASCADE,
|
|
172
|
+
CONSTRAINT slack_shared_task_origins_policy_fk
|
|
173
|
+
FOREIGN KEY (account_id, workspace_id, policy_revision_id)
|
|
174
|
+
REFERENCES slack_task_policy_revisions(account_id, workspace_id, id) ON DELETE RESTRICT,
|
|
175
|
+
CONSTRAINT slack_shared_task_origins_identity_uq UNIQUE (workspace_id, session_id),
|
|
176
|
+
CONSTRAINT slack_shared_task_origins_bounds_chk CHECK (
|
|
177
|
+
length(slack_team_id) BETWEEN 1 AND 128
|
|
178
|
+
AND length(source_channel_id) BETWEEN 1 AND 128
|
|
179
|
+
AND length(source_thread_ts) BETWEEN 1 AND 64
|
|
180
|
+
AND length(initiating_slack_user_id) BETWEEN 1 AND 128
|
|
181
|
+
AND policy_hash ~ '^[0-9a-f]{64}$'
|
|
182
|
+
AND policy_activation_version > 0
|
|
183
|
+
AND publication_mode IN ('never', 'approval_required', 'allow')
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
CREATE OR REPLACE FUNCTION slack_shared_task_origin_forbid_mutation()
|
|
188
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
189
|
+
BEGIN
|
|
190
|
+
RAISE EXCEPTION 'Slack shared task origin is immutable' USING ERRCODE = '42501';
|
|
191
|
+
END;
|
|
192
|
+
$$;
|
|
193
|
+
|
|
194
|
+
CREATE TRIGGER slack_shared_task_origins_immutable
|
|
195
|
+
BEFORE UPDATE OR DELETE ON slack_shared_task_origins
|
|
196
|
+
FOR EACH ROW EXECUTE FUNCTION slack_shared_task_origin_forbid_mutation();
|
|
197
|
+
|
|
198
|
+
ALTER TABLE slack_interaction_action_handles
|
|
199
|
+
DROP CONSTRAINT slack_interaction_action_handles_bounds_check;
|
|
200
|
+
ALTER TABLE slack_interaction_action_handles
|
|
201
|
+
ADD CONSTRAINT slack_interaction_action_handles_bounds_check CHECK (
|
|
202
|
+
session_event_sequence >= 0
|
|
203
|
+
AND octet_length(action_kind) BETWEEN 1 AND 64
|
|
204
|
+
AND octet_length(action_key) BETWEEN 1 AND 512
|
|
205
|
+
AND (target_id IS NULL OR octet_length(target_id) BETWEEN 1 AND 512)
|
|
206
|
+
AND (target_value IS NULL OR octet_length(target_value) BETWEEN 1 AND 1024)
|
|
207
|
+
AND octet_length(authorized_subject_id) BETWEEN 1 AND 512
|
|
208
|
+
AND octet_length(authorized_slack_user_id) BETWEEN 1 AND 64
|
|
209
|
+
AND action_kind IN (
|
|
210
|
+
'approval_approve', 'approval_reject', 'human_input_select',
|
|
211
|
+
'human_input_skip', 'session_status', 'session_pause', 'session_resume',
|
|
212
|
+
'shared_result_publish'
|
|
213
|
+
)
|
|
214
|
+
AND status IN ('pending', 'completed', 'stale')
|
|
215
|
+
AND (result IS NULL OR octet_length(result) BETWEEN 1 AND 64)
|
|
216
|
+
AND (
|
|
217
|
+
(status = 'pending' AND result IS NULL AND completed_at IS NULL)
|
|
218
|
+
OR (status IN ('completed', 'stale') AND result IS NOT NULL AND completed_at IS NOT NULL)
|
|
219
|
+
)
|
|
220
|
+
) NOT VALID;
|
|
221
|
+
ALTER TABLE slack_interaction_action_handles
|
|
222
|
+
VALIDATE CONSTRAINT slack_interaction_action_handles_bounds_check;
|
|
223
|
+
|
|
224
|
+
CREATE OR REPLACE FUNCTION slack_task_policy_forbid_mutation()
|
|
225
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
226
|
+
BEGIN
|
|
227
|
+
RAISE EXCEPTION 'Slack task policy history is immutable' USING ERRCODE = '42501';
|
|
228
|
+
END;
|
|
229
|
+
$$;
|
|
230
|
+
|
|
231
|
+
CREATE TRIGGER slack_task_policy_revisions_immutable
|
|
232
|
+
BEFORE UPDATE OR DELETE ON slack_task_policy_revisions
|
|
233
|
+
FOR EACH ROW EXECUTE FUNCTION slack_task_policy_forbid_mutation();
|
|
234
|
+
CREATE TRIGGER slack_task_policy_events_immutable
|
|
235
|
+
BEFORE UPDATE OR DELETE ON slack_task_policy_activation_events
|
|
236
|
+
FOR EACH ROW EXECUTE FUNCTION slack_task_policy_forbid_mutation();
|
|
237
|
+
|
|
238
|
+
CREATE OR REPLACE FUNCTION slack_task_policy_guard_head_mutation()
|
|
239
|
+
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
240
|
+
DECLARE expected_workspace_id text;
|
|
241
|
+
BEGIN
|
|
242
|
+
expected_workspace_id := current_setting('opengeni.slack_task_policy_lifecycle_workspace_id', true);
|
|
243
|
+
IF expected_workspace_id IS NULL OR expected_workspace_id = ''
|
|
244
|
+
OR expected_workspace_id IS DISTINCT FROM coalesce(NEW.workspace_id, OLD.workspace_id)::text
|
|
245
|
+
THEN
|
|
246
|
+
RAISE EXCEPTION 'Slack task policy head mutation is lifecycle-only' USING ERRCODE = '42501';
|
|
247
|
+
END IF;
|
|
248
|
+
IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;
|
|
249
|
+
RETURN NEW;
|
|
250
|
+
END;
|
|
251
|
+
$$;
|
|
252
|
+
|
|
253
|
+
CREATE TRIGGER slack_task_policy_heads_lifecycle_only
|
|
254
|
+
BEFORE INSERT OR UPDATE OR DELETE ON slack_task_policy_heads
|
|
255
|
+
FOR EACH ROW EXECUTE FUNCTION slack_task_policy_guard_head_mutation();
|
|
256
|
+
|
|
257
|
+
CREATE OR REPLACE FUNCTION slack_task_policy_update(
|
|
258
|
+
p_operation_id uuid,
|
|
259
|
+
p_request_fingerprint text,
|
|
260
|
+
p_account_id uuid,
|
|
261
|
+
p_workspace_id uuid,
|
|
262
|
+
p_policy jsonb,
|
|
263
|
+
p_expected_current_revision_id uuid,
|
|
264
|
+
p_expected_activation_version bigint,
|
|
265
|
+
p_actor_subject_id text,
|
|
266
|
+
p_reason text
|
|
267
|
+
) RETURNS TABLE (revision_id uuid, event_id uuid)
|
|
268
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
269
|
+
DECLARE
|
|
270
|
+
current_head slack_task_policy_heads%ROWTYPE;
|
|
271
|
+
existing_revision slack_task_policy_revisions%ROWTYPE;
|
|
272
|
+
existing_event slack_task_policy_activation_events%ROWTYPE;
|
|
273
|
+
created_revision slack_task_policy_revisions%ROWTYPE;
|
|
274
|
+
next_version bigint;
|
|
275
|
+
accepted_at timestamptz;
|
|
276
|
+
BEGIN
|
|
277
|
+
IF NULLIF(current_setting('opengeni.account_id', true), '')::uuid IS DISTINCT FROM p_account_id
|
|
278
|
+
OR NULLIF(current_setting('opengeni.workspace_id', true), '')::uuid IS DISTINCT FROM p_workspace_id
|
|
279
|
+
OR NULLIF(current_setting('opengeni.subject_id', true), '') IS DISTINCT FROM p_actor_subject_id
|
|
280
|
+
OR NULLIF(current_setting('opengeni.principal_kind', true), '') IS DISTINCT FROM 'human_session'
|
|
281
|
+
THEN
|
|
282
|
+
RAISE EXCEPTION 'Slack task policy update requires exact human workspace authority'
|
|
283
|
+
USING ERRCODE = '42501';
|
|
284
|
+
END IF;
|
|
285
|
+
IF p_request_fingerprint !~ '^[0-9a-f]{64}$'
|
|
286
|
+
OR p_expected_activation_version < 0
|
|
287
|
+
OR NOT slack_task_policy_valid(p_policy)
|
|
288
|
+
OR length(btrim(p_actor_subject_id)) NOT BETWEEN 1 AND 1024
|
|
289
|
+
OR length(btrim(p_reason)) NOT BETWEEN 1 AND 4096
|
|
290
|
+
THEN
|
|
291
|
+
RAISE EXCEPTION 'Slack task policy update input is invalid' USING ERRCODE = '22023';
|
|
292
|
+
END IF;
|
|
293
|
+
|
|
294
|
+
PERFORM 1 FROM workspaces
|
|
295
|
+
WHERE id = p_workspace_id AND account_id = p_account_id FOR UPDATE;
|
|
296
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'workspace was not found' USING ERRCODE = '42501'; END IF;
|
|
297
|
+
|
|
298
|
+
SELECT * INTO existing_revision FROM slack_task_policy_revisions
|
|
299
|
+
WHERE workspace_id = p_workspace_id AND operation_id = p_operation_id;
|
|
300
|
+
SELECT * INTO existing_event FROM slack_task_policy_activation_events
|
|
301
|
+
WHERE workspace_id = p_workspace_id AND operation_id = p_operation_id;
|
|
302
|
+
IF existing_revision.id IS NOT NULL OR existing_event.id IS NOT NULL THEN
|
|
303
|
+
IF existing_revision.id IS NULL OR existing_event.id IS NULL
|
|
304
|
+
OR existing_revision.request_fingerprint IS DISTINCT FROM p_request_fingerprint
|
|
305
|
+
OR existing_event.request_fingerprint IS DISTINCT FROM p_request_fingerprint
|
|
306
|
+
THEN
|
|
307
|
+
RAISE EXCEPTION 'Slack task policy operation id was reused' USING ERRCODE = 'P1471';
|
|
308
|
+
END IF;
|
|
309
|
+
revision_id := existing_revision.id;
|
|
310
|
+
event_id := existing_event.id;
|
|
311
|
+
RETURN NEXT;
|
|
312
|
+
RETURN;
|
|
313
|
+
END IF;
|
|
314
|
+
|
|
315
|
+
SELECT * INTO current_head FROM slack_task_policy_heads
|
|
316
|
+
WHERE workspace_id = p_workspace_id FOR UPDATE;
|
|
317
|
+
IF coalesce(current_head.activation_version, 0) IS DISTINCT FROM p_expected_activation_version
|
|
318
|
+
OR current_head.revision_id IS DISTINCT FROM p_expected_current_revision_id
|
|
319
|
+
THEN
|
|
320
|
+
RAISE EXCEPTION 'Slack task policy active revision changed' USING ERRCODE = '40001';
|
|
321
|
+
END IF;
|
|
322
|
+
|
|
323
|
+
accepted_at := clock_timestamp();
|
|
324
|
+
INSERT INTO slack_task_policy_revisions (
|
|
325
|
+
operation_id, request_fingerprint, account_id, workspace_id, policy, policy_hash,
|
|
326
|
+
supersedes_revision_id, created_by_subject_id, created_at
|
|
327
|
+
) VALUES (
|
|
328
|
+
p_operation_id, p_request_fingerprint, p_account_id, p_workspace_id, p_policy,
|
|
329
|
+
slack_task_policy_hash(p_policy), current_head.revision_id, p_actor_subject_id, accepted_at
|
|
330
|
+
) RETURNING * INTO created_revision;
|
|
331
|
+
|
|
332
|
+
next_version := coalesce(current_head.activation_version, 0) + 1;
|
|
333
|
+
PERFORM set_config('opengeni.slack_task_policy_lifecycle_workspace_id', p_workspace_id::text, true);
|
|
334
|
+
INSERT INTO slack_task_policy_heads (
|
|
335
|
+
account_id, workspace_id, revision_id, revision, policy_hash, activation_version, activated_at
|
|
336
|
+
) VALUES (
|
|
337
|
+
p_account_id, p_workspace_id, created_revision.id, created_revision.revision,
|
|
338
|
+
created_revision.policy_hash, next_version, accepted_at
|
|
339
|
+
) ON CONFLICT (workspace_id) DO UPDATE SET
|
|
340
|
+
revision_id = excluded.revision_id,
|
|
341
|
+
revision = excluded.revision,
|
|
342
|
+
policy_hash = excluded.policy_hash,
|
|
343
|
+
activation_version = excluded.activation_version,
|
|
344
|
+
activated_at = excluded.activated_at;
|
|
345
|
+
PERFORM set_config('opengeni.slack_task_policy_lifecycle_workspace_id', '', true);
|
|
346
|
+
|
|
347
|
+
INSERT INTO slack_task_policy_activation_events (
|
|
348
|
+
operation_id, request_fingerprint, account_id, workspace_id, activation_version,
|
|
349
|
+
old_revision_id, old_revision, old_policy_hash,
|
|
350
|
+
new_revision_id, new_revision, new_policy_hash,
|
|
351
|
+
actor_subject_id, reason, created_at
|
|
352
|
+
) VALUES (
|
|
353
|
+
p_operation_id, p_request_fingerprint, p_account_id, p_workspace_id, next_version,
|
|
354
|
+
current_head.revision_id, current_head.revision, current_head.policy_hash,
|
|
355
|
+
created_revision.id, created_revision.revision, created_revision.policy_hash,
|
|
356
|
+
p_actor_subject_id, p_reason, accepted_at
|
|
357
|
+
) RETURNING id INTO event_id;
|
|
358
|
+
revision_id := created_revision.id;
|
|
359
|
+
RETURN NEXT;
|
|
360
|
+
END;
|
|
361
|
+
$$;
|
|
362
|
+
|
|
363
|
+
REVOKE ALL ON FUNCTION slack_task_policy_update(uuid,text,uuid,uuid,jsonb,uuid,bigint,text,text) FROM PUBLIC;
|
|
364
|
+
|
|
365
|
+
ALTER TABLE slack_task_policy_revisions ENABLE ROW LEVEL SECURITY;
|
|
366
|
+
ALTER TABLE slack_task_policy_revisions FORCE ROW LEVEL SECURITY;
|
|
367
|
+
ALTER TABLE slack_task_policy_heads ENABLE ROW LEVEL SECURITY;
|
|
368
|
+
ALTER TABLE slack_task_policy_heads FORCE ROW LEVEL SECURITY;
|
|
369
|
+
ALTER TABLE slack_task_policy_activation_events ENABLE ROW LEVEL SECURITY;
|
|
370
|
+
ALTER TABLE slack_task_policy_activation_events FORCE ROW LEVEL SECURITY;
|
|
371
|
+
ALTER TABLE slack_shared_task_origins ENABLE ROW LEVEL SECURITY;
|
|
372
|
+
ALTER TABLE slack_shared_task_origins FORCE ROW LEVEL SECURITY;
|
|
373
|
+
|
|
374
|
+
CREATE POLICY workspace_isolation ON slack_task_policy_revisions
|
|
375
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
376
|
+
CREATE POLICY workspace_isolation ON slack_task_policy_heads
|
|
377
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
378
|
+
CREATE POLICY workspace_isolation ON slack_task_policy_activation_events
|
|
379
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
380
|
+
CREATE POLICY workspace_isolation ON slack_shared_task_origins
|
|
381
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
382
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
383
|
+
|
|
384
|
+
REVOKE ALL ON TABLE slack_task_policy_revisions FROM PUBLIC;
|
|
385
|
+
REVOKE ALL ON TABLE slack_task_policy_heads FROM PUBLIC;
|
|
386
|
+
REVOKE ALL ON TABLE slack_task_policy_activation_events FROM PUBLIC;
|
|
387
|
+
REVOKE ALL ON TABLE slack_shared_task_origins FROM PUBLIC;
|
|
388
|
+
REVOKE ALL ON SEQUENCE slack_task_policy_revision_seq FROM PUBLIC;
|
|
389
|
+
|
|
390
|
+
DO $grants$
|
|
391
|
+
BEGIN
|
|
392
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
393
|
+
GRANT SELECT ON TABLE slack_task_policy_revisions TO opengeni_app;
|
|
394
|
+
GRANT SELECT ON TABLE slack_task_policy_heads TO opengeni_app;
|
|
395
|
+
GRANT SELECT ON TABLE slack_task_policy_activation_events TO opengeni_app;
|
|
396
|
+
GRANT SELECT, INSERT ON TABLE slack_shared_task_origins TO opengeni_app;
|
|
397
|
+
GRANT EXECUTE ON FUNCTION slack_task_policy_update(uuid,text,uuid,uuid,jsonb,uuid,bigint,text,text)
|
|
398
|
+
TO opengeni_app;
|
|
399
|
+
END IF;
|
|
400
|
+
END $grants$;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Preserve the signed Slack event's bounded file-presence fact through the
|
|
3
|
+
-- durable inbox so mixed-text DMs and existing-thread replies fetch only their
|
|
4
|
+
-- exact provider message before importing authorized images.
|
|
5
|
+
|
|
6
|
+
SET LOCAL lock_timeout = '5s';
|
|
7
|
+
SET LOCAL statement_timeout = '10min';
|
|
8
|
+
|
|
9
|
+
ALTER TABLE "slack_interaction_inbox"
|
|
10
|
+
ADD COLUMN "has_files" boolean NOT NULL DEFAULT false;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Inert authority identity foundation for Variable Sets and Rigs. This slice
|
|
3
|
+
-- changes no runtime authorization, RLS policy, lifecycle GUC, API/DAO path,
|
|
4
|
+
-- runnable snapshot, grant consumption, or worker materialization behavior.
|
|
5
|
+
|
|
6
|
+
SET LOCAL lock_timeout = '5s';
|
|
7
|
+
SET LOCAL statement_timeout = '10min';
|
|
8
|
+
|
|
9
|
+
ALTER TABLE "workspace_variable_sets"
|
|
10
|
+
ADD COLUMN "authority_scope" text NOT NULL DEFAULT 'workspace',
|
|
11
|
+
ADD COLUMN "authority_id" uuid,
|
|
12
|
+
ADD COLUMN "owner_organization_membership_id" uuid,
|
|
13
|
+
ADD COLUMN "origin_workspace_id" uuid;
|
|
14
|
+
|
|
15
|
+
ALTER TABLE "rigs"
|
|
16
|
+
ADD COLUMN "authority_scope" text NOT NULL DEFAULT 'workspace',
|
|
17
|
+
ADD COLUMN "authority_id" uuid,
|
|
18
|
+
ADD COLUMN "owner_organization_membership_id" uuid,
|
|
19
|
+
ADD COLUMN "origin_workspace_id" uuid;
|
|
20
|
+
|
|
21
|
+
ALTER TABLE "workspace_variable_sets"
|
|
22
|
+
ADD CONSTRAINT "workspace_variable_sets_authority_scope_check"
|
|
23
|
+
CHECK ("authority_scope" IN ('workspace', 'user')) NOT VALID,
|
|
24
|
+
ADD CONSTRAINT "workspace_variable_sets_authority_shape_check" CHECK (
|
|
25
|
+
(
|
|
26
|
+
"authority_scope" = 'workspace'
|
|
27
|
+
AND "authority_id" IS NULL
|
|
28
|
+
AND "owner_organization_membership_id" IS NULL
|
|
29
|
+
) OR (
|
|
30
|
+
"authority_scope" = 'user'
|
|
31
|
+
AND "authority_id" IS NOT NULL
|
|
32
|
+
AND "owner_organization_membership_id" IS NOT NULL
|
|
33
|
+
)
|
|
34
|
+
) NOT VALID,
|
|
35
|
+
ADD CONSTRAINT "workspace_variable_sets_authority_fk" FOREIGN KEY (
|
|
36
|
+
"authority_id", "account_id", "owner_organization_membership_id"
|
|
37
|
+
) REFERENCES "organization_user_resource_authorities"(
|
|
38
|
+
"id", "account_id", "organization_membership_id"
|
|
39
|
+
) ON DELETE RESTRICT NOT VALID,
|
|
40
|
+
ADD CONSTRAINT "workspace_variable_sets_origin_workspace_fk" FOREIGN KEY (
|
|
41
|
+
"origin_workspace_id", "account_id"
|
|
42
|
+
) REFERENCES "workspaces"("id", "account_id")
|
|
43
|
+
ON DELETE SET NULL ("origin_workspace_id") NOT VALID;
|
|
44
|
+
|
|
45
|
+
ALTER TABLE "rigs"
|
|
46
|
+
ADD CONSTRAINT "rigs_authority_scope_check"
|
|
47
|
+
CHECK ("authority_scope" IN ('workspace', 'user')) NOT VALID,
|
|
48
|
+
ADD CONSTRAINT "rigs_authority_shape_check" CHECK (
|
|
49
|
+
(
|
|
50
|
+
"authority_scope" = 'workspace'
|
|
51
|
+
AND "authority_id" IS NULL
|
|
52
|
+
AND "owner_organization_membership_id" IS NULL
|
|
53
|
+
) OR (
|
|
54
|
+
"authority_scope" = 'user'
|
|
55
|
+
AND "authority_id" IS NOT NULL
|
|
56
|
+
AND "owner_organization_membership_id" IS NOT NULL
|
|
57
|
+
)
|
|
58
|
+
) NOT VALID,
|
|
59
|
+
ADD CONSTRAINT "rigs_authority_fk" FOREIGN KEY (
|
|
60
|
+
"authority_id", "account_id", "owner_organization_membership_id"
|
|
61
|
+
) REFERENCES "organization_user_resource_authorities"(
|
|
62
|
+
"id", "account_id", "organization_membership_id"
|
|
63
|
+
) ON DELETE RESTRICT NOT VALID,
|
|
64
|
+
ADD CONSTRAINT "rigs_origin_workspace_fk" FOREIGN KEY (
|
|
65
|
+
"origin_workspace_id", "account_id"
|
|
66
|
+
) REFERENCES "workspaces"("id", "account_id")
|
|
67
|
+
ON DELETE SET NULL ("origin_workspace_id") NOT VALID;
|
|
68
|
+
|
|
69
|
+
ALTER TABLE "workspace_variable_sets"
|
|
70
|
+
VALIDATE CONSTRAINT "workspace_variable_sets_authority_scope_check",
|
|
71
|
+
VALIDATE CONSTRAINT "workspace_variable_sets_authority_shape_check",
|
|
72
|
+
VALIDATE CONSTRAINT "workspace_variable_sets_authority_fk",
|
|
73
|
+
VALIDATE CONSTRAINT "workspace_variable_sets_origin_workspace_fk";
|
|
74
|
+
|
|
75
|
+
ALTER TABLE "rigs"
|
|
76
|
+
VALIDATE CONSTRAINT "rigs_authority_scope_check",
|
|
77
|
+
VALIDATE CONSTRAINT "rigs_authority_shape_check",
|
|
78
|
+
VALIDATE CONSTRAINT "rigs_authority_fk",
|
|
79
|
+
VALIDATE CONSTRAINT "rigs_origin_workspace_fk";
|
|
80
|
+
|
|
81
|
+
COMMENT ON COLUMN "workspace_variable_sets"."authority_scope" IS
|
|
82
|
+
'Inert authority identity foundation. Runtime access remains workspace-scoped until a later activation migration.';
|
|
83
|
+
COMMENT ON COLUMN "rigs"."authority_scope" IS
|
|
84
|
+
'Inert authority identity foundation. Runtime access remains workspace-scoped until a later activation migration.';
|