@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.
- package/dist/attached-browser-devices.d.ts +7 -0
- package/dist/automations.d.ts +154 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-integrations.d.ts +13 -0
- package/dist/child-lifecycle-notices.d.ts +68 -0
- package/dist/{chunk-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
- package/dist/chunk-2EH4WRHL.js.map +1 -0
- package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
- package/dist/chunk-6HMM2R5T.js +390 -0
- package/dist/chunk-6HMM2R5T.js.map +1 -0
- package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
- package/dist/chunk-AZHW7R5V.js.map +1 -0
- package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
- package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
- package/dist/chunk-KRLPEMLH.js.map +1 -0
- package/dist/chunk-NAB6FKFN.js +516 -0
- package/dist/chunk-NAB6FKFN.js.map +1 -0
- package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
- package/dist/chunk-SIBYBA2D.js.map +1 -0
- package/dist/chunk-UZNXG44K.js +4508 -0
- package/dist/chunk-UZNXG44K.js.map +1 -0
- package/dist/codemode-operations.d.ts +1 -6
- package/dist/company-brain-context-selection-schema.d.ts +705 -0
- package/dist/company-brain-context-selection.d.ts +94 -0
- package/dist/company-brain-governed-writes.d.ts +24 -0
- package/dist/company-brain.d.ts +55 -0
- package/dist/company-profile-agent-admin.d.ts +15 -0
- package/dist/company-profile-schema.d.ts +619 -2
- package/dist/company-profile.d.ts +9 -4
- package/dist/connection-authority.d.ts +95 -0
- package/dist/connection-scopes.d.ts +8 -0
- package/dist/connection-tenancy-backfill.d.ts +85 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +23 -4
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.d.ts +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation-schema.d.ts +984 -0
- package/dist/governed-learning-activation.d.ts +98 -0
- package/dist/governed-learning-evaluator-schema.d.ts +633 -0
- package/dist/governed-learning-evaluator.d.ts +28 -0
- package/dist/index.d.ts +1606 -81
- package/dist/index.js +21898 -8147
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +18 -0
- package/dist/integration-bindings.d.ts +1 -0
- package/dist/integration-facets.d.ts +30 -0
- package/dist/interaction-placement-loss.d.ts +22 -0
- package/dist/managed-human-provisioning.d.ts +25 -0
- package/dist/memory-domain.d.ts +3 -3
- package/dist/migrate.d.ts +11 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +43 -5
- package/dist/organization-membership-backfill.d.ts +174 -0
- package/dist/organization-membership-lifecycle.d.ts +162 -0
- package/dist/pr-review.d.ts +107 -0
- package/dist/preference-registry-schema.d.ts +2 -0
- package/dist/preference-registry.d.ts +2 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +29 -8
- package/dist/schema.d.ts +24914 -13703
- package/dist/schema.js +99 -1
- package/dist/scoped-knowledge-schema.d.ts +52 -1
- package/dist/session-background-commands.d.ts +125 -0
- package/dist/session-background-commands.js +34 -0
- package/dist/session-background-commands.js.map +1 -0
- package/dist/session-control.d.ts +156 -3
- package/dist/session-goal-pacing.d.ts +68 -0
- package/dist/session-queue-commands.d.ts +43 -4
- package/dist/session-realtime-ledger.d.ts +2 -0
- package/dist/session-tenancy.d.ts +71 -1
- package/dist/session-tenancy.js +25 -3
- package/dist/session-tool-call-settlement.d.ts +9 -4
- package/dist/slack-routing-personal-workspace.d.ts +23 -0
- package/dist/slack-routing.d.ts +268 -0
- package/dist/slack-task-policy-schema.d.ts +34 -0
- package/dist/slack-task-policy.d.ts +8 -0
- package/dist/slack-user-link-access.d.ts +28 -0
- package/dist/task-notes-schema.d.ts +594 -0
- package/dist/task-notes.d.ts +39 -0
- package/dist/turn-initiator.d.ts +2 -0
- package/dist/user-resource-authority.d.ts +109 -0
- package/dist/video-generation.js +3 -3
- package/dist/workspace-authority.d.ts +81 -0
- package/dist/workspace-instruction-policies-schema.d.ts +279 -0
- package/dist/workspace-instruction-policies.d.ts +62 -0
- package/dist/workspace-learning-policy.d.ts +1 -0
- package/dist/workspace-membership-permissions.d.ts +2 -0
- package/drizzle/0240_enrollment_connection_authority.sql +39 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
- package/drizzle/0245_model_context_contribution_facts.sql +88 -0
- package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
- package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
- package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
- package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
- package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
- package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
- package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
- package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
- package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
- package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
- package/drizzle/0256_connection_authority_delegation.sql +703 -0
- package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
- package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
- package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
- package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
- package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
- package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
- package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
- package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
- package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
- package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
- package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
- package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
- package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
- package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
- package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
- package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
- package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
- package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
- package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
- package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
- package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
- package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
- package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
- package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
- package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
- package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
- package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
- package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
- package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
- package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
- package/drizzle/0289_session_composer_policy_authority.sql +597 -0
- package/drizzle/0290_organization_membership_backfill.sql +268 -0
- package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
- package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
- package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
- package/drizzle/0294_preference_activation_authority.sql +237 -0
- package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
- package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
- package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
- package/drizzle/0298_organization_tenancy_parity.sql +609 -0
- package/drizzle/0299_organization_membership_lock_order.sql +291 -0
- package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
- package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
- package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
- package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
- package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
- package/drizzle/0305_personal_resource_grant_management.sql +584 -0
- package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
- package/drizzle/0307_session_attention_state.sql +51 -0
- package/drizzle/0308_session_archives.sql +35 -0
- package/drizzle/0309_channel_project_pins.sql +6 -0
- package/drizzle/0310_channel_project_order.sql +27 -0
- package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
- package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
- package/drizzle/0313_private_child_session_authority.sql +365 -0
- package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
- package/drizzle/0315_personal_github_repository_selection.sql +624 -0
- package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
- package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
- package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
- package/drizzle/0319_event_triggered_automations.sql +254 -0
- package/drizzle/0320_pr_review_pack.sql +113 -0
- package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
- package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
- package/drizzle/0323_organization_private_session_enablement.sql +489 -0
- package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
- package/drizzle/0325_child_lifecycle_notices.sql +44 -0
- package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
- package/drizzle/0327_slack_first_task_hint.sql +29 -0
- package/drizzle/0328_session_background_commands.sql +590 -0
- package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
- package/drizzle/0330_api_key_descriptions.sql +20 -0
- package/drizzle/0331_managed_organization_creation.sql +163 -0
- package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
- package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
- package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
- package/drizzle/0335_slack_workspace_routing.sql +460 -0
- package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
- package/drizzle/0337_slack_routed_action_handles.sql +189 -0
- package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
- package/drizzle/0339_document_authority_reclassification.sql +1153 -0
- package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
- package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
- package/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
- package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
- package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
- package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
- package/drizzle/0346_document_migration_audit_surface.sql +454 -0
- package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -0
- package/package.json +10 -6
- package/src/attached-browser-devices.ts +233 -5
- package/src/automations.ts +911 -0
- package/src/browser-sessions.ts +10 -0
- package/src/capability-integrations.ts +175 -1
- package/src/child-lifecycle-notices.ts +241 -0
- package/src/codemode-operations.ts +1 -35
- package/src/company-brain-context-selection-schema.ts +100 -0
- package/src/company-brain-context-selection.ts +359 -0
- package/src/company-brain-governed-writes.ts +1170 -0
- package/src/company-brain.ts +309 -0
- package/src/company-profile-agent-admin.ts +225 -0
- package/src/company-profile-schema.ts +121 -1
- package/src/company-profile.ts +21 -0
- package/src/computer-sessions.ts +10 -1
- package/src/connection-authority.ts +290 -0
- package/src/connection-scopes.ts +20 -0
- package/src/connection-tenancy-backfill.ts +167 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +87 -2
- package/src/editable-artifacts-schema.ts +10 -5
- package/src/editable-artifacts.ts +21 -11
- package/src/governed-learning-activation-schema.ts +121 -0
- package/src/governed-learning-activation.ts +588 -0
- package/src/governed-learning-evaluator-schema.ts +72 -0
- package/src/governed-learning-evaluator.ts +217 -0
- package/src/index.ts +11676 -1550
- package/src/insights.ts +107 -0
- package/src/integration-bindings.ts +88 -6
- package/src/integration-facets.ts +287 -84
- package/src/interaction-placement-loss.ts +234 -0
- package/src/managed-human-provisioning.ts +116 -0
- package/src/memory-domain.ts +27 -32
- package/src/migrate.ts +77 -1
- package/src/new-session-drafts.ts +229 -35
- package/src/organization-membership-backfill.ts +735 -0
- package/src/organization-membership-lifecycle.ts +995 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +905 -6
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1317 -72
- package/src/schema.ts +3316 -428
- package/src/scoped-knowledge-schema.ts +16 -8
- package/src/scoped-knowledge.ts +1 -1
- package/src/session-background-commands.ts +759 -0
- package/src/session-control.ts +640 -74
- package/src/session-goal-pacing.ts +126 -0
- package/src/session-queue-commands.ts +441 -85
- package/src/session-realtime-context.ts +4 -6
- package/src/session-realtime-ledger.ts +28 -14
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +410 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +867 -0
- package/src/slack-task-policy-schema.ts +5 -0
- package/src/slack-task-policy.ts +18 -0
- package/src/slack-user-link-access.ts +138 -11
- package/src/task-notes-schema.ts +74 -0
- package/src/task-notes.ts +124 -2
- package/src/turn-initiator.ts +8 -0
- package/src/user-resource-authority.ts +377 -0
- package/src/workspace-authority.ts +160 -0
- package/src/workspace-instruction-policies-schema.ts +53 -1
- package/src/workspace-instruction-policies.ts +528 -77
- package/src/workspace-learning-policy.ts +21 -5
- package/src/workspace-membership-permissions.ts +9 -0
- package/dist/chunk-4SR4HKKA.js.map +0 -1
- package/dist/chunk-6ZYKCRFO.js.map +0 -1
- package/dist/chunk-NXAFLCQX.js +0 -2468
- package/dist/chunk-NXAFLCQX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-WD5ROSLL.js +0 -117
- package/dist/chunk-WD5ROSLL.js.map +0 -1
- package/dist/chunk-ZWREYEWA.js.map +0 -1
- /package/dist/{chunk-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
- /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.';
|