@opengeni/db 1.0.1 → 3.2.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 (271) 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-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
  7. package/dist/chunk-2EH4WRHL.js.map +1 -0
  8. package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
  9. package/dist/chunk-6HMM2R5T.js +390 -0
  10. package/dist/chunk-6HMM2R5T.js.map +1 -0
  11. package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
  12. package/dist/chunk-AZHW7R5V.js.map +1 -0
  13. package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
  14. package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
  15. package/dist/chunk-KRLPEMLH.js.map +1 -0
  16. package/dist/chunk-NAB6FKFN.js +516 -0
  17. package/dist/chunk-NAB6FKFN.js.map +1 -0
  18. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  19. package/dist/chunk-SIBYBA2D.js.map +1 -0
  20. package/dist/chunk-UZNXG44K.js +4508 -0
  21. package/dist/chunk-UZNXG44K.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 +85 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +23 -4
  35. package/dist/editable-artifact-durable-export.js +2 -2
  36. package/dist/editable-artifacts.d.ts +2 -2
  37. package/dist/editable-artifacts.js +3 -3
  38. package/dist/governed-learning-activation-schema.d.ts +984 -0
  39. package/dist/governed-learning-activation.d.ts +98 -0
  40. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  41. package/dist/governed-learning-evaluator.d.ts +28 -0
  42. package/dist/index.d.ts +1606 -81
  43. package/dist/index.js +21898 -8147
  44. package/dist/index.js.map +1 -1
  45. package/dist/insights.d.ts +18 -0
  46. package/dist/integration-bindings.d.ts +1 -0
  47. package/dist/integration-facets.d.ts +30 -0
  48. package/dist/interaction-placement-loss.d.ts +22 -0
  49. package/dist/managed-human-provisioning.d.ts +25 -0
  50. package/dist/memory-domain.d.ts +3 -3
  51. package/dist/migrate.d.ts +11 -1
  52. package/dist/migrate.js +1 -1
  53. package/dist/new-session-drafts.d.ts +43 -5
  54. package/dist/organization-membership-backfill.d.ts +174 -0
  55. package/dist/organization-membership-lifecycle.d.ts +162 -0
  56. package/dist/pr-review.d.ts +107 -0
  57. package/dist/preference-registry-schema.d.ts +2 -0
  58. package/dist/preference-registry.d.ts +2 -0
  59. package/dist/provision-roles.js +1 -1
  60. package/dist/runtime-posture.d.ts +29 -8
  61. package/dist/schema.d.ts +24914 -13703
  62. package/dist/schema.js +99 -1
  63. package/dist/scoped-knowledge-schema.d.ts +52 -1
  64. package/dist/session-background-commands.d.ts +125 -0
  65. package/dist/session-background-commands.js +34 -0
  66. package/dist/session-background-commands.js.map +1 -0
  67. package/dist/session-control.d.ts +156 -3
  68. package/dist/session-goal-pacing.d.ts +68 -0
  69. package/dist/session-queue-commands.d.ts +43 -4
  70. package/dist/session-realtime-ledger.d.ts +2 -0
  71. package/dist/session-tenancy.d.ts +71 -1
  72. package/dist/session-tenancy.js +25 -3
  73. package/dist/session-tool-call-settlement.d.ts +9 -4
  74. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  75. package/dist/slack-routing.d.ts +268 -0
  76. package/dist/slack-task-policy-schema.d.ts +34 -0
  77. package/dist/slack-task-policy.d.ts +8 -0
  78. package/dist/slack-user-link-access.d.ts +28 -0
  79. package/dist/task-notes-schema.d.ts +594 -0
  80. package/dist/task-notes.d.ts +39 -0
  81. package/dist/turn-initiator.d.ts +2 -0
  82. package/dist/user-resource-authority.d.ts +109 -0
  83. package/dist/video-generation.js +3 -3
  84. package/dist/workspace-authority.d.ts +81 -0
  85. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  86. package/dist/workspace-instruction-policies.d.ts +62 -0
  87. package/dist/workspace-learning-policy.d.ts +1 -0
  88. package/dist/workspace-membership-permissions.d.ts +2 -0
  89. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  90. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  91. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  92. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  93. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  94. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  95. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  96. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  97. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  98. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  99. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  100. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  101. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  102. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  103. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  104. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  105. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  106. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  107. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  108. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  109. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  110. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  111. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  112. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  113. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  114. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  115. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  116. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  117. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  118. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  119. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  120. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  121. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  122. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  123. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  124. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  125. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  126. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  127. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  128. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  129. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  130. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  131. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  132. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  133. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  134. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  135. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  136. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  137. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  138. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  139. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  140. package/drizzle/0294_preference_activation_authority.sql +237 -0
  141. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  142. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  143. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  144. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  145. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  146. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  147. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  148. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  149. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  150. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  151. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  152. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  153. package/drizzle/0307_session_attention_state.sql +51 -0
  154. package/drizzle/0308_session_archives.sql +35 -0
  155. package/drizzle/0309_channel_project_pins.sql +6 -0
  156. package/drizzle/0310_channel_project_order.sql +27 -0
  157. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  158. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  159. package/drizzle/0313_private_child_session_authority.sql +365 -0
  160. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  161. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  162. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  163. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  164. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  165. package/drizzle/0319_event_triggered_automations.sql +254 -0
  166. package/drizzle/0320_pr_review_pack.sql +113 -0
  167. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  168. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  169. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  170. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  171. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  172. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  173. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  174. package/drizzle/0328_session_background_commands.sql +590 -0
  175. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  176. package/drizzle/0330_api_key_descriptions.sql +20 -0
  177. package/drizzle/0331_managed_organization_creation.sql +163 -0
  178. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  179. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  180. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  181. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  182. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  183. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  184. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  185. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  186. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  187. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
  188. package/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
  189. package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
  190. package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
  191. package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
  192. package/drizzle/0346_document_migration_audit_surface.sql +454 -0
  193. package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -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 +167 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +87 -2
  214. package/src/editable-artifacts-schema.ts +10 -5
  215. package/src/editable-artifacts.ts +21 -11
  216. package/src/governed-learning-activation-schema.ts +121 -0
  217. package/src/governed-learning-activation.ts +588 -0
  218. package/src/governed-learning-evaluator-schema.ts +72 -0
  219. package/src/governed-learning-evaluator.ts +217 -0
  220. package/src/index.ts +11676 -1550
  221. package/src/insights.ts +107 -0
  222. package/src/integration-bindings.ts +88 -6
  223. package/src/integration-facets.ts +287 -84
  224. package/src/interaction-placement-loss.ts +234 -0
  225. package/src/managed-human-provisioning.ts +116 -0
  226. package/src/memory-domain.ts +27 -32
  227. package/src/migrate.ts +77 -1
  228. package/src/new-session-drafts.ts +229 -35
  229. package/src/organization-membership-backfill.ts +735 -0
  230. package/src/organization-membership-lifecycle.ts +995 -0
  231. package/src/pr-review.ts +890 -0
  232. package/src/preference-registry.ts +31 -1
  233. package/src/provision-roles.ts +905 -6
  234. package/src/runtime-posture-cli.ts +2 -0
  235. package/src/runtime-posture.ts +1317 -72
  236. package/src/schema.ts +3316 -428
  237. package/src/scoped-knowledge-schema.ts +16 -8
  238. package/src/scoped-knowledge.ts +1 -1
  239. package/src/session-background-commands.ts +759 -0
  240. package/src/session-control.ts +640 -74
  241. package/src/session-goal-pacing.ts +126 -0
  242. package/src/session-queue-commands.ts +441 -85
  243. package/src/session-realtime-context.ts +4 -6
  244. package/src/session-realtime-ledger.ts +28 -14
  245. package/src/session-realtime-mirror.ts +1 -1
  246. package/src/session-tenancy.ts +410 -49
  247. package/src/session-tool-call-settlement.ts +38 -29
  248. package/src/slack-routing-personal-workspace.ts +67 -0
  249. package/src/slack-routing.ts +867 -0
  250. package/src/slack-task-policy-schema.ts +5 -0
  251. package/src/slack-task-policy.ts +18 -0
  252. package/src/slack-user-link-access.ts +138 -11
  253. package/src/task-notes-schema.ts +74 -0
  254. package/src/task-notes.ts +124 -2
  255. package/src/turn-initiator.ts +8 -0
  256. package/src/user-resource-authority.ts +377 -0
  257. package/src/workspace-authority.ts +160 -0
  258. package/src/workspace-instruction-policies-schema.ts +53 -1
  259. package/src/workspace-instruction-policies.ts +528 -77
  260. package/src/workspace-learning-policy.ts +21 -5
  261. package/src/workspace-membership-permissions.ts +9 -0
  262. package/dist/chunk-4SR4HKKA.js.map +0 -1
  263. package/dist/chunk-6ZYKCRFO.js.map +0 -1
  264. package/dist/chunk-NXAFLCQX.js +0 -2468
  265. package/dist/chunk-NXAFLCQX.js.map +0 -1
  266. package/dist/chunk-SK7YYHBI.js.map +0 -1
  267. package/dist/chunk-WD5ROSLL.js +0 -117
  268. package/dist/chunk-WD5ROSLL.js.map +0 -1
  269. package/dist/chunk-ZWREYEWA.js.map +0 -1
  270. /package/dist/{chunk-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
  271. /package/dist/{chunk-LTG3S6ZY.js.map → chunk-E6CLMKEE.js.map} +0 -0
@@ -0,0 +1,1255 @@
1
+ -- deployment-mode: rolling
2
+ -- Activate explicit organization, workspace, and organization+user ownership
3
+ -- for Variable Sets. Existing rows remain workspace-owned. User ownership is
4
+ -- derived only from the authenticated active organization member.
5
+
6
+ SET LOCAL lock_timeout = '5s';
7
+ SET LOCAL statement_timeout = '10min';
8
+
9
+ ALTER TABLE "workspace_variable_sets"
10
+ ADD COLUMN "generation" bigint NOT NULL DEFAULT 1,
11
+ ADD COLUMN "status" text NOT NULL DEFAULT 'active',
12
+ ADD COLUMN "revoked_at" timestamptz;
13
+
14
+ ALTER TABLE "workspace_variable_sets"
15
+ DROP CONSTRAINT "workspace_variable_sets_authority_scope_check",
16
+ DROP CONSTRAINT "workspace_variable_sets_authority_shape_check";
17
+
18
+ ALTER TABLE "workspace_variable_sets"
19
+ ADD CONSTRAINT "workspace_variable_sets_authority_scope_check"
20
+ CHECK ("authority_scope" IN ('organization', 'workspace', 'user')) NOT VALID,
21
+ ADD CONSTRAINT "workspace_variable_sets_authority_shape_check" CHECK (
22
+ (
23
+ "authority_scope" IN ('organization', 'workspace')
24
+ AND "authority_id" IS NULL
25
+ AND "owner_organization_membership_id" IS NULL
26
+ ) OR (
27
+ "authority_scope" = 'user'
28
+ AND "authority_id" IS NOT NULL
29
+ AND "owner_organization_membership_id" IS NOT NULL
30
+ )
31
+ ) NOT VALID,
32
+ ADD CONSTRAINT "workspace_variable_sets_generation_check"
33
+ CHECK ("generation" > 0) NOT VALID,
34
+ ADD CONSTRAINT "workspace_variable_sets_status_check"
35
+ CHECK ("status" IN ('active', 'revoked')) NOT VALID,
36
+ ADD CONSTRAINT "workspace_variable_sets_revocation_check" CHECK (
37
+ ("status" = 'active' AND "revoked_at" IS NULL)
38
+ OR ("status" = 'revoked' AND "revoked_at" IS NOT NULL)
39
+ ) NOT VALID;
40
+
41
+ ALTER TABLE "workspace_variable_sets"
42
+ VALIDATE CONSTRAINT "workspace_variable_sets_authority_scope_check",
43
+ VALIDATE CONSTRAINT "workspace_variable_sets_authority_shape_check",
44
+ VALIDATE CONSTRAINT "workspace_variable_sets_generation_check",
45
+ VALIDATE CONSTRAINT "workspace_variable_sets_status_check",
46
+ VALIDATE CONSTRAINT "workspace_variable_sets_revocation_check";
47
+
48
+ DROP INDEX "workspace_variable_sets_workspace_name_idx";
49
+ CREATE UNIQUE INDEX "workspace_variable_sets_workspace_name_active_idx"
50
+ ON "workspace_variable_sets" ("workspace_id", "name")
51
+ WHERE "authority_scope" = 'workspace' AND "status" = 'active';
52
+ CREATE UNIQUE INDEX "workspace_variable_sets_organization_name_active_idx"
53
+ ON "workspace_variable_sets" ("account_id", "name")
54
+ WHERE "authority_scope" = 'organization' AND "status" = 'active';
55
+ CREATE UNIQUE INDEX "workspace_variable_sets_user_name_active_idx"
56
+ ON "workspace_variable_sets" (
57
+ "account_id", "owner_organization_membership_id", "name"
58
+ ) WHERE "authority_scope" = 'user' AND "status" = 'active';
59
+ CREATE INDEX "workspace_variable_sets_account_scope_created_idx"
60
+ ON "workspace_variable_sets" ("account_id", "authority_scope", "created_at", "id")
61
+ WHERE "status" = 'active';
62
+
63
+ CREATE TABLE opengeni_private.variable_set_authority_capabilities (
64
+ "backend_pid" integer NOT NULL,
65
+ "transaction_id" xid8 NOT NULL,
66
+ "capability_kind" text NOT NULL,
67
+ "created_at" timestamptz NOT NULL DEFAULT clock_timestamp(),
68
+ CONSTRAINT "variable_set_authority_capabilities_kind_chk" CHECK (
69
+ "capability_kind" IN ('read', 'write', 'materialize')
70
+ ),
71
+ CONSTRAINT "variable_set_authority_capabilities_pk" PRIMARY KEY (
72
+ "backend_pid", "transaction_id", "capability_kind"
73
+ )
74
+ );
75
+ REVOKE ALL ON TABLE opengeni_private.variable_set_authority_capabilities FROM PUBLIC;
76
+
77
+ CREATE OR REPLACE FUNCTION opengeni_private.variable_set_authority_capability_active(
78
+ p_capability_kind text DEFAULT NULL
79
+ ) RETURNS boolean
80
+ LANGUAGE sql
81
+ STABLE
82
+ SECURITY DEFINER
83
+ SET search_path = pg_catalog
84
+ AS $capability_active$
85
+ SELECT EXISTS (
86
+ SELECT 1
87
+ FROM opengeni_private.variable_set_authority_capabilities capability
88
+ WHERE capability.backend_pid = pg_catalog.pg_backend_pid()
89
+ AND capability.transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
90
+ AND (
91
+ p_capability_kind IS NULL
92
+ OR capability.capability_kind = p_capability_kind
93
+ )
94
+ )
95
+ $capability_active$;
96
+ REVOKE ALL ON FUNCTION
97
+ opengeni_private.variable_set_authority_capability_active(text) FROM PUBLIC;
98
+
99
+ DO $variable_set_capability_policies$
100
+ DECLARE
101
+ data_schema text := current_schema();
102
+ migration_owner text := current_user;
103
+ table_name text;
104
+ BEGIN
105
+ FOREACH table_name IN ARRAY ARRAY[
106
+ 'workspace_variable_sets',
107
+ 'workspace_variable_set_variables',
108
+ 'organization_memberships',
109
+ 'workspace_memberships',
110
+ 'organization_user_resource_authorities',
111
+ 'organization_user_resource_grants',
112
+ 'sessions',
113
+ 'scheduled_tasks',
114
+ 'session_turns',
115
+ 'session_turn_attempts',
116
+ 'session_attempt_interruptions',
117
+ 'rig_versions'
118
+ ] LOOP
119
+ EXECUTE format(
120
+ 'CREATE POLICY variable_set_authority_capability_read ON %I.%I '
121
+ || 'FOR SELECT USING (current_user = %L AND '
122
+ || 'opengeni_private.variable_set_authority_capability_active())',
123
+ data_schema,
124
+ table_name,
125
+ migration_owner
126
+ );
127
+ END LOOP;
128
+
129
+ FOREACH table_name IN ARRAY ARRAY[
130
+ 'workspace_variable_sets',
131
+ 'workspace_variable_set_variables',
132
+ 'organization_user_resource_authorities',
133
+ 'organization_user_resource_grants'
134
+ ] LOOP
135
+ EXECUTE format(
136
+ 'CREATE POLICY variable_set_authority_capability_insert ON %I.%I '
137
+ || 'FOR INSERT WITH CHECK (current_user = %L AND '
138
+ || 'opengeni_private.variable_set_authority_capability_active(''write''))',
139
+ data_schema,
140
+ table_name,
141
+ migration_owner
142
+ );
143
+ EXECUTE format(
144
+ 'CREATE POLICY variable_set_authority_capability_update ON %I.%I '
145
+ || 'FOR UPDATE USING (current_user = %L AND '
146
+ || 'opengeni_private.variable_set_authority_capability_active(''write'')) '
147
+ || 'WITH CHECK (current_user = %L AND '
148
+ || 'opengeni_private.variable_set_authority_capability_active(''write''))',
149
+ data_schema,
150
+ table_name,
151
+ migration_owner,
152
+ migration_owner
153
+ );
154
+ EXECUTE format(
155
+ 'CREATE POLICY variable_set_authority_capability_delete ON %I.%I '
156
+ || 'FOR DELETE USING (current_user = %L AND '
157
+ || 'opengeni_private.variable_set_authority_capability_active(''write''))',
158
+ data_schema,
159
+ table_name,
160
+ migration_owner
161
+ );
162
+ END LOOP;
163
+ END
164
+ $variable_set_capability_policies$;
165
+
166
+ DO $scoped_variable_set_authority$
167
+ DECLARE
168
+ data_schema text := current_schema();
169
+ BEGIN
170
+ EXECUTE format($ddl$
171
+ CREATE OR REPLACE FUNCTION %1$I.create_scoped_variable_set(
172
+ p_account_id uuid,
173
+ p_workspace_id uuid,
174
+ p_scope text,
175
+ p_name text,
176
+ p_description text,
177
+ p_variables jsonb DEFAULT '[]'::jsonb,
178
+ p_allow_organization boolean DEFAULT false
179
+ ) RETURNS TABLE (
180
+ variable_set_id uuid,
181
+ authority_scope text,
182
+ generation bigint,
183
+ status text
184
+ )
185
+ LANGUAGE plpgsql
186
+ SECURITY DEFINER
187
+ SET search_path = %1$I, pg_catalog
188
+ AS $body$
189
+ DECLARE
190
+ caller_subject text := nullif(pg_catalog.current_setting('opengeni.subject_id', true), '');
191
+ owner_membership organization_memberships%%ROWTYPE;
192
+ created_id uuid := pg_catalog.gen_random_uuid();
193
+ created_authority_id uuid;
194
+ variable_count integer;
195
+ BEGIN
196
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
197
+ backend_pid, transaction_id, capability_kind
198
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
199
+ ON CONFLICT DO NOTHING;
200
+
201
+ IF p_account_id IS DISTINCT FROM nullif(
202
+ pg_catalog.current_setting('opengeni.account_id', true), ''
203
+ )::uuid
204
+ OR p_workspace_id IS DISTINCT FROM nullif(
205
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
206
+ )::uuid
207
+ THEN
208
+ RAISE EXCEPTION 'variable-set creation scope mismatch' USING ERRCODE = '42501';
209
+ END IF;
210
+ IF p_scope NOT IN ('organization', 'workspace', 'user')
211
+ OR nullif(btrim(p_name), '') IS NULL
212
+ OR length(p_name) > 120
213
+ OR p_description IS NOT NULL AND length(p_description) > 2000
214
+ OR pg_catalog.jsonb_typeof(p_variables) IS DISTINCT FROM 'array'
215
+ THEN
216
+ RAISE EXCEPTION 'invalid scoped variable-set creation request' USING ERRCODE = '22023';
217
+ END IF;
218
+
219
+ PERFORM 1 FROM workspaces workspace_value
220
+ WHERE workspace_value.id = p_workspace_id
221
+ AND workspace_value.account_id = p_account_id
222
+ FOR SHARE;
223
+ IF NOT FOUND THEN
224
+ RAISE EXCEPTION 'variable-set workspace is outside the organization'
225
+ USING ERRCODE = '42501';
226
+ END IF;
227
+
228
+ IF p_scope = 'organization' AND NOT p_allow_organization THEN
229
+ RAISE EXCEPTION 'organization variable-set creation requires account authority'
230
+ USING ERRCODE = '42501';
231
+ ELSIF p_scope = 'user' THEN
232
+ IF caller_subject IS NULL THEN
233
+ RAISE EXCEPTION 'user variable-set creation requires an authenticated subject'
234
+ USING ERRCODE = '42501';
235
+ END IF;
236
+ SELECT membership.* INTO STRICT owner_membership
237
+ FROM organization_memberships membership
238
+ WHERE membership.account_id = p_account_id
239
+ AND membership.subject_id = caller_subject
240
+ AND membership.status = 'active'
241
+ AND membership.revoked_at IS NULL
242
+ FOR SHARE;
243
+ IF owner_membership.personal_workspace_id IS DISTINCT FROM p_workspace_id THEN
244
+ PERFORM 1 FROM workspace_memberships workspace_membership
245
+ WHERE workspace_membership.account_id = p_account_id
246
+ AND workspace_membership.workspace_id = p_workspace_id
247
+ AND workspace_membership.subject_id = caller_subject
248
+ FOR KEY SHARE;
249
+ IF NOT FOUND THEN
250
+ RAISE EXCEPTION 'user variable-set owner lacks current workspace access'
251
+ USING ERRCODE = '42501';
252
+ END IF;
253
+ END IF;
254
+ created_authority_id := pg_catalog.gen_random_uuid();
255
+ INSERT INTO organization_user_resource_authorities (
256
+ id, account_id, organization_membership_id, resource_kind,
257
+ resource_id, origin_workspace_id, generation, status
258
+ ) VALUES (
259
+ created_authority_id, p_account_id, owner_membership.id, 'variable_set',
260
+ created_id, p_workspace_id, 1, 'active'
261
+ );
262
+ END IF;
263
+
264
+ SELECT count(*)::integer INTO variable_count
265
+ FROM pg_catalog.jsonb_array_elements(p_variables) item
266
+ WHERE pg_catalog.jsonb_typeof(item) = 'object'
267
+ AND item ? 'name' AND item ? 'valueEncrypted'
268
+ AND pg_catalog.jsonb_typeof(item -> 'name') = 'string'
269
+ AND pg_catalog.jsonb_typeof(item -> 'valueEncrypted') = 'string';
270
+ IF variable_count <> pg_catalog.jsonb_array_length(p_variables) THEN
271
+ RAISE EXCEPTION 'invalid encrypted variable-set values' USING ERRCODE = '22023';
272
+ END IF;
273
+
274
+ INSERT INTO workspace_variable_sets (
275
+ id, account_id, workspace_id, name, description, authority_scope,
276
+ authority_id, owner_organization_membership_id, origin_workspace_id,
277
+ generation, status
278
+ ) VALUES (
279
+ created_id, p_account_id, p_workspace_id, p_name, p_description, p_scope,
280
+ created_authority_id,
281
+ CASE WHEN p_scope = 'user' THEN owner_membership.id ELSE NULL END,
282
+ p_workspace_id, 1, 'active'
283
+ );
284
+
285
+ INSERT INTO workspace_variable_set_variables (
286
+ account_id, workspace_id, variable_set_id, name, value_encrypted
287
+ )
288
+ SELECT p_account_id, p_workspace_id, created_id,
289
+ item ->> 'name', item ->> 'valueEncrypted'
290
+ FROM pg_catalog.jsonb_array_elements(p_variables) item;
291
+
292
+ variable_set_id := created_id;
293
+ authority_scope := p_scope;
294
+ generation := 1;
295
+ status := 'active';
296
+ RETURN NEXT;
297
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
298
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
299
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
300
+ AND capability_kind = 'write';
301
+ RETURN;
302
+ EXCEPTION WHEN OTHERS THEN
303
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
304
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
305
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
306
+ AND capability_kind = 'write';
307
+ RAISE;
308
+ END
309
+ $body$;
310
+ $ddl$, data_schema);
311
+ END
312
+ $scoped_variable_set_authority$;
313
+
314
+ REVOKE ALL ON FUNCTION create_scoped_variable_set(
315
+ uuid, uuid, text, text, text, jsonb, boolean
316
+ ) FROM PUBLIC;
317
+ DO $grants$
318
+ BEGIN
319
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
320
+ GRANT EXECUTE ON FUNCTION create_scoped_variable_set(
321
+ uuid, uuid, text, text, text, jsonb, boolean
322
+ ) TO opengeni_app;
323
+ REVOKE ALL ON TABLE organization_user_resource_authorities FROM opengeni_app;
324
+ REVOKE ALL ON TABLE organization_user_resource_grants FROM opengeni_app;
325
+ END IF;
326
+ END
327
+ $grants$;
328
+
329
+ COMMENT ON COLUMN "workspace_variable_sets"."authority_scope" IS
330
+ 'Explicit owner scope: organization, workspace, or organization+user. Omitted legacy creation remains workspace-owned.';
331
+ COMMENT ON COLUMN "workspace_variable_sets"."generation" IS
332
+ 'Monotonic resource generation revalidated immediately before plaintext read or runtime materialization.';
333
+
334
+ DO $scoped_variable_set_functions$
335
+ DECLARE
336
+ data_schema text := current_schema();
337
+ BEGIN
338
+ EXECUTE format($ddl$
339
+ CREATE OR REPLACE FUNCTION %1$I.scoped_variable_set_actor_membership(
340
+ p_account_id uuid,
341
+ p_workspace_id uuid
342
+ ) RETURNS uuid
343
+ LANGUAGE plpgsql
344
+ SECURITY DEFINER
345
+ SET search_path = %1$I, pg_catalog
346
+ AS $body$
347
+ DECLARE
348
+ caller_subject text := nullif(pg_catalog.current_setting('opengeni.subject_id', true), '');
349
+ membership_id uuid;
350
+ personal_workspace_id uuid;
351
+ BEGIN
352
+ IF p_account_id IS DISTINCT FROM nullif(
353
+ pg_catalog.current_setting('opengeni.account_id', true), ''
354
+ )::uuid
355
+ OR p_workspace_id IS DISTINCT FROM nullif(
356
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
357
+ )::uuid
358
+ THEN
359
+ RAISE EXCEPTION 'variable-set actor scope mismatch' USING ERRCODE = '42501';
360
+ END IF;
361
+
362
+ SELECT membership.id, membership.personal_workspace_id
363
+ INTO membership_id, personal_workspace_id
364
+ FROM organization_memberships membership
365
+ WHERE membership.account_id = p_account_id
366
+ AND membership.subject_id = caller_subject
367
+ AND membership.status = 'active'
368
+ AND membership.revoked_at IS NULL
369
+ FOR SHARE;
370
+
371
+ -- Configured-key, delegated API-grant, and legacy internal callers may
372
+ -- predate organization memberships. They may operate on organization or
373
+ -- workspace sets only: a NULL membership id can never match a user-owned
374
+ -- set. Exact runtime materialization separately validates its canonical
375
+ -- session, turn, attempt, generation, and selected variable set.
376
+ IF membership_id IS NULL THEN
377
+ RETURN NULL;
378
+ END IF;
379
+
380
+ IF personal_workspace_id IS DISTINCT FROM p_workspace_id THEN
381
+ PERFORM 1
382
+ FROM workspace_memberships workspace_membership
383
+ WHERE workspace_membership.account_id = p_account_id
384
+ AND workspace_membership.workspace_id = p_workspace_id
385
+ AND workspace_membership.subject_id = caller_subject
386
+ FOR KEY SHARE;
387
+ IF NOT FOUND THEN
388
+ RAISE EXCEPTION 'variable-set actor lacks current workspace access'
389
+ USING ERRCODE = '42501';
390
+ END IF;
391
+ END IF;
392
+ RETURN membership_id;
393
+ END
394
+ $body$;
395
+ $ddl$, data_schema);
396
+
397
+ EXECUTE format($ddl$
398
+ CREATE OR REPLACE FUNCTION %1$I.scoped_variable_set_json(
399
+ p_variable_set_id uuid
400
+ ) RETURNS jsonb
401
+ LANGUAGE sql
402
+ STABLE
403
+ SECURITY DEFINER
404
+ SET search_path = %1$I, pg_catalog
405
+ AS $body$
406
+ SELECT pg_catalog.jsonb_build_object(
407
+ 'id', variable_set.id,
408
+ 'accountId', variable_set.account_id,
409
+ 'workspaceId', variable_set.workspace_id,
410
+ 'scope', variable_set.authority_scope,
411
+ 'generation', variable_set.generation,
412
+ 'status', variable_set.status,
413
+ 'name', variable_set.name,
414
+ 'description', variable_set.description,
415
+ 'variables', coalesce((
416
+ SELECT pg_catalog.jsonb_agg(
417
+ pg_catalog.jsonb_build_object(
418
+ 'name', variable.name,
419
+ 'version', variable.version,
420
+ 'createdAt', variable.created_at,
421
+ 'updatedAt', variable.updated_at
422
+ ) ORDER BY variable.name
423
+ )
424
+ FROM workspace_variable_set_variables variable
425
+ WHERE variable.variable_set_id = variable_set.id
426
+ AND variable.account_id = variable_set.account_id
427
+ ), '[]'::jsonb),
428
+ 'createdAt', variable_set.created_at,
429
+ 'updatedAt', variable_set.updated_at
430
+ )
431
+ FROM workspace_variable_sets variable_set
432
+ WHERE variable_set.id = p_variable_set_id
433
+ $body$;
434
+ $ddl$, data_schema);
435
+
436
+ EXECUTE format($ddl$
437
+ CREATE OR REPLACE FUNCTION %1$I.list_scoped_variable_sets(
438
+ p_account_id uuid,
439
+ p_workspace_id uuid,
440
+ p_variable_set_id uuid DEFAULT NULL,
441
+ p_name text DEFAULT NULL,
442
+ p_scope text DEFAULT NULL
443
+ ) RETURNS SETOF jsonb
444
+ LANGUAGE plpgsql
445
+ SECURITY DEFINER
446
+ SET search_path = %1$I, pg_catalog
447
+ AS $body$
448
+ DECLARE
449
+ actor_membership_id uuid;
450
+ variable_set_row record;
451
+ BEGIN
452
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
453
+ backend_pid, transaction_id, capability_kind
454
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
455
+ ON CONFLICT DO NOTHING;
456
+ actor_membership_id := scoped_variable_set_actor_membership(
457
+ p_account_id, p_workspace_id
458
+ );
459
+ IF p_scope IS NOT NULL AND p_scope NOT IN ('organization', 'workspace', 'user') THEN
460
+ RAISE EXCEPTION 'invalid variable-set scope' USING ERRCODE = '22023';
461
+ END IF;
462
+
463
+ FOR variable_set_row IN
464
+ SELECT variable_set.id
465
+ FROM workspace_variable_sets variable_set
466
+ WHERE variable_set.account_id = p_account_id
467
+ AND variable_set.status = 'active'
468
+ AND (p_variable_set_id IS NULL OR variable_set.id = p_variable_set_id)
469
+ AND (p_name IS NULL OR variable_set.name = p_name)
470
+ AND (p_scope IS NULL OR variable_set.authority_scope = p_scope)
471
+ AND (
472
+ variable_set.authority_scope = 'organization'
473
+ OR (
474
+ variable_set.authority_scope = 'workspace'
475
+ AND variable_set.workspace_id = p_workspace_id
476
+ )
477
+ OR (
478
+ variable_set.authority_scope = 'user'
479
+ AND variable_set.owner_organization_membership_id = actor_membership_id
480
+ )
481
+ )
482
+ ORDER BY
483
+ CASE variable_set.authority_scope
484
+ WHEN 'user' THEN 1 WHEN 'workspace' THEN 2 ELSE 3
485
+ END,
486
+ variable_set.created_at,
487
+ variable_set.id
488
+ LOOP
489
+ RETURN NEXT scoped_variable_set_json(variable_set_row.id);
490
+ END LOOP;
491
+
492
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
493
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
494
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
495
+ AND capability_kind = 'read';
496
+ RETURN;
497
+ EXCEPTION WHEN OTHERS THEN
498
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
499
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
500
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
501
+ AND capability_kind = 'read';
502
+ RAISE;
503
+ END
504
+ $body$;
505
+ $ddl$, data_schema);
506
+
507
+ EXECUTE format($ddl$
508
+ CREATE OR REPLACE FUNCTION %1$I.count_scoped_variable_sets(
509
+ p_account_id uuid,
510
+ p_workspace_id uuid,
511
+ p_scope text
512
+ ) RETURNS integer
513
+ LANGUAGE plpgsql
514
+ SECURITY DEFINER
515
+ SET search_path = %1$I, pg_catalog
516
+ AS $body$
517
+ DECLARE
518
+ actor_membership_id uuid;
519
+ result_count integer;
520
+ BEGIN
521
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
522
+ backend_pid, transaction_id, capability_kind
523
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
524
+ ON CONFLICT DO NOTHING;
525
+ actor_membership_id := scoped_variable_set_actor_membership(
526
+ p_account_id, p_workspace_id
527
+ );
528
+ IF p_scope NOT IN ('organization', 'workspace', 'user') THEN
529
+ RAISE EXCEPTION 'invalid variable-set scope' USING ERRCODE = '22023';
530
+ END IF;
531
+ SELECT count(*)::integer INTO result_count
532
+ FROM workspace_variable_sets variable_set
533
+ WHERE variable_set.account_id = p_account_id
534
+ AND variable_set.authority_scope = p_scope
535
+ AND variable_set.status = 'active'
536
+ AND (
537
+ p_scope = 'organization'
538
+ OR (p_scope = 'workspace' AND variable_set.workspace_id = p_workspace_id)
539
+ OR (
540
+ p_scope = 'user'
541
+ AND variable_set.owner_organization_membership_id = actor_membership_id
542
+ )
543
+ );
544
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
545
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
546
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
547
+ AND capability_kind = 'read';
548
+ RETURN result_count;
549
+ EXCEPTION WHEN OTHERS THEN
550
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
551
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
552
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
553
+ AND capability_kind = 'read';
554
+ RAISE;
555
+ END
556
+ $body$;
557
+ $ddl$, data_schema);
558
+
559
+ EXECUTE format($ddl$
560
+ CREATE OR REPLACE FUNCTION %1$I.mutate_scoped_variable_set(
561
+ p_account_id uuid,
562
+ p_workspace_id uuid,
563
+ p_variable_set_id uuid,
564
+ p_operation text,
565
+ p_name text DEFAULT NULL,
566
+ p_name_present boolean DEFAULT false,
567
+ p_description text DEFAULT NULL,
568
+ p_description_present boolean DEFAULT false,
569
+ p_variable_name text DEFAULT NULL,
570
+ p_value_encrypted text DEFAULT NULL,
571
+ p_allow_organization boolean DEFAULT false
572
+ ) RETURNS jsonb
573
+ LANGUAGE plpgsql
574
+ SECURITY DEFINER
575
+ SET search_path = %1$I, pg_catalog
576
+ AS $body$
577
+ DECLARE
578
+ actor_membership_id uuid;
579
+ variable_set_row workspace_variable_sets%%ROWTYPE;
580
+ deleted_variable boolean := false;
581
+ attached_sessions integer;
582
+ attached_tasks integer;
583
+ mutation_result jsonb;
584
+ BEGIN
585
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
586
+ backend_pid, transaction_id, capability_kind
587
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
588
+ ON CONFLICT DO NOTHING;
589
+ actor_membership_id := scoped_variable_set_actor_membership(
590
+ p_account_id, p_workspace_id
591
+ );
592
+ IF p_operation NOT IN ('update', 'set_variable', 'delete_variable', 'revoke') THEN
593
+ RAISE EXCEPTION 'invalid variable-set mutation' USING ERRCODE = '22023';
594
+ END IF;
595
+
596
+ SELECT variable_set.* INTO STRICT variable_set_row
597
+ FROM workspace_variable_sets variable_set
598
+ WHERE variable_set.id = p_variable_set_id
599
+ AND variable_set.account_id = p_account_id
600
+ AND variable_set.status = 'active'
601
+ AND (
602
+ (
603
+ variable_set.authority_scope = 'organization'
604
+ AND p_allow_organization
605
+ )
606
+ OR (
607
+ variable_set.authority_scope = 'workspace'
608
+ AND variable_set.workspace_id = p_workspace_id
609
+ )
610
+ OR (
611
+ variable_set.authority_scope = 'user'
612
+ AND variable_set.owner_organization_membership_id = actor_membership_id
613
+ )
614
+ )
615
+ FOR UPDATE;
616
+
617
+ IF variable_set_row.authority_scope = 'organization' AND NOT p_allow_organization THEN
618
+ RAISE EXCEPTION 'organization variable-set mutation requires account authority'
619
+ USING ERRCODE = '42501';
620
+ END IF;
621
+
622
+ IF p_operation = 'update' THEN
623
+ IF p_name_present AND (nullif(btrim(p_name), '') IS NULL OR length(p_name) > 120) THEN
624
+ RAISE EXCEPTION 'invalid variable-set name' USING ERRCODE = '22023';
625
+ END IF;
626
+ IF p_description_present AND p_description IS NOT NULL
627
+ AND length(p_description) > 2000
628
+ THEN
629
+ RAISE EXCEPTION 'invalid variable-set description' USING ERRCODE = '22023';
630
+ END IF;
631
+ UPDATE workspace_variable_sets
632
+ SET name = CASE WHEN p_name_present THEN p_name ELSE name END,
633
+ description = CASE
634
+ WHEN p_description_present THEN p_description ELSE description
635
+ END,
636
+ updated_at = clock_timestamp()
637
+ WHERE id = variable_set_row.id;
638
+ ELSIF p_operation = 'set_variable' THEN
639
+ IF p_variable_name IS NULL OR p_value_encrypted IS NULL THEN
640
+ RAISE EXCEPTION 'variable name and encrypted value are required'
641
+ USING ERRCODE = '22023';
642
+ END IF;
643
+ INSERT INTO workspace_variable_set_variables (
644
+ account_id, workspace_id, variable_set_id, name, value_encrypted
645
+ ) VALUES (
646
+ p_account_id, variable_set_row.workspace_id, variable_set_row.id,
647
+ p_variable_name, p_value_encrypted
648
+ )
649
+ ON CONFLICT (workspace_id, variable_set_id, name)
650
+ DO UPDATE SET value_encrypted = excluded.value_encrypted,
651
+ version = workspace_variable_set_variables.version + 1,
652
+ updated_at = clock_timestamp();
653
+ UPDATE workspace_variable_sets
654
+ SET generation = generation + 1, updated_at = clock_timestamp()
655
+ WHERE id = variable_set_row.id;
656
+ IF variable_set_row.authority_scope = 'user' THEN
657
+ UPDATE organization_user_resource_authorities
658
+ SET generation = generation + 1, updated_at = clock_timestamp()
659
+ WHERE id = variable_set_row.authority_id
660
+ AND account_id = p_account_id
661
+ AND status = 'active';
662
+ END IF;
663
+ ELSIF p_operation = 'delete_variable' THEN
664
+ DELETE FROM workspace_variable_set_variables
665
+ WHERE account_id = p_account_id
666
+ AND variable_set_id = variable_set_row.id
667
+ AND name = p_variable_name;
668
+ GET DIAGNOSTICS attached_sessions = ROW_COUNT;
669
+ deleted_variable := attached_sessions = 1;
670
+ IF deleted_variable THEN
671
+ UPDATE workspace_variable_sets
672
+ SET generation = generation + 1, updated_at = clock_timestamp()
673
+ WHERE id = variable_set_row.id;
674
+ IF variable_set_row.authority_scope = 'user' THEN
675
+ UPDATE organization_user_resource_authorities
676
+ SET generation = generation + 1, updated_at = clock_timestamp()
677
+ WHERE id = variable_set_row.authority_id
678
+ AND account_id = p_account_id
679
+ AND status = 'active';
680
+ END IF;
681
+ END IF;
682
+ ELSE
683
+ SELECT count(*)::integer INTO attached_tasks
684
+ FROM scheduled_tasks task
685
+ WHERE task.account_id = p_account_id
686
+ AND task.variable_set_id = variable_set_row.id;
687
+ SELECT count(*)::integer INTO attached_sessions
688
+ FROM sessions session_value
689
+ WHERE session_value.account_id = p_account_id
690
+ AND session_value.variable_set_id = variable_set_row.id
691
+ AND session_value.status IN (
692
+ 'queued', 'running', 'requires_action', 'recovering', 'waiting_capacity'
693
+ );
694
+ IF attached_tasks > 0 OR attached_sessions > 0 THEN
695
+ RAISE EXCEPTION 'variable set remains attached to %% scheduled tasks and %% sessions',
696
+ attached_tasks, attached_sessions USING ERRCODE = '23503';
697
+ END IF;
698
+ IF variable_set_row.authority_scope = 'user' THEN
699
+ UPDATE organization_user_resource_authorities
700
+ SET status = 'revoked', revoked_at = clock_timestamp(),
701
+ generation = generation + 1, updated_at = clock_timestamp()
702
+ WHERE id = variable_set_row.authority_id
703
+ AND account_id = p_account_id
704
+ AND status = 'active';
705
+ UPDATE organization_user_resource_grants
706
+ SET status = 'revoked', revoked_at = clock_timestamp(),
707
+ generation = generation + 1, updated_at = clock_timestamp()
708
+ WHERE account_id = p_account_id
709
+ AND authority_id = variable_set_row.authority_id
710
+ AND status = 'active';
711
+ END IF;
712
+ DELETE FROM workspace_variable_sets
713
+ WHERE id = variable_set_row.id;
714
+ END IF;
715
+
716
+ variable_set_row.id := p_variable_set_id;
717
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
718
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
719
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
720
+ AND capability_kind = 'write';
721
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
722
+ backend_pid, transaction_id, capability_kind
723
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
724
+ ON CONFLICT DO NOTHING;
725
+ mutation_result := pg_catalog.jsonb_build_object(
726
+ 'variableSet', scoped_variable_set_json(variable_set_row.id),
727
+ 'deletedVariable', deleted_variable
728
+ );
729
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
730
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
731
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
732
+ AND capability_kind = 'read';
733
+ RETURN mutation_result;
734
+ EXCEPTION WHEN OTHERS THEN
735
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
736
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
737
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
738
+ AND capability_kind IN ('write', 'read');
739
+ RAISE;
740
+ END
741
+ $body$;
742
+ $ddl$, data_schema);
743
+
744
+ EXECUTE format($ddl$
745
+ CREATE OR REPLACE FUNCTION %1$I.assert_scoped_variable_set_attempt(
746
+ p_account_id uuid,
747
+ p_workspace_id uuid,
748
+ p_session_id uuid,
749
+ p_turn_id uuid,
750
+ p_attempt_id uuid,
751
+ p_execution_generation integer
752
+ ) RETURNS text
753
+ LANGUAGE plpgsql
754
+ SECURITY DEFINER
755
+ SET search_path = %1$I, pg_catalog
756
+ AS $body$
757
+ DECLARE
758
+ initiating_subject text;
759
+ caller_subject text := coalesce(
760
+ nullif(pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''),
761
+ nullif(pg_catalog.current_setting('opengeni.subject_id', true), '')
762
+ );
763
+ BEGIN
764
+ IF p_account_id IS DISTINCT FROM nullif(
765
+ pg_catalog.current_setting('opengeni.account_id', true), ''
766
+ )::uuid
767
+ OR p_workspace_id IS DISTINCT FROM nullif(
768
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
769
+ )::uuid
770
+ OR p_execution_generation <= 0
771
+ THEN
772
+ RAISE EXCEPTION 'variable-set attempt scope mismatch' USING ERRCODE = '42501';
773
+ END IF;
774
+ SELECT coalesce(
775
+ nullif(btrim(turn_value.initiating_human_subject_id), ''),
776
+ CASE WHEN turn_value.initiator_kind = 'subject'
777
+ THEN nullif(btrim(turn_value.initiator_subject_id), '') END
778
+ )
779
+ INTO STRICT initiating_subject
780
+ FROM sessions session_value
781
+ JOIN session_turns turn_value
782
+ ON turn_value.id = p_turn_id
783
+ AND turn_value.account_id = session_value.account_id
784
+ AND turn_value.workspace_id = session_value.workspace_id
785
+ AND turn_value.session_id = session_value.id
786
+ JOIN session_turn_attempts attempt
787
+ ON attempt.id = p_attempt_id
788
+ AND attempt.account_id = turn_value.account_id
789
+ AND attempt.workspace_id = turn_value.workspace_id
790
+ AND attempt.session_id = turn_value.session_id
791
+ AND attempt.turn_id = turn_value.id
792
+ WHERE session_value.id = p_session_id
793
+ AND session_value.account_id = p_account_id
794
+ AND session_value.workspace_id = p_workspace_id
795
+ AND session_value.active_turn_id = p_turn_id
796
+ AND turn_value.active_attempt_id = p_attempt_id
797
+ AND turn_value.execution_generation = p_execution_generation
798
+ AND turn_value.status = 'running'
799
+ AND attempt.execution_generation = p_execution_generation
800
+ AND attempt.state IN ('claimed', 'running')
801
+ AND attempt.closed_at IS NULL
802
+ AND attempt.quiesced_at IS NULL
803
+ AND attempt.authority_epoch = session_value.authority_epoch
804
+ AND attempt.authority_visibility = session_value.visibility
805
+ AND attempt.authority_owner_organization_membership_id
806
+ IS NOT DISTINCT FROM session_value.owner_organization_membership_id
807
+ AND NOT EXISTS (
808
+ SELECT 1 FROM session_attempt_interruptions interruption
809
+ WHERE interruption.account_id = p_account_id
810
+ AND interruption.workspace_id = p_workspace_id
811
+ AND interruption.session_id = p_session_id
812
+ AND interruption.attempt_id = p_attempt_id
813
+ AND interruption.state IN ('pending', 'delivered', 'acknowledged')
814
+ )
815
+ FOR SHARE OF session_value, turn_value
816
+ FOR UPDATE OF attempt;
817
+ IF initiating_subject IS NULL OR caller_subject IS DISTINCT FROM initiating_subject THEN
818
+ RAISE EXCEPTION 'variable-set attempt initiating human mismatch'
819
+ USING ERRCODE = '42501';
820
+ END IF;
821
+ RETURN initiating_subject;
822
+ EXCEPTION WHEN NO_DATA_FOUND THEN
823
+ RAISE EXCEPTION 'variable-set read requires the exact current uninterrupted attempt'
824
+ USING ERRCODE = '42501';
825
+ END
826
+ $body$;
827
+ $ddl$, data_schema);
828
+
829
+ EXECUTE format($ddl$
830
+ CREATE OR REPLACE FUNCTION %1$I.read_scoped_variable_set_secret(
831
+ p_account_id uuid,
832
+ p_workspace_id uuid,
833
+ p_variable_set_id uuid,
834
+ p_variable_set_name text,
835
+ p_variable_name text,
836
+ p_actor_kind text,
837
+ p_session_id uuid DEFAULT NULL,
838
+ p_turn_id uuid DEFAULT NULL,
839
+ p_attempt_id uuid DEFAULT NULL,
840
+ p_execution_generation integer DEFAULT NULL
841
+ ) RETURNS TABLE (
842
+ variable_set_id uuid,
843
+ variable_name text,
844
+ variable_version integer,
845
+ value_encrypted text,
846
+ authority_scope text,
847
+ variable_set_generation bigint
848
+ )
849
+ LANGUAGE plpgsql
850
+ SECURITY DEFINER
851
+ SET search_path = %1$I, pg_catalog
852
+ AS $body$
853
+ DECLARE
854
+ actor_membership_id uuid;
855
+ variable_set_row workspace_variable_sets%%ROWTYPE;
856
+ resolved_count integer;
857
+ audit_subject text := coalesce(
858
+ nullif(pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''),
859
+ nullif(pg_catalog.current_setting('opengeni.subject_id', true), '')
860
+ );
861
+ BEGIN
862
+ IF (p_variable_set_id IS NULL) = (p_variable_set_name IS NULL)
863
+ OR p_actor_kind NOT IN ('subject', 'agent_attempt')
864
+ THEN
865
+ RAISE EXCEPTION 'invalid exact variable-set read request' USING ERRCODE = '22023';
866
+ END IF;
867
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
868
+ backend_pid, transaction_id, capability_kind
869
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'materialize')
870
+ ON CONFLICT DO NOTHING;
871
+
872
+ IF p_actor_kind = 'subject' THEN
873
+ actor_membership_id := scoped_variable_set_actor_membership(
874
+ p_account_id, p_workspace_id
875
+ );
876
+ ELSE
877
+ audit_subject := assert_scoped_variable_set_attempt(
878
+ p_account_id, p_workspace_id, p_session_id, p_turn_id, p_attempt_id,
879
+ p_execution_generation
880
+ );
881
+ END IF;
882
+
883
+ SELECT variable_set.* INTO STRICT variable_set_row
884
+ FROM workspace_variable_sets variable_set
885
+ WHERE variable_set.account_id = p_account_id
886
+ AND variable_set.status = 'active'
887
+ AND (
888
+ (p_variable_set_id IS NOT NULL AND variable_set.id = p_variable_set_id)
889
+ OR (p_variable_set_name IS NOT NULL AND variable_set.name = p_variable_set_name)
890
+ )
891
+ AND (
892
+ variable_set.authority_scope = 'organization'
893
+ OR (
894
+ variable_set.authority_scope = 'workspace'
895
+ AND variable_set.workspace_id = p_workspace_id
896
+ )
897
+ OR (
898
+ variable_set.authority_scope = 'user'
899
+ AND (
900
+ (p_actor_kind = 'subject'
901
+ AND variable_set.owner_organization_membership_id = actor_membership_id)
902
+ OR p_actor_kind = 'agent_attempt'
903
+ )
904
+ )
905
+ )
906
+ ORDER BY CASE variable_set.authority_scope
907
+ WHEN 'user' THEN 1 WHEN 'workspace' THEN 2 ELSE 3 END
908
+ LIMIT 1
909
+ FOR SHARE;
910
+
911
+ IF p_actor_kind = 'agent_attempt' THEN
912
+ PERFORM 1 FROM sessions session_value
913
+ LEFT JOIN rig_versions rig_version
914
+ ON rig_version.id = session_value.rig_version_id
915
+ AND rig_version.rig_id = session_value.rig_id
916
+ AND rig_version.account_id = session_value.account_id
917
+ WHERE session_value.id = p_session_id
918
+ AND session_value.account_id = p_account_id
919
+ AND session_value.workspace_id = p_workspace_id
920
+ AND (
921
+ session_value.variable_set_id = variable_set_row.id
922
+ OR coalesce(rig_version.default_variable_set_ids, '[]'::jsonb)
923
+ ? variable_set_row.id::text
924
+ );
925
+ IF NOT FOUND THEN
926
+ RAISE EXCEPTION 'exact variable-set resource was not admitted for this attempt'
927
+ USING ERRCODE = '42501';
928
+ END IF;
929
+ IF variable_set_row.authority_scope = 'user' THEN
930
+ SELECT count(*)::integer INTO resolved_count
931
+ FROM resolve_session_attempt_personal_resources(
932
+ p_account_id, p_workspace_id, p_attempt_id
933
+ ) resolved
934
+ WHERE resolved.resource_kind = 'variable_set'
935
+ AND resolved.resource_id = variable_set_row.id
936
+ AND resolved.authority_id = variable_set_row.authority_id
937
+ AND resolved.authority_generation = variable_set_row.generation;
938
+ IF resolved_count <> 1 THEN
939
+ RAISE EXCEPTION 'personal variable-set grant is not exact or current'
940
+ USING ERRCODE = '42501';
941
+ END IF;
942
+ END IF;
943
+ END IF;
944
+
945
+ RETURN QUERY
946
+ SELECT variable_set_row.id, variable.name, variable.version,
947
+ variable.value_encrypted, variable_set_row.authority_scope,
948
+ variable_set_row.generation
949
+ FROM workspace_variable_set_variables variable
950
+ WHERE variable.account_id = p_account_id
951
+ AND variable.variable_set_id = variable_set_row.id
952
+ AND variable.name = p_variable_name;
953
+ IF FOUND THEN
954
+ INSERT INTO audit_events (
955
+ account_id, workspace_id, subject_id, action, target_type, target_id,
956
+ metadata, metadata_codec_version
957
+ ) VALUES (
958
+ p_account_id, p_workspace_id, audit_subject,
959
+ 'variable_set.variable.read', 'workspace_variable_set',
960
+ variable_set_row.id::text,
961
+ pg_catalog.jsonb_build_object(
962
+ 'variableSetId', variable_set_row.id,
963
+ 'name', p_variable_name,
964
+ 'actorKind', p_actor_kind,
965
+ 'scope', variable_set_row.authority_scope,
966
+ 'generation', variable_set_row.generation,
967
+ 'sessionId', p_session_id,
968
+ 'turnId', p_turn_id,
969
+ 'attemptId', p_attempt_id,
970
+ 'executionGeneration', p_execution_generation
971
+ ),
972
+ 1
973
+ );
974
+ END IF;
975
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
976
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
977
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
978
+ AND capability_kind = 'materialize';
979
+ RETURN;
980
+ EXCEPTION WHEN OTHERS THEN
981
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
982
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
983
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
984
+ AND capability_kind = 'materialize';
985
+ RAISE;
986
+ END
987
+ $body$;
988
+ $ddl$, data_schema);
989
+
990
+ EXECUTE format($ddl$
991
+ CREATE OR REPLACE FUNCTION %1$I.materialize_scoped_variable_set_for_attempt(
992
+ p_account_id uuid,
993
+ p_workspace_id uuid,
994
+ p_session_id uuid,
995
+ p_turn_id uuid,
996
+ p_attempt_id uuid,
997
+ p_execution_generation integer,
998
+ p_variable_set_id uuid
999
+ ) RETURNS TABLE (
1000
+ variable_set_id uuid,
1001
+ variable_set_name text,
1002
+ variable_set_description text,
1003
+ authority_scope text,
1004
+ variable_set_generation bigint,
1005
+ variable_name text,
1006
+ value_encrypted text
1007
+ )
1008
+ LANGUAGE plpgsql
1009
+ SECURITY DEFINER
1010
+ SET search_path = %1$I, pg_catalog
1011
+ AS $body$
1012
+ DECLARE
1013
+ initiating_subject text;
1014
+ variable_set_row workspace_variable_sets%%ROWTYPE;
1015
+ resolved_count integer;
1016
+ BEGIN
1017
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
1018
+ backend_pid, transaction_id, capability_kind
1019
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'materialize')
1020
+ ON CONFLICT DO NOTHING;
1021
+ initiating_subject := assert_scoped_variable_set_attempt(
1022
+ p_account_id, p_workspace_id, p_session_id, p_turn_id, p_attempt_id,
1023
+ p_execution_generation
1024
+ );
1025
+
1026
+ SELECT variable_set.* INTO STRICT variable_set_row
1027
+ FROM workspace_variable_sets variable_set
1028
+ WHERE variable_set.id = p_variable_set_id
1029
+ AND variable_set.account_id = p_account_id
1030
+ AND variable_set.status = 'active'
1031
+ FOR SHARE;
1032
+ PERFORM 1 FROM sessions session_value
1033
+ LEFT JOIN rig_versions rig_version
1034
+ ON rig_version.id = session_value.rig_version_id
1035
+ AND rig_version.rig_id = session_value.rig_id
1036
+ AND rig_version.account_id = session_value.account_id
1037
+ WHERE session_value.id = p_session_id
1038
+ AND session_value.account_id = p_account_id
1039
+ AND session_value.workspace_id = p_workspace_id
1040
+ AND (
1041
+ session_value.variable_set_id = variable_set_row.id
1042
+ OR coalesce(rig_version.default_variable_set_ids, '[]'::jsonb)
1043
+ ? variable_set_row.id::text
1044
+ );
1045
+ IF NOT FOUND THEN
1046
+ RAISE EXCEPTION 'runtime variable set was not selected by the exact session'
1047
+ USING ERRCODE = '42501';
1048
+ END IF;
1049
+ IF variable_set_row.authority_scope = 'workspace'
1050
+ AND variable_set_row.workspace_id IS DISTINCT FROM p_workspace_id
1051
+ THEN
1052
+ RAISE EXCEPTION 'workspace variable set is outside the runtime workspace'
1053
+ USING ERRCODE = '42501';
1054
+ ELSIF variable_set_row.authority_scope = 'user' THEN
1055
+ SELECT count(*)::integer INTO resolved_count
1056
+ FROM resolve_session_attempt_personal_resources(
1057
+ p_account_id, p_workspace_id, p_attempt_id
1058
+ ) resolved
1059
+ WHERE resolved.resource_kind = 'variable_set'
1060
+ AND resolved.resource_id = variable_set_row.id
1061
+ AND resolved.authority_id = variable_set_row.authority_id
1062
+ AND resolved.authority_generation = variable_set_row.generation;
1063
+ IF resolved_count <> 1 THEN
1064
+ RAISE EXCEPTION 'personal variable-set grant is not exact or current'
1065
+ USING ERRCODE = '42501';
1066
+ END IF;
1067
+ END IF;
1068
+
1069
+ INSERT INTO audit_events (
1070
+ account_id, workspace_id, subject_id, action, target_type, target_id,
1071
+ metadata, metadata_codec_version
1072
+ ) VALUES (
1073
+ p_account_id, p_workspace_id, initiating_subject,
1074
+ 'variable_set.materialized', 'workspace_variable_set',
1075
+ variable_set_row.id::text,
1076
+ pg_catalog.jsonb_build_object(
1077
+ 'variableSetId', variable_set_row.id,
1078
+ 'scope', variable_set_row.authority_scope,
1079
+ 'generation', variable_set_row.generation,
1080
+ 'sessionId', p_session_id,
1081
+ 'turnId', p_turn_id,
1082
+ 'attemptId', p_attempt_id,
1083
+ 'executionGeneration', p_execution_generation
1084
+ ),
1085
+ 1
1086
+ );
1087
+ RETURN QUERY
1088
+ SELECT selected.id, selected.name, selected.description,
1089
+ selected.authority_scope, selected.generation,
1090
+ variable.name, variable.value_encrypted
1091
+ FROM workspace_variable_sets selected
1092
+ LEFT JOIN workspace_variable_set_variables variable
1093
+ ON variable.account_id = selected.account_id
1094
+ AND variable.variable_set_id = selected.id
1095
+ WHERE selected.id = variable_set_row.id
1096
+ ORDER BY variable.name;
1097
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
1098
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
1099
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
1100
+ AND capability_kind = 'materialize';
1101
+ RETURN;
1102
+ EXCEPTION WHEN OTHERS THEN
1103
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
1104
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
1105
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
1106
+ AND capability_kind = 'materialize';
1107
+ RAISE;
1108
+ END
1109
+ $body$;
1110
+ $ddl$, data_schema);
1111
+
1112
+ EXECUTE format($ddl$
1113
+ CREATE OR REPLACE FUNCTION %1$I.materialize_scoped_variable_set_for_session(
1114
+ p_account_id uuid,
1115
+ p_workspace_id uuid,
1116
+ p_session_id uuid,
1117
+ p_variable_set_id uuid
1118
+ ) RETURNS TABLE (
1119
+ variable_set_id uuid,
1120
+ variable_set_name text,
1121
+ variable_set_description text,
1122
+ authority_scope text,
1123
+ variable_set_generation bigint,
1124
+ variable_name text,
1125
+ value_encrypted text
1126
+ )
1127
+ LANGUAGE plpgsql
1128
+ SECURITY DEFINER
1129
+ SET search_path = %1$I, pg_catalog
1130
+ AS $body$
1131
+ DECLARE
1132
+ variable_set_row workspace_variable_sets%%ROWTYPE;
1133
+ BEGIN
1134
+ IF p_account_id IS DISTINCT FROM nullif(
1135
+ pg_catalog.current_setting('opengeni.account_id', true), ''
1136
+ )::uuid
1137
+ OR p_workspace_id IS DISTINCT FROM nullif(
1138
+ pg_catalog.current_setting('opengeni.workspace_id', true), ''
1139
+ )::uuid
1140
+ THEN
1141
+ RAISE EXCEPTION 'variable-set session materialization scope mismatch'
1142
+ USING ERRCODE = '42501';
1143
+ END IF;
1144
+ INSERT INTO opengeni_private.variable_set_authority_capabilities (
1145
+ backend_pid, transaction_id, capability_kind
1146
+ ) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'materialize')
1147
+ ON CONFLICT DO NOTHING;
1148
+ SELECT variable_set.* INTO STRICT variable_set_row
1149
+ FROM sessions session_value
1150
+ JOIN workspace_variable_sets variable_set
1151
+ ON variable_set.id = p_variable_set_id
1152
+ AND variable_set.account_id = session_value.account_id
1153
+ WHERE session_value.id = p_session_id
1154
+ AND session_value.account_id = p_account_id
1155
+ AND session_value.workspace_id = p_workspace_id
1156
+ AND session_value.variable_set_id = p_variable_set_id
1157
+ AND session_value.status IN (
1158
+ 'queued', 'running', 'idle', 'requires_action', 'recovering', 'waiting_capacity'
1159
+ )
1160
+ AND variable_set.status = 'active'
1161
+ AND (
1162
+ variable_set.authority_scope = 'organization'
1163
+ OR (
1164
+ variable_set.authority_scope = 'workspace'
1165
+ AND variable_set.workspace_id = p_workspace_id
1166
+ )
1167
+ )
1168
+ FOR SHARE OF session_value, variable_set;
1169
+ RETURN QUERY
1170
+ SELECT selected.id, selected.name, selected.description,
1171
+ selected.authority_scope, selected.generation,
1172
+ variable.name, variable.value_encrypted
1173
+ FROM workspace_variable_sets selected
1174
+ LEFT JOIN workspace_variable_set_variables variable
1175
+ ON variable.account_id = selected.account_id
1176
+ AND variable.variable_set_id = selected.id
1177
+ WHERE selected.id = variable_set_row.id
1178
+ ORDER BY variable.name;
1179
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
1180
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
1181
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
1182
+ AND capability_kind = 'materialize';
1183
+ RETURN;
1184
+ EXCEPTION WHEN OTHERS THEN
1185
+ DELETE FROM opengeni_private.variable_set_authority_capabilities
1186
+ WHERE backend_pid = pg_catalog.pg_backend_pid()
1187
+ AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
1188
+ AND capability_kind = 'materialize';
1189
+ RAISE;
1190
+ END
1191
+ $body$;
1192
+ $ddl$, data_schema);
1193
+ END
1194
+ $scoped_variable_set_functions$;
1195
+
1196
+ REVOKE ALL ON FUNCTION scoped_variable_set_actor_membership(uuid, uuid) FROM PUBLIC;
1197
+ REVOKE ALL ON FUNCTION scoped_variable_set_json(uuid) FROM PUBLIC;
1198
+ REVOKE ALL ON FUNCTION list_scoped_variable_sets(uuid, uuid, uuid, text, text) FROM PUBLIC;
1199
+ REVOKE ALL ON FUNCTION count_scoped_variable_sets(uuid, uuid, text) FROM PUBLIC;
1200
+ REVOKE ALL ON FUNCTION mutate_scoped_variable_set(
1201
+ uuid, uuid, uuid, text, text, boolean, text, boolean, text, text, boolean
1202
+ ) FROM PUBLIC;
1203
+ REVOKE ALL ON FUNCTION assert_scoped_variable_set_attempt(
1204
+ uuid, uuid, uuid, uuid, uuid, integer
1205
+ ) FROM PUBLIC;
1206
+ REVOKE ALL ON FUNCTION read_scoped_variable_set_secret(
1207
+ uuid, uuid, uuid, text, text, text, uuid, uuid, uuid, integer
1208
+ ) FROM PUBLIC;
1209
+ REVOKE ALL ON FUNCTION materialize_scoped_variable_set_for_attempt(
1210
+ uuid, uuid, uuid, uuid, uuid, integer, uuid
1211
+ ) FROM PUBLIC;
1212
+ REVOKE ALL ON FUNCTION materialize_scoped_variable_set_for_session(
1213
+ uuid, uuid, uuid, uuid
1214
+ ) FROM PUBLIC;
1215
+
1216
+ DO $scoped_variable_set_grants$
1217
+ BEGIN
1218
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
1219
+ GRANT EXECUTE ON FUNCTION list_scoped_variable_sets(uuid, uuid, uuid, text, text)
1220
+ TO opengeni_app;
1221
+ GRANT EXECUTE ON FUNCTION count_scoped_variable_sets(uuid, uuid, text)
1222
+ TO opengeni_app;
1223
+ GRANT EXECUTE ON FUNCTION mutate_scoped_variable_set(
1224
+ uuid, uuid, uuid, text, text, boolean, text, boolean, text, text, boolean
1225
+ ) TO opengeni_app;
1226
+ GRANT EXECUTE ON FUNCTION read_scoped_variable_set_secret(
1227
+ uuid, uuid, uuid, text, text, text, uuid, uuid, uuid, integer
1228
+ ) TO opengeni_app;
1229
+ GRANT EXECUTE ON FUNCTION materialize_scoped_variable_set_for_attempt(
1230
+ uuid, uuid, uuid, uuid, uuid, integer, uuid
1231
+ ) TO opengeni_app;
1232
+ GRANT EXECUTE ON FUNCTION materialize_scoped_variable_set_for_session(
1233
+ uuid, uuid, uuid, uuid
1234
+ ) TO opengeni_app;
1235
+ GRANT EXECUTE ON FUNCTION
1236
+ opengeni_private.variable_set_authority_capability_active(text)
1237
+ TO opengeni_app;
1238
+ REVOKE SELECT, INSERT, UPDATE, DELETE ON TABLE workspace_variable_sets
1239
+ FROM opengeni_app;
1240
+ REVOKE SELECT, INSERT, UPDATE, DELETE ON TABLE workspace_variable_set_variables
1241
+ FROM opengeni_app;
1242
+ REVOKE ALL ON TABLE opengeni_private.variable_set_authority_capabilities
1243
+ FROM opengeni_app;
1244
+ REVOKE ALL ON TABLE organization_user_resource_authorities FROM opengeni_app;
1245
+ REVOKE ALL ON TABLE organization_user_resource_grants FROM opengeni_app;
1246
+ END IF;
1247
+ END
1248
+ $scoped_variable_set_grants$;
1249
+
1250
+ COMMENT ON FUNCTION materialize_scoped_variable_set_for_attempt(
1251
+ uuid, uuid, uuid, uuid, uuid, integer, uuid
1252
+ ) IS 'Only ciphertext egress for runtime injection; revalidates the exact live attempt and personal grant immediately before returning encrypted values.';
1253
+ COMMENT ON FUNCTION read_scoped_variable_set_secret(
1254
+ uuid, uuid, uuid, text, text, text, uuid, uuid, uuid, integer
1255
+ ) IS 'Only ciphertext egress for exact plaintext reads; commits value-free audit metadata before application decryption.';