@opengeni/db 0.36.1 → 3.1.0-canary.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.
Files changed (274) hide show
  1. package/dist/attached-browser-devices.d.ts +7 -0
  2. package/dist/automations.d.ts +154 -0
  3. package/dist/canonical-human-identities.js +3 -3
  4. package/dist/capability-integrations.d.ts +13 -0
  5. package/dist/child-lifecycle-notices.d.ts +68 -0
  6. package/dist/{chunk-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
  7. package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
  8. package/dist/{chunk-HSOWSYOX.js → chunk-NMUBV7Z5.js} +19 -11
  9. package/dist/chunk-NMUBV7Z5.js.map +1 -0
  10. package/dist/chunk-OF5OBB76.js +4457 -0
  11. package/dist/chunk-OF5OBB76.js.map +1 -0
  12. package/dist/{chunk-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
  13. package/dist/chunk-PR2WMLOQ.js.map +1 -0
  14. package/dist/{chunk-Z7VYMNPZ.js → chunk-SCPUJS53.js} +41 -4
  15. package/dist/chunk-SCPUJS53.js.map +1 -0
  16. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  17. package/dist/chunk-SIBYBA2D.js.map +1 -0
  18. package/dist/chunk-TIKF3KTI.js +383 -0
  19. package/dist/chunk-TIKF3KTI.js.map +1 -0
  20. package/dist/chunk-ZZ5LJEFX.js +516 -0
  21. package/dist/chunk-ZZ5LJEFX.js.map +1 -0
  22. package/dist/codemode-operations.d.ts +1 -6
  23. package/dist/company-brain-context-selection-schema.d.ts +705 -0
  24. package/dist/company-brain-context-selection.d.ts +94 -0
  25. package/dist/company-brain-governed-writes.d.ts +24 -0
  26. package/dist/company-brain.d.ts +55 -0
  27. package/dist/company-profile-agent-admin.d.ts +15 -0
  28. package/dist/company-profile-schema.d.ts +619 -2
  29. package/dist/company-profile.d.ts +9 -4
  30. package/dist/connection-authority.d.ts +95 -0
  31. package/dist/connection-scopes.d.ts +8 -0
  32. package/dist/connection-tenancy-backfill.d.ts +41 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +19 -0
  35. package/dist/editable-artifact-durable-export.d.ts +10 -0
  36. package/dist/editable-artifact-durable-export.js +18 -3
  37. package/dist/editable-artifact-durable-export.js.map +1 -1
  38. package/dist/editable-artifacts.d.ts +2 -2
  39. package/dist/editable-artifacts.js +3 -3
  40. package/dist/governed-learning-activation-schema.d.ts +984 -0
  41. package/dist/governed-learning-activation.d.ts +98 -0
  42. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  43. package/dist/governed-learning-evaluator.d.ts +28 -0
  44. package/dist/index.d.ts +1633 -87
  45. package/dist/index.js +22004 -8109
  46. package/dist/index.js.map +1 -1
  47. package/dist/insights.d.ts +18 -0
  48. package/dist/integration-bindings.d.ts +1 -0
  49. package/dist/integration-facets.d.ts +30 -0
  50. package/dist/interaction-placement-loss.d.ts +22 -0
  51. package/dist/knowledge-source-sync-schema.d.ts +730 -0
  52. package/dist/knowledge-source-sync.d.ts +60 -0
  53. package/dist/managed-human-provisioning.d.ts +25 -0
  54. package/dist/memory-domain.d.ts +3 -3
  55. package/dist/migrate.d.ts +11 -1
  56. package/dist/migrate.js +1 -1
  57. package/dist/new-session-drafts.d.ts +43 -5
  58. package/dist/organization-membership-backfill.d.ts +174 -0
  59. package/dist/organization-membership-lifecycle.d.ts +162 -0
  60. package/dist/pr-review.d.ts +107 -0
  61. package/dist/preference-registry-schema.d.ts +2 -0
  62. package/dist/preference-registry.d.ts +2 -0
  63. package/dist/provision-roles.js +1 -1
  64. package/dist/runtime-posture.d.ts +23 -9
  65. package/dist/schema.d.ts +24925 -13697
  66. package/dist/schema.js +103 -1
  67. package/dist/scoped-knowledge-schema.d.ts +52 -1
  68. package/dist/session-background-commands.d.ts +125 -0
  69. package/dist/session-background-commands.js +34 -0
  70. package/dist/session-background-commands.js.map +1 -0
  71. package/dist/session-control.d.ts +156 -3
  72. package/dist/session-goal-pacing.d.ts +68 -0
  73. package/dist/session-queue-commands.d.ts +42 -5
  74. package/dist/session-realtime-ledger.d.ts +3 -0
  75. package/dist/session-tenancy.d.ts +71 -1
  76. package/dist/session-tenancy.js +25 -3
  77. package/dist/session-tool-call-settlement.d.ts +9 -4
  78. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  79. package/dist/slack-routing.d.ts +153 -0
  80. package/dist/slack-task-policy-schema.d.ts +34 -0
  81. package/dist/slack-task-policy.d.ts +8 -0
  82. package/dist/slack-user-link-access.d.ts +1 -0
  83. package/dist/task-notes-schema.d.ts +594 -0
  84. package/dist/task-notes.d.ts +39 -0
  85. package/dist/turn-initiator.d.ts +2 -0
  86. package/dist/user-resource-authority.d.ts +109 -0
  87. package/dist/video-generation.js +3 -3
  88. package/dist/workspace-authority.d.ts +81 -0
  89. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  90. package/dist/workspace-instruction-policies.d.ts +62 -0
  91. package/dist/workspace-learning-policy.d.ts +1 -0
  92. package/dist/workspace-membership-permissions.d.ts +2 -0
  93. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  94. package/drizzle/0240_model_context_user_messages.sql +204 -0
  95. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  96. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  97. package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
  98. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  99. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  100. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  101. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  102. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  103. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  104. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  105. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  106. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  107. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  108. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  109. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  110. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  111. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  112. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  113. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  114. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  115. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  116. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  117. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  118. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  119. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  120. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  121. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  122. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  123. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  124. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  125. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  126. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  127. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  128. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  129. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  130. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  131. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  132. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  133. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  134. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  135. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  136. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  137. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  138. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  139. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  140. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  141. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  142. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  143. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  144. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  145. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  146. package/drizzle/0294_preference_activation_authority.sql +237 -0
  147. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  148. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  149. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  150. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  151. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  152. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  153. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  154. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  155. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  156. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  157. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  158. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  159. package/drizzle/0307_session_attention_state.sql +51 -0
  160. package/drizzle/0308_session_archives.sql +35 -0
  161. package/drizzle/0309_channel_project_pins.sql +6 -0
  162. package/drizzle/0310_channel_project_order.sql +27 -0
  163. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  164. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  165. package/drizzle/0313_private_child_session_authority.sql +365 -0
  166. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  167. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  168. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  169. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  170. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  171. package/drizzle/0319_event_triggered_automations.sql +254 -0
  172. package/drizzle/0320_pr_review_pack.sql +113 -0
  173. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  174. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  175. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  176. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  177. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  178. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  179. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  180. package/drizzle/0328_session_background_commands.sql +590 -0
  181. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  182. package/drizzle/0330_api_key_descriptions.sql +20 -0
  183. package/drizzle/0331_managed_organization_creation.sql +163 -0
  184. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  185. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  186. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  187. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  188. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  189. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  190. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  191. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  192. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  193. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
  194. package/package.json +10 -6
  195. package/src/attached-browser-devices.ts +233 -5
  196. package/src/automations.ts +911 -0
  197. package/src/browser-sessions.ts +10 -0
  198. package/src/capability-integrations.ts +175 -1
  199. package/src/child-lifecycle-notices.ts +241 -0
  200. package/src/codemode-operations.ts +1 -35
  201. package/src/company-brain-context-selection-schema.ts +100 -0
  202. package/src/company-brain-context-selection.ts +359 -0
  203. package/src/company-brain-governed-writes.ts +1170 -0
  204. package/src/company-brain.ts +309 -0
  205. package/src/company-profile-agent-admin.ts +225 -0
  206. package/src/company-profile-schema.ts +121 -1
  207. package/src/company-profile.ts +21 -0
  208. package/src/computer-sessions.ts +10 -1
  209. package/src/connection-authority.ts +290 -0
  210. package/src/connection-scopes.ts +20 -0
  211. package/src/connection-tenancy-backfill.ts +81 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +75 -2
  214. package/src/editable-artifact-durable-export.ts +27 -0
  215. package/src/editable-artifacts-schema.ts +10 -5
  216. package/src/editable-artifacts.ts +21 -11
  217. package/src/governed-learning-activation-schema.ts +121 -0
  218. package/src/governed-learning-activation.ts +588 -0
  219. package/src/governed-learning-evaluator-schema.ts +72 -0
  220. package/src/governed-learning-evaluator.ts +217 -0
  221. package/src/index.ts +12001 -1699
  222. package/src/insights.ts +107 -0
  223. package/src/integration-bindings.ts +88 -6
  224. package/src/integration-facets.ts +287 -84
  225. package/src/interaction-placement-loss.ts +234 -0
  226. package/src/knowledge-source-sync-schema.ts +83 -0
  227. package/src/knowledge-source-sync.ts +530 -0
  228. package/src/managed-human-provisioning.ts +116 -0
  229. package/src/memory-domain.ts +27 -32
  230. package/src/migrate.ts +77 -1
  231. package/src/new-session-drafts.ts +229 -35
  232. package/src/organization-membership-backfill.ts +735 -0
  233. package/src/organization-membership-lifecycle.ts +985 -0
  234. package/src/pr-review.ts +890 -0
  235. package/src/preference-registry.ts +31 -1
  236. package/src/provision-roles.ts +931 -24
  237. package/src/runtime-posture-cli.ts +2 -0
  238. package/src/runtime-posture.ts +1315 -52
  239. package/src/schema.ts +3336 -438
  240. package/src/scoped-knowledge-schema.ts +16 -8
  241. package/src/scoped-knowledge.ts +1 -1
  242. package/src/session-background-commands.ts +759 -0
  243. package/src/session-control.ts +640 -74
  244. package/src/session-goal-pacing.ts +126 -0
  245. package/src/session-queue-commands.ts +450 -98
  246. package/src/session-realtime-context.ts +19 -3
  247. package/src/session-realtime-ledger.ts +75 -12
  248. package/src/session-realtime-mirror.ts +1 -1
  249. package/src/session-tenancy.ts +403 -49
  250. package/src/session-tool-call-settlement.ts +38 -29
  251. package/src/slack-routing-personal-workspace.ts +67 -0
  252. package/src/slack-routing.ts +469 -0
  253. package/src/slack-task-policy-schema.ts +5 -0
  254. package/src/slack-task-policy.ts +18 -0
  255. package/src/slack-user-link-access.ts +17 -1
  256. package/src/task-notes-schema.ts +74 -0
  257. package/src/task-notes.ts +124 -2
  258. package/src/turn-initiator.ts +8 -0
  259. package/src/user-resource-authority.ts +377 -0
  260. package/src/workspace-authority.ts +160 -0
  261. package/src/workspace-instruction-policies-schema.ts +53 -1
  262. package/src/workspace-instruction-policies.ts +528 -77
  263. package/src/workspace-learning-policy.ts +21 -5
  264. package/src/workspace-membership-permissions.ts +9 -0
  265. package/dist/chunk-5KTIEDX7.js.map +0 -1
  266. package/dist/chunk-FPVAD4CO.js +0 -117
  267. package/dist/chunk-FPVAD4CO.js.map +0 -1
  268. package/dist/chunk-HSOWSYOX.js.map +0 -1
  269. package/dist/chunk-SK7YYHBI.js.map +0 -1
  270. package/dist/chunk-VKLB2ZGI.js +0 -2389
  271. package/dist/chunk-VKLB2ZGI.js.map +0 -1
  272. package/dist/chunk-Z7VYMNPZ.js.map +0 -1
  273. /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
  274. /package/dist/{chunk-VTPRIXKG.js.map → chunk-NJVZPWXY.js.map} +0 -0
@@ -0,0 +1,189 @@
1
+ -- deployment-mode: rolling
2
+ -- Two things per-channel Slack routing needs from storage once the routed
3
+ -- workspace and the installation's workspace can actually differ.
4
+ --
5
+ -- 1. A Slack button click arrives on an inbox row that carries HOME tenancy and
6
+ -- names one action handle by id. The handle lives in the workspace that owns
7
+ -- its session, which is TARGET, and its RESTRICTIVE session-visibility policy
8
+ -- resolves the session under the handle's own scope. Without a way to learn
9
+ -- that scope from the id, every routed Status/Stop/Approve click reads under
10
+ -- HOME, finds nothing, and is refused as an invalid handle.
11
+ --
12
+ -- 2. `slack_shared_task_origins` carries TWO composite foreign keys on the SAME
13
+ -- (account_id, workspace_id) pair: one to `slack_interactions` and one to
14
+ -- `slack_task_policy_revisions`. The interaction is TARGET and the Slack task
15
+ -- policy stays HOME by explicit decision, because it governs what may be read
16
+ -- out of the Slack conversation rather than who the task belongs to. Once the
17
+ -- two differ, no value of that pair satisfies both constraints and every
18
+ -- private-handoff task in a routed workspace fails at insert.
19
+ --
20
+ -- Rolling: the probe is additive, and the shared-task-origin columns are
21
+ -- nullable with the existing rows backfilled to their own tenancy, so an old
22
+ -- image that writes neither column keeps working exactly as it does today.
23
+
24
+ SET LOCAL lock_timeout = '5s';
25
+ SET LOCAL statement_timeout = '10min';
26
+
27
+ -- `slack_interaction_action_handles` carries a RESTRICTIVE
28
+ -- `session_visibility_isolation` policy whose helper resolves the handle's
29
+ -- session under the CURRENT scope. A permissive policy cannot open that: a
30
+ -- restrictive policy is ANDed, and weakening it would weaken session visibility
31
+ -- itself. So the tenancy is not read out of the handle table at all. A private,
32
+ -- ids-only mapping is maintained by a trigger on the handle table and lives in
33
+ -- `opengeni_private`, where the runtime role has no privileges and the definer
34
+ -- probe is the only reader.
35
+ --
36
+ -- Content-free by construction: handle id, connection id, and the tenancy pair.
37
+ -- No action kind, no target value, no subject, no session content. The caller
38
+ -- must still re-read the full handle under the returned tenancy's own RLS, which
39
+ -- is where every existing authorization check already lives.
40
+ CREATE TABLE opengeni_private.slack_action_handle_tenancy (
41
+ "handle_id" uuid PRIMARY KEY,
42
+ "connection_id" uuid NOT NULL,
43
+ "account_id" uuid NOT NULL,
44
+ "workspace_id" uuid NOT NULL
45
+ );
46
+ REVOKE ALL ON TABLE opengeni_private.slack_action_handle_tenancy FROM PUBLIC;
47
+
48
+ CREATE FUNCTION opengeni_private.sync_slack_action_handle_tenancy()
49
+ RETURNS trigger
50
+ LANGUAGE plpgsql
51
+ SECURITY DEFINER
52
+ SET search_path = pg_catalog
53
+ AS $$
54
+ BEGIN
55
+ IF TG_OP = 'DELETE' THEN
56
+ DELETE FROM opengeni_private.slack_action_handle_tenancy
57
+ WHERE handle_id = OLD.id;
58
+ RETURN OLD;
59
+ END IF;
60
+ INSERT INTO opengeni_private.slack_action_handle_tenancy (
61
+ handle_id, connection_id, account_id, workspace_id
62
+ ) VALUES (NEW.id, NEW.connection_id, NEW.account_id, NEW.workspace_id)
63
+ ON CONFLICT (handle_id) DO UPDATE
64
+ SET connection_id = EXCLUDED.connection_id,
65
+ account_id = EXCLUDED.account_id,
66
+ workspace_id = EXCLUDED.workspace_id;
67
+ RETURN NEW;
68
+ END
69
+ $$;
70
+ REVOKE ALL ON FUNCTION opengeni_private.sync_slack_action_handle_tenancy() FROM PUBLIC;
71
+
72
+ DO $slack_handle_trigger$
73
+ DECLARE data_schema text := current_schema();
74
+ BEGIN
75
+ EXECUTE format(
76
+ 'CREATE TRIGGER slack_action_handle_tenancy_sync
77
+ AFTER INSERT OR UPDATE OF account_id, workspace_id, connection_id OR DELETE
78
+ ON %I.slack_interaction_action_handles
79
+ FOR EACH ROW EXECUTE FUNCTION opengeni_private.sync_slack_action_handle_tenancy()',
80
+ data_schema
81
+ );
82
+ END
83
+ $slack_handle_trigger$;
84
+
85
+ -- FORCE ROW LEVEL SECURITY binds the table owner and no tenant GUC is set during
86
+ -- a migration, so reading the existing handles needs the owner-only posture
87
+ -- window. The app role stays policy-bound throughout.
88
+ ALTER TABLE "slack_interaction_action_handles" NO FORCE ROW LEVEL SECURITY;
89
+
90
+ INSERT INTO opengeni_private.slack_action_handle_tenancy (
91
+ handle_id, connection_id, account_id, workspace_id
92
+ )
93
+ SELECT H.id, H.connection_id, H.account_id, H.workspace_id
94
+ FROM "slack_interaction_action_handles" H
95
+ ON CONFLICT (handle_id) DO NOTHING;
96
+
97
+ ALTER TABLE "slack_interaction_action_handles" FORCE ROW LEVEL SECURITY;
98
+
99
+ DO $slack_handle_probe$
100
+ BEGIN
101
+ EXECUTE $ddl$
102
+ CREATE FUNCTION opengeni_private.resolve_slack_action_handle_tenancy(
103
+ p_connection_id uuid,
104
+ p_handle_id uuid
105
+ )
106
+ RETURNS TABLE (account_id uuid, workspace_id uuid)
107
+ LANGUAGE sql
108
+ STABLE
109
+ SECURITY DEFINER
110
+ SET search_path = opengeni_private, pg_catalog
111
+ AS $function$
112
+ SELECT T.account_id, T.workspace_id
113
+ FROM slack_action_handle_tenancy T
114
+ WHERE T.handle_id = p_handle_id
115
+ AND T.connection_id = p_connection_id
116
+ LIMIT 1
117
+ $function$
118
+ $ddl$;
119
+ END
120
+ $slack_handle_probe$;
121
+
122
+ REVOKE ALL ON FUNCTION opengeni_private.resolve_slack_action_handle_tenancy(uuid, uuid)
123
+ FROM PUBLIC;
124
+
125
+ -- The Slack task policy revision this origin froze is a HOME fact. Give it its
126
+ -- own tenancy pair so the row's own (account_id, workspace_id) stays free to be
127
+ -- the interaction's.
128
+ ALTER TABLE "slack_shared_task_origins"
129
+ ADD COLUMN "policy_account_id" uuid,
130
+ ADD COLUMN "policy_workspace_id" uuid;
131
+
132
+ -- Two owner-bound guards stand between this backfill and the rows it must reach.
133
+ --
134
+ -- FORCE ROW LEVEL SECURITY binds the table owner and no tenant GUC is set during
135
+ -- a migration, so a bare UPDATE would match ZERO rows and report success.
136
+ --
137
+ -- `slack_shared_task_origins_immutable` is an unconditional BEFORE UPDATE OR
138
+ -- DELETE trigger, so the same UPDATE would instead RAISE and abort this whole
139
+ -- migration on any deployment that has ever recorded one shared-task origin.
140
+ --
141
+ -- Relax both for exactly this statement. The value written is the one each row
142
+ -- already implied - before routing, the policy revision was always frozen in the
143
+ -- row's own workspace - so no evidence changes meaning. The app role stays
144
+ -- policy-bound and the immutability guard is restored immediately.
145
+ ALTER TABLE "slack_shared_task_origins" NO FORCE ROW LEVEL SECURITY;
146
+ ALTER TABLE "slack_shared_task_origins" DISABLE TRIGGER "slack_shared_task_origins_immutable";
147
+
148
+ UPDATE "slack_shared_task_origins"
149
+ SET "policy_account_id" = "account_id",
150
+ "policy_workspace_id" = "workspace_id"
151
+ WHERE "policy_account_id" IS NULL;
152
+
153
+ ALTER TABLE "slack_shared_task_origins" ENABLE TRIGGER "slack_shared_task_origins_immutable";
154
+ ALTER TABLE "slack_shared_task_origins" FORCE ROW LEVEL SECURITY;
155
+
156
+ ALTER TABLE "slack_shared_task_origins"
157
+ DROP CONSTRAINT "slack_shared_task_origins_policy_fk";
158
+
159
+ ALTER TABLE "slack_shared_task_origins"
160
+ ADD CONSTRAINT "slack_shared_task_origins_policy_home_fk"
161
+ FOREIGN KEY ("policy_account_id", "policy_workspace_id", "policy_revision_id")
162
+ REFERENCES "slack_task_policy_revisions"("account_id", "workspace_id", "id")
163
+ ON DELETE RESTRICT NOT VALID;
164
+
165
+ ALTER TABLE "slack_shared_task_origins"
166
+ VALIDATE CONSTRAINT "slack_shared_task_origins_policy_home_fk";
167
+
168
+ ALTER TABLE "slack_shared_task_origins"
169
+ ADD CONSTRAINT "slack_shared_task_origins_policy_home_chk"
170
+ CHECK (("policy_account_id" IS NULL) = ("policy_workspace_id" IS NULL)) NOT VALID;
171
+
172
+ ALTER TABLE "slack_shared_task_origins"
173
+ VALIDATE CONSTRAINT "slack_shared_task_origins_policy_home_chk";
174
+
175
+ DO $grants$
176
+ BEGIN
177
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
178
+ GRANT EXECUTE ON FUNCTION
179
+ opengeni_private.resolve_slack_action_handle_tenancy(uuid, uuid) TO opengeni_app;
180
+ REVOKE ALL ON TABLE opengeni_private.slack_action_handle_tenancy FROM opengeni_app;
181
+ END IF;
182
+ END
183
+ $grants$;
184
+
185
+ COMMENT ON COLUMN "slack_shared_task_origins"."policy_workspace_id" IS
186
+ 'Home tenancy of the frozen Slack task policy revision; null on rows written before Slack workspace routing.';
187
+
188
+ RESET statement_timeout;
189
+ RESET lock_timeout;
@@ -0,0 +1,410 @@
1
+ -- deployment-mode: maintenance
2
+ -- Extend accepted-turn personal-resource attachments to the selected user-owned
3
+ -- Connected Machine. The attachment summary and protocol-v1 attempt snapshot
4
+ -- now admit a third resource kind, so every API/control/turn worker must be
5
+ -- stopped before this cutover and no pre-0338 worker may restart afterwards.
6
+
7
+ SET LOCAL lock_timeout = '5s';
8
+ SET LOCAL statement_timeout = '10min';
9
+
10
+ DO $atomic_connected_machine_writer_drain_before_lock$
11
+ DECLARE
12
+ configured_roles_text text := nullif(
13
+ current_setting('opengeni.migration_application_roles', true), ''
14
+ );
15
+ configured_roles jsonb;
16
+ BEGIN
17
+ IF configured_roles_text IS NULL THEN
18
+ RAISE EXCEPTION
19
+ '0338 atomic Connected Machine attachment requires an explicit application database role list'
20
+ USING ERRCODE = '55000';
21
+ END IF;
22
+ BEGIN
23
+ configured_roles := configured_roles_text::jsonb;
24
+ EXCEPTION WHEN OTHERS THEN
25
+ RAISE EXCEPTION
26
+ '0338 atomic Connected Machine attachment received a malformed application database role list'
27
+ USING ERRCODE = '55000';
28
+ END;
29
+ IF jsonb_typeof(configured_roles) <> 'array'
30
+ OR jsonb_array_length(configured_roles) NOT BETWEEN 1 AND 16
31
+ OR EXISTS (
32
+ SELECT 1 FROM jsonb_array_elements(configured_roles) AS roles(value)
33
+ WHERE jsonb_typeof(value) <> 'string'
34
+ OR btrim(value #>> '{}') = ''
35
+ OR octet_length(value #>> '{}') > 63
36
+ )
37
+ OR (
38
+ SELECT count(*) FROM jsonb_array_elements_text(configured_roles)
39
+ ) <> (
40
+ SELECT count(DISTINCT value)
41
+ FROM jsonb_array_elements_text(configured_roles) AS roles(value)
42
+ )
43
+ THEN
44
+ RAISE EXCEPTION
45
+ '0338 atomic Connected Machine attachment received an invalid application database role list'
46
+ USING ERRCODE = '55000';
47
+ END IF;
48
+ IF EXISTS (
49
+ SELECT 1 FROM pg_stat_activity activity
50
+ JOIN jsonb_array_elements_text(configured_roles) roles(role_name)
51
+ ON roles.role_name = activity.usename
52
+ WHERE activity.datname = current_database()
53
+ AND activity.pid <> pg_backend_pid()
54
+ )
55
+ THEN
56
+ RAISE EXCEPTION
57
+ '0338 atomic Connected Machine attachment requires all configured OpenGeni application database sessions to be stopped'
58
+ USING ERRCODE = '55000';
59
+ END IF;
60
+ END
61
+ $atomic_connected_machine_writer_drain_before_lock$;
62
+
63
+ LOCK TABLE sessions IN ACCESS EXCLUSIVE MODE;
64
+ LOCK TABLE session_turns IN ACCESS EXCLUSIVE MODE;
65
+ LOCK TABLE session_turn_attempts IN ACCESS EXCLUSIVE MODE;
66
+ LOCK TABLE turn_personal_resource_attachment_receipts IN ACCESS EXCLUSIVE MODE;
67
+ LOCK TABLE turn_personal_resource_snapshots IN ACCESS EXCLUSIVE MODE;
68
+ LOCK TABLE session_attempt_personal_resource_snapshots IN ACCESS EXCLUSIVE MODE;
69
+ LOCK TABLE enrollments IN ACCESS EXCLUSIVE MODE;
70
+ LOCK TABLE sandboxes IN ACCESS EXCLUSIVE MODE;
71
+
72
+ DO $atomic_connected_machine_writer_drain_after_lock$
73
+ DECLARE
74
+ configured_roles jsonb := current_setting(
75
+ 'opengeni.migration_application_roles', false
76
+ )::jsonb;
77
+ BEGIN
78
+ IF EXISTS (
79
+ SELECT 1 FROM pg_stat_activity activity
80
+ JOIN jsonb_array_elements_text(configured_roles) roles(role_name)
81
+ ON roles.role_name = activity.usename
82
+ WHERE activity.datname = current_database()
83
+ AND activity.pid <> pg_backend_pid()
84
+ )
85
+ THEN
86
+ RAISE EXCEPTION
87
+ '0338 atomic Connected Machine attachment requires all configured OpenGeni application database sessions to be stopped'
88
+ USING ERRCODE = '55000';
89
+ END IF;
90
+ END
91
+ $atomic_connected_machine_writer_drain_after_lock$;
92
+
93
+ ALTER TABLE turn_personal_resource_attachment_receipts
94
+ DROP CONSTRAINT turn_personal_resource_attachment_receipts_identity_chk;
95
+ ALTER TABLE turn_personal_resource_attachment_receipts
96
+ ADD CONSTRAINT turn_personal_resource_attachment_receipts_identity_chk CHECK (
97
+ octet_length(initiating_human_subject_id) BETWEEN 1 AND 512
98
+ AND membership_authorization_revision > 0
99
+ AND session_authority_epoch > 0
100
+ AND grant_mode IN ('once', 'session', 'always')
101
+ AND session_visibility IN ('user_private', 'workspace_shared')
102
+ AND shared_output_warning_version = 1
103
+ AND resource_count BETWEEN 1 AND 28
104
+ AND (session_visibility <> 'workspace_shared' OR shared_output_acknowledged IS TRUE)
105
+ );
106
+
107
+ ALTER TABLE turn_personal_resource_snapshots
108
+ DROP CONSTRAINT turn_personal_resource_snapshots_kind_chk;
109
+ ALTER TABLE turn_personal_resource_snapshots
110
+ ADD CONSTRAINT turn_personal_resource_snapshots_kind_chk CHECK (
111
+ (resource_kind = 'variable_set' AND action = 'variable_set.use'
112
+ AND resource_version_id IS NULL)
113
+ OR (resource_kind = 'rig' AND action = 'rig.use'
114
+ AND resource_version_id IS NOT NULL)
115
+ OR (resource_kind = 'connected_machine' AND action = 'connected_machine.use'
116
+ AND resource_version_id IS NULL)
117
+ );
118
+
119
+ ALTER TABLE session_attempt_personal_resource_snapshots
120
+ DROP CONSTRAINT session_attempt_personal_resource_snapshots_kind_chk;
121
+ ALTER TABLE session_attempt_personal_resource_snapshots
122
+ ADD CONSTRAINT session_attempt_personal_resource_snapshots_kind_chk CHECK (
123
+ (resource_kind = 'variable_set' AND resource_version_id IS NULL)
124
+ OR (resource_kind = 'rig' AND resource_version_id IS NOT NULL)
125
+ OR (resource_kind = 'connected_machine' AND resource_version_id IS NULL)
126
+ );
127
+ ALTER TABLE session_attempt_personal_resource_snapshots
128
+ DROP CONSTRAINT session_attempt_personal_resource_snapshots_action_chk;
129
+ ALTER TABLE session_attempt_personal_resource_snapshots
130
+ ADD CONSTRAINT session_attempt_personal_resource_snapshots_action_chk CHECK (
131
+ (resource_kind = 'variable_set' AND action = 'variable_set.use')
132
+ OR (resource_kind = 'rig' AND action = 'rig.use')
133
+ OR (resource_kind = 'connected_machine' AND action = 'connected_machine.use')
134
+ );
135
+
136
+ -- The source-patch block contains the replacement function's enrollment and
137
+ -- sandbox reads. The production migrator is a NON-superuser/NOBYPASSRLS owner,
138
+ -- so make those references owner-visible inside this exact transaction-local
139
+ -- window. A failure rolls the complete migration back, including FORCE state.
140
+ ALTER TABLE enrollments NO FORCE ROW LEVEL SECURITY;
141
+ ALTER TABLE sandboxes NO FORCE ROW LEVEL SECURITY;
142
+
143
+ -- The 0306 function is long and security-sensitive. Patch only its four exact,
144
+ -- previously shipped source fragments and abort if any expected fragment is
145
+ -- absent. Recreating the signature explicitly preserves the hardened search
146
+ -- path while keeping this migration reviewable as a narrow protocol extension.
147
+ DO $extend_atomic_attachment_function$
148
+ DECLARE
149
+ data_schema text := current_schema();
150
+ function_source text;
151
+ prior_source text;
152
+ BEGIN
153
+ SELECT procedure_value.prosrc INTO STRICT function_source
154
+ FROM pg_proc procedure_value
155
+ JOIN pg_namespace namespace_value ON namespace_value.oid = procedure_value.pronamespace
156
+ WHERE namespace_value.nspname = data_schema
157
+ AND procedure_value.oid = (
158
+ pg_catalog.format(
159
+ '%I.accept_turn_personal_resource_attachment(uuid,uuid,uuid,uuid,text,integer,boolean,integer)',
160
+ data_schema
161
+ )::regprocedure
162
+ );
163
+
164
+ prior_source := function_source;
165
+ function_source := replace(function_source,
166
+ $old$ FOR SHARE OF variable_set;
167
+
168
+ WITH selected AS ($old$,
169
+ $new$ FOR SHARE OF variable_set;
170
+ PERFORM sandbox.id
171
+ FROM sandboxes sandbox
172
+ WHERE sandbox.id = session_row.active_sandbox_id
173
+ AND sandbox.account_id = p_account_id
174
+ AND sandbox.kind = 'selfhosted'
175
+ FOR SHARE;
176
+ PERFORM enrollment.id
177
+ FROM sandboxes sandbox
178
+ JOIN enrollments enrollment
179
+ ON enrollment.id = sandbox.enrollment_id
180
+ AND enrollment.account_id = p_account_id
181
+ WHERE sandbox.id = session_row.active_sandbox_id
182
+ AND sandbox.account_id = p_account_id
183
+ AND sandbox.kind = 'selfhosted'
184
+ AND enrollment.authority_scope = 'user'
185
+ FOR SHARE OF enrollment;
186
+
187
+ WITH selected AS ($new$
188
+ );
189
+ IF function_source = prior_source THEN
190
+ RAISE EXCEPTION '0338 could not extend the atomic attachment lock set'
191
+ USING ERRCODE = '55000';
192
+ END IF;
193
+
194
+ prior_source := function_source;
195
+ function_source := replace(function_source,
196
+ $old$ WHERE version_value.id = session_row.rig_version_id
197
+ AND version_value.rig_id = session_row.rig_id
198
+ AND version_value.account_id = p_account_id
199
+ ), grouped AS ($old$,
200
+ $new$ WHERE version_value.id = session_row.rig_version_id
201
+ AND version_value.rig_id = session_row.rig_id
202
+ AND version_value.account_id = p_account_id
203
+ UNION ALL
204
+ SELECT 'connected_machine', enrollment.id, NULL::uuid,
205
+ 'connected_machine.use', 'session_active_sandbox',
206
+ enrollment.origin_workspace_id, enrollment.authority_id,
207
+ enrollment.owner_organization_membership_id
208
+ FROM sandboxes sandbox
209
+ JOIN enrollments enrollment
210
+ ON enrollment.id = sandbox.enrollment_id
211
+ AND enrollment.account_id = p_account_id
212
+ WHERE sandbox.id = session_row.active_sandbox_id
213
+ AND sandbox.account_id = p_account_id
214
+ AND sandbox.kind = 'selfhosted'
215
+ AND enrollment.authority_scope = 'user'
216
+ AND enrollment.status = 'active'
217
+ ), grouped AS ($new$
218
+ );
219
+ IF function_source = prior_source THEN
220
+ RAISE EXCEPTION '0338 could not extend the atomic attachment closure'
221
+ USING ERRCODE = '55000';
222
+ END IF;
223
+
224
+ prior_source := function_source;
225
+ function_source := replace(
226
+ function_source,
227
+ 'no personal Variable Set or Rig is selected by this session',
228
+ 'no personal Variable Set, Rig, or Connected Machine is selected by this session'
229
+ );
230
+ IF function_source = prior_source THEN
231
+ RAISE EXCEPTION '0338 could not update the empty attachment diagnostic'
232
+ USING ERRCODE = '55000';
233
+ END IF;
234
+ function_source := replace(
235
+ function_source,
236
+ 'personal Variable Set/Rig closure exceeds the accepted-work bound',
237
+ 'personal resource closure exceeds the accepted-work bound'
238
+ );
239
+ function_source := replace(function_source, 'IF selected_count > 27 THEN',
240
+ 'IF selected_count > 28 THEN');
241
+ IF function_source NOT LIKE '%IF selected_count > 28 THEN%'
242
+ OR function_source LIKE '%IF selected_count > 27 THEN%'
243
+ THEN
244
+ RAISE EXCEPTION '0338 could not update the attachment bound'
245
+ USING ERRCODE = '55000';
246
+ END IF;
247
+
248
+ EXECUTE pg_catalog.format(
249
+ 'CREATE OR REPLACE FUNCTION %I.accept_turn_personal_resource_attachment('
250
+ || 'p_account_id uuid, p_workspace_id uuid, p_session_id uuid, p_turn_id uuid, '
251
+ || 'p_mode text, p_expected_authority_epoch integer, '
252
+ || 'p_workspace_shared_acknowledged boolean, '
253
+ || 'p_shared_output_warning_version integer) '
254
+ || 'RETURNS TABLE (grant_mode text, grant_context text, resource_count integer, '
255
+ || 'resource_kinds text[], shared_output_warning_version integer, replay boolean) '
256
+ || 'LANGUAGE plpgsql SECURITY DEFINER '
257
+ || 'SET search_path TO pg_catalog, %I, pg_temp AS %L',
258
+ data_schema, data_schema, function_source
259
+ );
260
+ END
261
+ $extend_atomic_attachment_function$;
262
+
263
+ ALTER TABLE enrollments FORCE ROW LEVEL SECURITY;
264
+ ALTER TABLE sandboxes FORCE ROW LEVEL SECURITY;
265
+
266
+ -- Protocol-v1 attachment admission runs before this alphabetically-later
267
+ -- trigger and has already validated/copy-frozen the complete accepted-turn
268
+ -- snapshot. Reuse that exact machine row, including a consumed `once` grant,
269
+ -- instead of selecting mutable grant state again. Version-0 turns keep the
270
+ -- pre-0338 trigger unchanged.
271
+ CREATE FUNCTION admit_session_attempt_personal_machine_v1() RETURNS trigger
272
+ LANGUAGE plpgsql
273
+ SECURITY DEFINER
274
+ SET search_path FROM CURRENT
275
+ AS $body$
276
+ DECLARE
277
+ session_row sessions%ROWTYPE;
278
+ sandbox_row sandboxes%ROWTYPE;
279
+ enrollment_row enrollments%ROWTYPE;
280
+ snapshot_row session_attempt_personal_resource_snapshots%ROWTYPE;
281
+ BEGIN
282
+ INSERT INTO opengeni_private.scoped_compute_capabilities(
283
+ backend_pid, transaction_id, capability_kind
284
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
285
+ ON CONFLICT DO NOTHING;
286
+
287
+ SELECT session_value.* INTO STRICT session_row
288
+ FROM sessions session_value
289
+ WHERE session_value.id = NEW.session_id
290
+ AND session_value.account_id = NEW.account_id
291
+ AND session_value.workspace_id = NEW.workspace_id
292
+ FOR SHARE;
293
+ IF session_row.active_sandbox_id IS NULL THEN
294
+ DELETE FROM opengeni_private.scoped_compute_capabilities
295
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
296
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
297
+ RETURN NEW;
298
+ END IF;
299
+
300
+ SELECT sandbox.* INTO sandbox_row
301
+ FROM sandboxes sandbox
302
+ WHERE sandbox.id = session_row.active_sandbox_id
303
+ AND sandbox.account_id = NEW.account_id
304
+ AND sandbox.kind = 'selfhosted'
305
+ FOR SHARE;
306
+ IF sandbox_row.enrollment_id IS NULL THEN
307
+ DELETE FROM opengeni_private.scoped_compute_capabilities
308
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
309
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
310
+ RETURN NEW;
311
+ END IF;
312
+
313
+ SELECT enrollment.* INTO enrollment_row
314
+ FROM enrollments enrollment
315
+ WHERE enrollment.id = sandbox_row.enrollment_id
316
+ AND enrollment.account_id = NEW.account_id
317
+ AND enrollment.authority_scope = 'user'
318
+ AND enrollment.status = 'active'
319
+ FOR SHARE;
320
+ IF enrollment_row.id IS NULL THEN
321
+ DELETE FROM opengeni_private.scoped_compute_capabilities
322
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
323
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
324
+ RETURN NEW;
325
+ END IF;
326
+
327
+ SELECT snapshot.* INTO STRICT snapshot_row
328
+ FROM session_attempt_personal_resource_snapshots snapshot
329
+ WHERE snapshot.attempt_id = NEW.id
330
+ AND snapshot.account_id = NEW.account_id
331
+ AND snapshot.workspace_id = NEW.workspace_id
332
+ AND snapshot.session_id = NEW.session_id
333
+ AND snapshot.turn_id = NEW.turn_id
334
+ AND snapshot.execution_generation = NEW.execution_generation
335
+ AND snapshot.resource_kind = 'connected_machine'
336
+ AND snapshot.resource_id = enrollment_row.id
337
+ AND snapshot.action = 'connected_machine.use';
338
+
339
+ IF snapshot_row.authority_id IS DISTINCT FROM enrollment_row.authority_id
340
+ OR snapshot_row.authority_generation IS DISTINCT FROM enrollment_row.generation
341
+ OR snapshot_row.owner_organization_membership_id
342
+ IS DISTINCT FROM enrollment_row.owner_organization_membership_id
343
+ OR snapshot_row.session_visibility IS DISTINCT FROM session_row.visibility
344
+ OR snapshot_row.session_authority_epoch IS DISTINCT FROM session_row.authority_epoch
345
+ THEN
346
+ RAISE EXCEPTION 'turn-bound personal machine snapshot is not current'
347
+ USING ERRCODE = '42501';
348
+ END IF;
349
+
350
+ INSERT INTO session_attempt_connected_machine_authorizations(
351
+ attempt_id, account_id, workspace_id, session_id, turn_id, execution_generation,
352
+ initiating_human_subject_id, owner_organization_membership_id,
353
+ membership_authorization_revision, enrollment_id, sandbox_id, authority_id,
354
+ authority_generation, enrollment_generation, session_visibility,
355
+ session_authority_epoch, grant_id, grant_generation, grant_mode
356
+ )
357
+ SELECT NEW.id, NEW.account_id, NEW.workspace_id, NEW.session_id, NEW.turn_id,
358
+ NEW.execution_generation, admission.initiating_human_subject_id,
359
+ snapshot_row.owner_organization_membership_id,
360
+ snapshot_row.membership_authorization_revision, enrollment_row.id, sandbox_row.id,
361
+ snapshot_row.authority_id, snapshot_row.authority_generation,
362
+ enrollment_row.generation, snapshot_row.session_visibility,
363
+ snapshot_row.session_authority_epoch, snapshot_row.grant_id,
364
+ snapshot_row.grant_generation, snapshot_row.grant_mode
365
+ FROM session_attempt_personal_resource_admissions admission
366
+ WHERE admission.attempt_id = NEW.id
367
+ AND admission.account_id = NEW.account_id
368
+ AND admission.workspace_id = NEW.workspace_id
369
+ AND admission.session_id = NEW.session_id
370
+ AND admission.turn_id = NEW.turn_id;
371
+ IF NOT FOUND THEN
372
+ RAISE EXCEPTION 'turn-bound personal machine admission is missing'
373
+ USING ERRCODE = '42501';
374
+ END IF;
375
+
376
+ DELETE FROM opengeni_private.scoped_compute_capabilities
377
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
378
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
379
+ AND capability_kind = 'write';
380
+ RETURN NEW;
381
+ EXCEPTION WHEN OTHERS THEN
382
+ DELETE FROM opengeni_private.scoped_compute_capabilities
383
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
384
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
385
+ RAISE;
386
+ END
387
+ $body$;
388
+
389
+ DROP TRIGGER z_session_attempt_personal_machine_admission ON session_turn_attempts;
390
+ CREATE TRIGGER z_session_attempt_personal_machine_admission_legacy
391
+ AFTER INSERT ON session_turn_attempts FOR EACH ROW
392
+ WHEN (NEW.personal_resource_protocol_version = 0)
393
+ EXECUTE FUNCTION admit_session_attempt_personal_machine();
394
+ CREATE TRIGGER zz_session_attempt_personal_machine_admission_v1
395
+ AFTER INSERT ON session_turn_attempts FOR EACH ROW
396
+ WHEN (NEW.personal_resource_protocol_version = 1)
397
+ EXECUTE FUNCTION admit_session_attempt_personal_machine_v1();
398
+
399
+ REVOKE ALL ON FUNCTION admit_session_attempt_personal_machine_v1() FROM PUBLIC;
400
+
401
+ DO $atomic_connected_machine_function_hardening$
402
+ DECLARE data_schema text := current_schema();
403
+ BEGIN
404
+ EXECUTE pg_catalog.format(
405
+ 'ALTER FUNCTION %I.admit_session_attempt_personal_machine_v1() '
406
+ || 'SET search_path TO pg_catalog, %I, pg_temp',
407
+ data_schema, data_schema
408
+ );
409
+ END
410
+ $atomic_connected_machine_function_hardening$;