@opengeni/db 1.0.1 → 3.1.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-LTG3S6ZY.js → chunk-EULAN2NP.js} +2 -2
- package/dist/{chunk-CUPM3FGB.js → chunk-NJVZPWXY.js} +3 -3
- package/dist/{chunk-4SR4HKKA.js → chunk-NMUBV7Z5.js} +19 -11
- package/dist/chunk-NMUBV7Z5.js.map +1 -0
- package/dist/chunk-OF5OBB76.js +4457 -0
- package/dist/chunk-OF5OBB76.js.map +1 -0
- package/dist/{chunk-6ZYKCRFO.js → chunk-PR2WMLOQ.js} +7580 -4417
- package/dist/chunk-PR2WMLOQ.js.map +1 -0
- package/dist/{chunk-ZWREYEWA.js → chunk-SCPUJS53.js} +41 -4
- package/dist/chunk-SCPUJS53.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-TIKF3KTI.js +383 -0
- package/dist/chunk-TIKF3KTI.js.map +1 -0
- package/dist/chunk-ZZ5LJEFX.js +516 -0
- package/dist/chunk-ZZ5LJEFX.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 +41 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +19 -0
- 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 +1595 -81
- package/dist/index.js +21571 -8126
- 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 +22 -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 +41 -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 +153 -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 +1 -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/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 +81 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +75 -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 +11651 -1548
- 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 +985 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +877 -6
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1291 -76
- package/src/schema.ts +3303 -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 +437 -84
- package/src/session-realtime-context.ts +3 -3
- package/src/session-realtime-ledger.ts +22 -11
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +403 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +469 -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 +17 -1
- 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-LTG3S6ZY.js.map → chunk-EULAN2NP.js.map} +0 -0
- /package/dist/{chunk-CUPM3FGB.js.map → chunk-NJVZPWXY.js.map} +0 -0
|
@@ -0,0 +1,1700 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Activate explicit organization, workspace, and organization+user ownership
|
|
3
|
+
-- for Connected Machines and Rigs. Existing rows remain workspace-owned.
|
|
4
|
+
|
|
5
|
+
SET LOCAL lock_timeout = '5s';
|
|
6
|
+
SET LOCAL statement_timeout = '10min';
|
|
7
|
+
|
|
8
|
+
-- Freeze the active data schema into every SECURITY DEFINER routine created by
|
|
9
|
+
-- this migration. Standalone installs resolve to public; embedded installs
|
|
10
|
+
-- resolve to their dedicated schema. pg_temp remains explicitly last.
|
|
11
|
+
SELECT pg_catalog.set_config(
|
|
12
|
+
'search_path',
|
|
13
|
+
pg_catalog.format('%I, pg_catalog, pg_temp', pg_catalog.current_schema()),
|
|
14
|
+
true
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
ALTER TABLE rigs
|
|
18
|
+
ADD COLUMN generation bigint NOT NULL DEFAULT 1,
|
|
19
|
+
ADD COLUMN status text NOT NULL DEFAULT 'active',
|
|
20
|
+
ADD COLUMN revoked_at timestamptz;
|
|
21
|
+
ALTER TABLE rigs DROP CONSTRAINT rigs_authority_scope_check;
|
|
22
|
+
ALTER TABLE rigs DROP CONSTRAINT rigs_authority_shape_check;
|
|
23
|
+
ALTER TABLE rigs ADD CONSTRAINT rigs_authority_scope_check
|
|
24
|
+
CHECK (authority_scope IN ('organization', 'workspace', 'user')) NOT VALID;
|
|
25
|
+
ALTER TABLE rigs ADD CONSTRAINT rigs_authority_shape_check CHECK (
|
|
26
|
+
(authority_scope IN ('organization', 'workspace') AND authority_id IS NULL
|
|
27
|
+
AND owner_organization_membership_id IS NULL)
|
|
28
|
+
OR (authority_scope = 'user' AND authority_id IS NOT NULL
|
|
29
|
+
AND owner_organization_membership_id IS NOT NULL)
|
|
30
|
+
) NOT VALID;
|
|
31
|
+
ALTER TABLE rigs ADD CONSTRAINT rigs_generation_check CHECK (generation > 0) NOT VALID;
|
|
32
|
+
ALTER TABLE rigs ADD CONSTRAINT rigs_status_check
|
|
33
|
+
CHECK (status IN ('active', 'revoked')) NOT VALID;
|
|
34
|
+
ALTER TABLE rigs ADD CONSTRAINT rigs_revocation_check CHECK (
|
|
35
|
+
(status = 'active' AND revoked_at IS NULL)
|
|
36
|
+
OR (status = 'revoked' AND revoked_at IS NOT NULL)
|
|
37
|
+
) NOT VALID;
|
|
38
|
+
ALTER TABLE rigs VALIDATE CONSTRAINT rigs_authority_scope_check;
|
|
39
|
+
ALTER TABLE rigs VALIDATE CONSTRAINT rigs_authority_shape_check;
|
|
40
|
+
ALTER TABLE rigs VALIDATE CONSTRAINT rigs_generation_check;
|
|
41
|
+
ALTER TABLE rigs VALIDATE CONSTRAINT rigs_status_check;
|
|
42
|
+
ALTER TABLE rigs VALIDATE CONSTRAINT rigs_revocation_check;
|
|
43
|
+
DROP INDEX rigs_workspace_name_idx;
|
|
44
|
+
CREATE UNIQUE INDEX rigs_workspace_name_active_idx ON rigs(workspace_id, name)
|
|
45
|
+
WHERE authority_scope = 'workspace' AND status = 'active';
|
|
46
|
+
CREATE UNIQUE INDEX rigs_organization_name_active_idx ON rigs(account_id, name)
|
|
47
|
+
WHERE authority_scope = 'organization' AND status = 'active';
|
|
48
|
+
CREATE UNIQUE INDEX rigs_user_name_active_idx
|
|
49
|
+
ON rigs(account_id, owner_organization_membership_id, name)
|
|
50
|
+
WHERE authority_scope = 'user' AND status = 'active';
|
|
51
|
+
|
|
52
|
+
ALTER TABLE enrollments
|
|
53
|
+
ADD COLUMN authority_scope text NOT NULL DEFAULT 'workspace',
|
|
54
|
+
ADD COLUMN authority_id uuid,
|
|
55
|
+
ADD COLUMN owner_organization_membership_id uuid,
|
|
56
|
+
ADD COLUMN origin_workspace_id uuid,
|
|
57
|
+
ADD COLUMN generation bigint NOT NULL DEFAULT 1;
|
|
58
|
+
UPDATE enrollments SET origin_workspace_id = workspace_id WHERE origin_workspace_id IS NULL;
|
|
59
|
+
ALTER TABLE enrollments ADD CONSTRAINT enrollments_authority_scope_check
|
|
60
|
+
CHECK (authority_scope IN ('organization', 'workspace', 'user')) NOT VALID;
|
|
61
|
+
ALTER TABLE enrollments ADD CONSTRAINT enrollments_authority_shape_check CHECK (
|
|
62
|
+
(authority_scope IN ('organization', 'workspace') AND authority_id IS NULL
|
|
63
|
+
AND owner_organization_membership_id IS NULL)
|
|
64
|
+
OR (authority_scope = 'user' AND authority_id IS NOT NULL
|
|
65
|
+
AND owner_organization_membership_id IS NOT NULL)
|
|
66
|
+
) NOT VALID;
|
|
67
|
+
ALTER TABLE enrollments ADD CONSTRAINT enrollments_generation_check
|
|
68
|
+
CHECK (generation > 0) NOT VALID;
|
|
69
|
+
ALTER TABLE enrollments ADD CONSTRAINT enrollments_authority_fk
|
|
70
|
+
FOREIGN KEY (authority_id, account_id, owner_organization_membership_id)
|
|
71
|
+
REFERENCES organization_user_resource_authorities(
|
|
72
|
+
id, account_id, organization_membership_id
|
|
73
|
+
) ON DELETE RESTRICT NOT VALID;
|
|
74
|
+
ALTER TABLE enrollments ADD CONSTRAINT enrollments_origin_workspace_fk
|
|
75
|
+
FOREIGN KEY (origin_workspace_id, account_id)
|
|
76
|
+
REFERENCES workspaces(id, account_id) ON DELETE SET NULL (origin_workspace_id) NOT VALID;
|
|
77
|
+
ALTER TABLE enrollments VALIDATE CONSTRAINT enrollments_authority_scope_check;
|
|
78
|
+
ALTER TABLE enrollments VALIDATE CONSTRAINT enrollments_authority_shape_check;
|
|
79
|
+
ALTER TABLE enrollments VALIDATE CONSTRAINT enrollments_generation_check;
|
|
80
|
+
ALTER TABLE enrollments VALIDATE CONSTRAINT enrollments_authority_fk;
|
|
81
|
+
ALTER TABLE enrollments VALIDATE CONSTRAINT enrollments_origin_workspace_fk;
|
|
82
|
+
DROP INDEX enrollments_workspace_pubkey_idx;
|
|
83
|
+
CREATE UNIQUE INDEX enrollments_workspace_pubkey_idx
|
|
84
|
+
ON enrollments(workspace_id, pubkey)
|
|
85
|
+
WHERE authority_scope = 'workspace';
|
|
86
|
+
CREATE UNIQUE INDEX enrollments_organization_pubkey_idx
|
|
87
|
+
ON enrollments(account_id, pubkey)
|
|
88
|
+
WHERE authority_scope = 'organization';
|
|
89
|
+
CREATE UNIQUE INDEX enrollments_user_pubkey_idx
|
|
90
|
+
ON enrollments(account_id, owner_organization_membership_id, pubkey)
|
|
91
|
+
WHERE authority_scope = 'user';
|
|
92
|
+
|
|
93
|
+
CREATE TABLE opengeni_private.scoped_compute_capabilities (
|
|
94
|
+
backend_pid integer NOT NULL,
|
|
95
|
+
transaction_id xid8 NOT NULL,
|
|
96
|
+
capability_kind text NOT NULL,
|
|
97
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
98
|
+
CONSTRAINT scoped_compute_capabilities_kind_check
|
|
99
|
+
CHECK (capability_kind IN ('read', 'write', 'runtime')),
|
|
100
|
+
CONSTRAINT scoped_compute_capabilities_pk
|
|
101
|
+
PRIMARY KEY (backend_pid, transaction_id, capability_kind)
|
|
102
|
+
);
|
|
103
|
+
REVOKE ALL ON TABLE opengeni_private.scoped_compute_capabilities FROM PUBLIC;
|
|
104
|
+
|
|
105
|
+
CREATE OR REPLACE FUNCTION opengeni_private.scoped_compute_capability_active(
|
|
106
|
+
p_capability_kind text DEFAULT NULL
|
|
107
|
+
) RETURNS boolean
|
|
108
|
+
LANGUAGE sql STABLE SECURITY DEFINER SET search_path = pg_catalog AS $$
|
|
109
|
+
SELECT EXISTS (
|
|
110
|
+
SELECT 1 FROM opengeni_private.scoped_compute_capabilities capability
|
|
111
|
+
WHERE capability.backend_pid = pg_catalog.pg_backend_pid()
|
|
112
|
+
AND capability.transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
113
|
+
AND (p_capability_kind IS NULL OR capability.capability_kind = p_capability_kind)
|
|
114
|
+
)
|
|
115
|
+
$$;
|
|
116
|
+
REVOKE ALL ON FUNCTION opengeni_private.scoped_compute_capability_active(text) FROM PUBLIC;
|
|
117
|
+
|
|
118
|
+
-- RLS can also run under a supported non-bypass structural owner (for example
|
|
119
|
+
-- the workspace activity initializer), not only opengeni_app. PostgreSQL checks
|
|
120
|
+
-- every policy function's EXECUTE ACL before it can short-circuit a false owner
|
|
121
|
+
-- branch, so policies use this public, value-free guard rather than exposing the
|
|
122
|
+
-- private predicate itself. The caller supplies current_user from the policy;
|
|
123
|
+
-- even a direct spoof can only observe a same-transaction capability that the
|
|
124
|
+
-- caller cannot mint because the private table remains inaccessible.
|
|
125
|
+
CREATE OR REPLACE FUNCTION scoped_compute_policy_capability_active(
|
|
126
|
+
p_actor text, p_expected_owner text, p_capability_kind text DEFAULT NULL
|
|
127
|
+
) RETURNS boolean
|
|
128
|
+
LANGUAGE sql STABLE SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
129
|
+
SELECT p_actor = p_expected_owner
|
|
130
|
+
AND opengeni_private.scoped_compute_capability_active(p_capability_kind)
|
|
131
|
+
$$;
|
|
132
|
+
GRANT EXECUTE ON FUNCTION scoped_compute_policy_capability_active(text, text, text)
|
|
133
|
+
TO PUBLIC;
|
|
134
|
+
|
|
135
|
+
CREATE OR REPLACE FUNCTION sync_personal_enrollment_authority() RETURNS trigger
|
|
136
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
137
|
+
BEGIN
|
|
138
|
+
IF NEW.authority_scope <> 'user' OR (
|
|
139
|
+
NEW.generation = OLD.generation AND NEW.status = OLD.status
|
|
140
|
+
) THEN
|
|
141
|
+
RETURN NEW;
|
|
142
|
+
END IF;
|
|
143
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
144
|
+
backend_pid, transaction_id, capability_kind
|
|
145
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
|
|
146
|
+
ON CONFLICT DO NOTHING;
|
|
147
|
+
UPDATE organization_user_resource_authorities
|
|
148
|
+
SET generation = NEW.generation, status = NEW.status,
|
|
149
|
+
revoked_at = CASE WHEN NEW.status = 'revoked' THEN coalesce(NEW.revoked_at, clock_timestamp())
|
|
150
|
+
ELSE NULL END,
|
|
151
|
+
updated_at = clock_timestamp()
|
|
152
|
+
WHERE id = NEW.authority_id AND account_id = NEW.account_id
|
|
153
|
+
AND organization_membership_id = NEW.owner_organization_membership_id
|
|
154
|
+
AND resource_kind = 'connected_machine' AND resource_id = NEW.id;
|
|
155
|
+
IF NOT FOUND THEN
|
|
156
|
+
RAISE EXCEPTION 'personal machine authority is missing' USING ERRCODE = '42501';
|
|
157
|
+
END IF;
|
|
158
|
+
UPDATE organization_user_resource_grants
|
|
159
|
+
SET status = 'revoked', revoked_at = clock_timestamp(),
|
|
160
|
+
generation = generation + 1, updated_at = clock_timestamp()
|
|
161
|
+
WHERE authority_id = NEW.authority_id AND account_id = NEW.account_id
|
|
162
|
+
AND status = 'active';
|
|
163
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
164
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
165
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
166
|
+
AND capability_kind = 'write';
|
|
167
|
+
RETURN NEW;
|
|
168
|
+
EXCEPTION WHEN OTHERS THEN
|
|
169
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
170
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
171
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
172
|
+
RAISE;
|
|
173
|
+
END
|
|
174
|
+
$$;
|
|
175
|
+
CREATE TRIGGER sync_personal_enrollment_authority_after_update
|
|
176
|
+
AFTER UPDATE OF generation, status ON enrollments
|
|
177
|
+
FOR EACH ROW EXECUTE FUNCTION sync_personal_enrollment_authority();
|
|
178
|
+
REVOKE ALL ON FUNCTION sync_personal_enrollment_authority() FROM PUBLIC;
|
|
179
|
+
|
|
180
|
+
DO $policies$
|
|
181
|
+
DECLARE
|
|
182
|
+
data_schema text := current_schema();
|
|
183
|
+
migration_owner text := current_user;
|
|
184
|
+
table_name text;
|
|
185
|
+
BEGIN
|
|
186
|
+
FOREACH table_name IN ARRAY ARRAY[
|
|
187
|
+
'rigs', 'rig_versions', 'rig_changes', 'enrollments', 'sandboxes',
|
|
188
|
+
'organization_memberships', 'workspace_memberships',
|
|
189
|
+
'organization_user_resource_authorities', 'organization_user_resource_grants',
|
|
190
|
+
'sessions', 'workspace_session_activity_revisions', 'session_turns', 'session_turn_attempts',
|
|
191
|
+
'session_attempt_interruptions', 'session_attempt_personal_resource_admissions',
|
|
192
|
+
'session_attempt_personal_resource_snapshots',
|
|
193
|
+
'personal_resource_once_consumption_receipts'
|
|
194
|
+
] LOOP
|
|
195
|
+
EXECUTE format(
|
|
196
|
+
'CREATE POLICY scoped_compute_capability_read ON %I.%I FOR SELECT USING '
|
|
197
|
+
|| '(scoped_compute_policy_capability_active(current_user, %L, NULL))',
|
|
198
|
+
data_schema, table_name, migration_owner
|
|
199
|
+
);
|
|
200
|
+
END LOOP;
|
|
201
|
+
FOREACH table_name IN ARRAY ARRAY[
|
|
202
|
+
'rigs', 'rig_versions', 'enrollments', 'sandboxes', 'sessions',
|
|
203
|
+
'workspace_session_activity_revisions',
|
|
204
|
+
'organization_user_resource_authorities', 'organization_user_resource_grants'
|
|
205
|
+
] LOOP
|
|
206
|
+
EXECUTE format(
|
|
207
|
+
'CREATE POLICY scoped_compute_capability_insert ON %I.%I FOR INSERT WITH CHECK '
|
|
208
|
+
|| '(scoped_compute_policy_capability_active(current_user, %L, ''write''))',
|
|
209
|
+
data_schema, table_name, migration_owner
|
|
210
|
+
);
|
|
211
|
+
EXECUTE format(
|
|
212
|
+
'CREATE POLICY scoped_compute_capability_update ON %I.%I FOR UPDATE USING '
|
|
213
|
+
|| '(scoped_compute_policy_capability_active(current_user, %L, ''write'')) '
|
|
214
|
+
|| 'WITH CHECK (scoped_compute_policy_capability_active('
|
|
215
|
+
|| 'current_user, %L, ''write''))',
|
|
216
|
+
data_schema, table_name, migration_owner, migration_owner
|
|
217
|
+
);
|
|
218
|
+
END LOOP;
|
|
219
|
+
END
|
|
220
|
+
$policies$;
|
|
221
|
+
|
|
222
|
+
CREATE OR REPLACE FUNCTION scoped_compute_actor_membership(
|
|
223
|
+
p_account_id uuid,
|
|
224
|
+
p_workspace_id uuid
|
|
225
|
+
) RETURNS uuid
|
|
226
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
227
|
+
DECLARE
|
|
228
|
+
caller_subject text := nullif(pg_catalog.current_setting('opengeni.subject_id', true), '');
|
|
229
|
+
membership_id uuid;
|
|
230
|
+
personal_workspace_id uuid;
|
|
231
|
+
BEGIN
|
|
232
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
233
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
234
|
+
OR p_workspace_id IS DISTINCT FROM nullif(
|
|
235
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
236
|
+
THEN
|
|
237
|
+
RAISE EXCEPTION 'scoped compute actor scope mismatch' USING ERRCODE = '42501';
|
|
238
|
+
END IF;
|
|
239
|
+
SELECT membership.id, membership.personal_workspace_id
|
|
240
|
+
INTO membership_id, personal_workspace_id
|
|
241
|
+
FROM organization_memberships membership
|
|
242
|
+
WHERE membership.account_id = p_account_id
|
|
243
|
+
AND membership.subject_id = caller_subject
|
|
244
|
+
AND membership.status = 'active' AND membership.revoked_at IS NULL
|
|
245
|
+
FOR SHARE;
|
|
246
|
+
IF membership_id IS NULL THEN RETURN NULL; END IF;
|
|
247
|
+
IF personal_workspace_id IS DISTINCT FROM p_workspace_id THEN
|
|
248
|
+
PERFORM 1 FROM workspace_memberships workspace_membership
|
|
249
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
250
|
+
AND workspace_membership.workspace_id = p_workspace_id
|
|
251
|
+
AND workspace_membership.subject_id = caller_subject
|
|
252
|
+
FOR KEY SHARE;
|
|
253
|
+
IF NOT FOUND THEN
|
|
254
|
+
RAISE EXCEPTION 'scoped compute actor lacks current workspace access'
|
|
255
|
+
USING ERRCODE = '42501';
|
|
256
|
+
END IF;
|
|
257
|
+
END IF;
|
|
258
|
+
RETURN membership_id;
|
|
259
|
+
END
|
|
260
|
+
$$;
|
|
261
|
+
REVOKE ALL ON FUNCTION scoped_compute_actor_membership(uuid, uuid) FROM PUBLIC;
|
|
262
|
+
|
|
263
|
+
CREATE OR REPLACE FUNCTION scoped_rig_json(p_rig_id uuid) RETURNS jsonb
|
|
264
|
+
LANGUAGE sql STABLE SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
265
|
+
SELECT pg_catalog.jsonb_build_object(
|
|
266
|
+
'id', rig.id, 'accountId', rig.account_id, 'workspaceId', rig.workspace_id,
|
|
267
|
+
'scope', rig.authority_scope, 'generation', rig.generation, 'status', rig.status,
|
|
268
|
+
'name', rig.name, 'description', rig.description, 'createdBy', rig.created_by,
|
|
269
|
+
'activeVersion', (
|
|
270
|
+
SELECT pg_catalog.jsonb_build_object(
|
|
271
|
+
'id', version.id, 'rigId', version.rig_id, 'version', version.version,
|
|
272
|
+
'image', version.image, 'setupScript', version.setup_script,
|
|
273
|
+
'checks', version.checks, 'credentialHooks', version.credential_hooks,
|
|
274
|
+
'defaultVariableSetIds', version.default_variable_set_ids,
|
|
275
|
+
'changelog', version.changelog, 'providerImages', version.provider_images,
|
|
276
|
+
'createdBy', version.created_by, 'active', version.active,
|
|
277
|
+
'createdAt', version.created_at
|
|
278
|
+
) FROM rig_versions version
|
|
279
|
+
WHERE version.rig_id = rig.id AND version.account_id = rig.account_id
|
|
280
|
+
AND version.active = true LIMIT 1
|
|
281
|
+
),
|
|
282
|
+
'activeVersionHealth', CASE WHEN EXISTS (
|
|
283
|
+
SELECT 1 FROM rig_versions version
|
|
284
|
+
WHERE version.rig_id = rig.id AND version.account_id = rig.account_id
|
|
285
|
+
AND version.active = true
|
|
286
|
+
) THEN pg_catalog.jsonb_build_object('checkHealth', 'unknown', 'lastVerifiedAt', NULL)
|
|
287
|
+
ELSE NULL END,
|
|
288
|
+
'versionCount', (SELECT count(*)::integer FROM rig_versions version
|
|
289
|
+
WHERE version.rig_id = rig.id AND version.account_id = rig.account_id),
|
|
290
|
+
'createdAt', rig.created_at, 'updatedAt', rig.updated_at
|
|
291
|
+
) FROM rigs rig WHERE rig.id = p_rig_id
|
|
292
|
+
$$;
|
|
293
|
+
REVOKE ALL ON FUNCTION scoped_rig_json(uuid) FROM PUBLIC;
|
|
294
|
+
|
|
295
|
+
CREATE OR REPLACE FUNCTION list_scoped_rigs(
|
|
296
|
+
p_account_id uuid,
|
|
297
|
+
p_workspace_id uuid,
|
|
298
|
+
p_rig_id uuid DEFAULT NULL,
|
|
299
|
+
p_name text DEFAULT NULL,
|
|
300
|
+
p_scope text DEFAULT NULL
|
|
301
|
+
) RETURNS SETOF jsonb
|
|
302
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
303
|
+
DECLARE
|
|
304
|
+
actor_membership_id uuid;
|
|
305
|
+
rig_row record;
|
|
306
|
+
BEGIN
|
|
307
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
308
|
+
backend_pid, transaction_id, capability_kind
|
|
309
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
310
|
+
ON CONFLICT DO NOTHING;
|
|
311
|
+
actor_membership_id := scoped_compute_actor_membership(p_account_id, p_workspace_id);
|
|
312
|
+
IF p_scope IS NOT NULL AND p_scope NOT IN ('organization', 'workspace', 'user') THEN
|
|
313
|
+
RAISE EXCEPTION 'invalid rig scope' USING ERRCODE = '22023';
|
|
314
|
+
END IF;
|
|
315
|
+
FOR rig_row IN
|
|
316
|
+
SELECT rig.id FROM rigs rig
|
|
317
|
+
WHERE rig.account_id = p_account_id AND rig.status = 'active'
|
|
318
|
+
AND (p_rig_id IS NULL OR rig.id = p_rig_id)
|
|
319
|
+
AND (p_name IS NULL OR rig.name = p_name)
|
|
320
|
+
AND (p_scope IS NULL OR rig.authority_scope = p_scope)
|
|
321
|
+
AND (
|
|
322
|
+
rig.authority_scope = 'organization'
|
|
323
|
+
OR (rig.authority_scope = 'workspace' AND rig.workspace_id = p_workspace_id)
|
|
324
|
+
OR (rig.authority_scope = 'user'
|
|
325
|
+
AND rig.owner_organization_membership_id = actor_membership_id)
|
|
326
|
+
)
|
|
327
|
+
ORDER BY CASE rig.authority_scope WHEN 'user' THEN 1 WHEN 'workspace' THEN 2 ELSE 3 END,
|
|
328
|
+
rig.created_at, rig.id
|
|
329
|
+
LOOP
|
|
330
|
+
RETURN NEXT scoped_rig_json(rig_row.id);
|
|
331
|
+
END LOOP;
|
|
332
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
333
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
334
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
335
|
+
AND capability_kind = 'read';
|
|
336
|
+
RETURN;
|
|
337
|
+
EXCEPTION WHEN OTHERS THEN
|
|
338
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
339
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
340
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
341
|
+
AND capability_kind = 'read';
|
|
342
|
+
RAISE;
|
|
343
|
+
END
|
|
344
|
+
$$;
|
|
345
|
+
REVOKE ALL ON FUNCTION list_scoped_rigs(uuid, uuid, uuid, text, text) FROM PUBLIC;
|
|
346
|
+
|
|
347
|
+
CREATE OR REPLACE FUNCTION count_scoped_rigs(
|
|
348
|
+
p_account_id uuid, p_workspace_id uuid, p_scope text
|
|
349
|
+
) RETURNS integer
|
|
350
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
351
|
+
DECLARE actor_membership_id uuid; result_count integer;
|
|
352
|
+
BEGIN
|
|
353
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
354
|
+
backend_pid, transaction_id, capability_kind
|
|
355
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
356
|
+
ON CONFLICT DO NOTHING;
|
|
357
|
+
actor_membership_id := scoped_compute_actor_membership(p_account_id, p_workspace_id);
|
|
358
|
+
IF p_scope NOT IN ('organization', 'workspace', 'user') THEN
|
|
359
|
+
RAISE EXCEPTION 'invalid rig scope' USING ERRCODE = '22023';
|
|
360
|
+
END IF;
|
|
361
|
+
SELECT count(*)::integer INTO result_count FROM rigs rig
|
|
362
|
+
WHERE rig.account_id = p_account_id AND rig.status = 'active'
|
|
363
|
+
AND rig.authority_scope = p_scope
|
|
364
|
+
AND (p_scope = 'organization'
|
|
365
|
+
OR (p_scope = 'workspace' AND rig.workspace_id = p_workspace_id)
|
|
366
|
+
OR (p_scope = 'user' AND rig.owner_organization_membership_id = actor_membership_id));
|
|
367
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
368
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
369
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
370
|
+
AND capability_kind = 'read';
|
|
371
|
+
RETURN result_count;
|
|
372
|
+
EXCEPTION WHEN OTHERS THEN
|
|
373
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
374
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
375
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
376
|
+
AND capability_kind = 'read';
|
|
377
|
+
RAISE;
|
|
378
|
+
END
|
|
379
|
+
$$;
|
|
380
|
+
REVOKE ALL ON FUNCTION count_scoped_rigs(uuid, uuid, text) FROM PUBLIC;
|
|
381
|
+
|
|
382
|
+
CREATE OR REPLACE FUNCTION create_scoped_rig(
|
|
383
|
+
p_account_id uuid,
|
|
384
|
+
p_workspace_id uuid,
|
|
385
|
+
p_scope text,
|
|
386
|
+
p_name text,
|
|
387
|
+
p_description text,
|
|
388
|
+
p_created_by text,
|
|
389
|
+
p_initial_version jsonb,
|
|
390
|
+
p_allow_organization boolean DEFAULT false
|
|
391
|
+
) RETURNS jsonb
|
|
392
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
393
|
+
DECLARE
|
|
394
|
+
owner_membership organization_memberships%ROWTYPE;
|
|
395
|
+
caller_subject text := nullif(pg_catalog.current_setting('opengeni.subject_id', true), '');
|
|
396
|
+
rig_id uuid := pg_catalog.gen_random_uuid();
|
|
397
|
+
authority_id uuid;
|
|
398
|
+
result jsonb;
|
|
399
|
+
BEGIN
|
|
400
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
401
|
+
backend_pid, transaction_id, capability_kind
|
|
402
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
|
|
403
|
+
ON CONFLICT DO NOTHING;
|
|
404
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
405
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
406
|
+
OR p_workspace_id IS DISTINCT FROM nullif(
|
|
407
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
408
|
+
OR p_scope NOT IN ('organization', 'workspace', 'user')
|
|
409
|
+
THEN RAISE EXCEPTION 'invalid scoped rig creation request' USING ERRCODE = '42501';
|
|
410
|
+
END IF;
|
|
411
|
+
IF p_scope = 'organization' AND NOT p_allow_organization THEN
|
|
412
|
+
RAISE EXCEPTION 'organization rig creation requires account authority'
|
|
413
|
+
USING ERRCODE = '42501';
|
|
414
|
+
ELSIF p_scope = 'user' THEN
|
|
415
|
+
SELECT membership.* INTO STRICT owner_membership
|
|
416
|
+
FROM organization_memberships membership
|
|
417
|
+
WHERE membership.account_id = p_account_id AND membership.subject_id = caller_subject
|
|
418
|
+
AND membership.status = 'active' AND membership.revoked_at IS NULL FOR SHARE;
|
|
419
|
+
IF owner_membership.personal_workspace_id IS DISTINCT FROM p_workspace_id THEN
|
|
420
|
+
PERFORM 1 FROM workspace_memberships workspace_membership
|
|
421
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
422
|
+
AND workspace_membership.workspace_id = p_workspace_id
|
|
423
|
+
AND workspace_membership.subject_id = caller_subject FOR KEY SHARE;
|
|
424
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'rig owner lacks workspace access'
|
|
425
|
+
USING ERRCODE = '42501'; END IF;
|
|
426
|
+
END IF;
|
|
427
|
+
authority_id := pg_catalog.gen_random_uuid();
|
|
428
|
+
INSERT INTO organization_user_resource_authorities(
|
|
429
|
+
id, account_id, organization_membership_id, resource_kind, resource_id,
|
|
430
|
+
origin_workspace_id, generation, status
|
|
431
|
+
) VALUES (authority_id, p_account_id, owner_membership.id, 'rig', rig_id,
|
|
432
|
+
p_workspace_id, 1, 'active');
|
|
433
|
+
END IF;
|
|
434
|
+
INSERT INTO rigs(
|
|
435
|
+
id, account_id, workspace_id, name, description, created_by, authority_scope,
|
|
436
|
+
authority_id, owner_organization_membership_id, origin_workspace_id,
|
|
437
|
+
generation, status
|
|
438
|
+
) VALUES (
|
|
439
|
+
rig_id, p_account_id, p_workspace_id, p_name, p_description, p_created_by, p_scope,
|
|
440
|
+
authority_id, CASE WHEN p_scope = 'user' THEN owner_membership.id ELSE NULL END,
|
|
441
|
+
p_workspace_id, 1, 'active'
|
|
442
|
+
);
|
|
443
|
+
INSERT INTO rig_versions(
|
|
444
|
+
account_id, workspace_id, rig_id, version, image, setup_script, checks,
|
|
445
|
+
credential_hooks, default_variable_set_ids, changelog, provider_images,
|
|
446
|
+
created_by, active
|
|
447
|
+
) VALUES (
|
|
448
|
+
p_account_id, p_workspace_id, rig_id, 1, p_initial_version ->> 'image',
|
|
449
|
+
p_initial_version ->> 'setupScript', coalesce(p_initial_version -> 'checks', '[]'::jsonb),
|
|
450
|
+
coalesce(p_initial_version -> 'credentialHooks', '[]'::jsonb),
|
|
451
|
+
coalesce(p_initial_version -> 'defaultVariableSetIds', '[]'::jsonb),
|
|
452
|
+
p_initial_version ->> 'changelog', '{}'::jsonb,
|
|
453
|
+
coalesce(p_initial_version ->> 'createdBy', p_created_by), true
|
|
454
|
+
);
|
|
455
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
456
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
457
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
458
|
+
AND capability_kind = 'write';
|
|
459
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
460
|
+
backend_pid, transaction_id, capability_kind
|
|
461
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
462
|
+
ON CONFLICT DO NOTHING;
|
|
463
|
+
result := scoped_rig_json(rig_id);
|
|
464
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
465
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
466
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
467
|
+
AND capability_kind = 'read';
|
|
468
|
+
RETURN result;
|
|
469
|
+
EXCEPTION WHEN OTHERS THEN
|
|
470
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
471
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
472
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
473
|
+
RAISE;
|
|
474
|
+
END
|
|
475
|
+
$$;
|
|
476
|
+
REVOKE ALL ON FUNCTION create_scoped_rig(
|
|
477
|
+
uuid, uuid, text, text, text, text, jsonb, boolean
|
|
478
|
+
) FROM PUBLIC;
|
|
479
|
+
|
|
480
|
+
CREATE OR REPLACE FUNCTION mutate_scoped_rig(
|
|
481
|
+
p_account_id uuid, p_workspace_id uuid, p_rig_id uuid, p_operation text,
|
|
482
|
+
p_name text DEFAULT NULL, p_name_present boolean DEFAULT false,
|
|
483
|
+
p_description text DEFAULT NULL, p_description_present boolean DEFAULT false,
|
|
484
|
+
p_allow_organization boolean DEFAULT false
|
|
485
|
+
) RETURNS jsonb
|
|
486
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
487
|
+
DECLARE
|
|
488
|
+
actor_membership_id uuid;
|
|
489
|
+
rig_row rigs%ROWTYPE;
|
|
490
|
+
active_sessions integer;
|
|
491
|
+
result jsonb;
|
|
492
|
+
BEGIN
|
|
493
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
494
|
+
backend_pid, transaction_id, capability_kind
|
|
495
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
|
|
496
|
+
ON CONFLICT DO NOTHING;
|
|
497
|
+
actor_membership_id := scoped_compute_actor_membership(p_account_id, p_workspace_id);
|
|
498
|
+
SELECT rig.* INTO STRICT rig_row FROM rigs rig
|
|
499
|
+
WHERE rig.id = p_rig_id AND rig.account_id = p_account_id AND rig.status = 'active'
|
|
500
|
+
AND ((rig.authority_scope = 'organization' AND p_allow_organization)
|
|
501
|
+
OR (rig.authority_scope = 'workspace' AND rig.workspace_id = p_workspace_id)
|
|
502
|
+
OR (rig.authority_scope = 'user'
|
|
503
|
+
AND rig.owner_organization_membership_id = actor_membership_id))
|
|
504
|
+
FOR UPDATE;
|
|
505
|
+
IF p_operation = 'update' THEN
|
|
506
|
+
UPDATE rigs SET name = CASE WHEN p_name_present THEN p_name ELSE name END,
|
|
507
|
+
description = CASE WHEN p_description_present THEN p_description ELSE description END,
|
|
508
|
+
updated_at = clock_timestamp() WHERE id = p_rig_id;
|
|
509
|
+
ELSIF p_operation = 'revoke' THEN
|
|
510
|
+
SELECT count(*)::integer INTO active_sessions FROM sessions session_value
|
|
511
|
+
WHERE session_value.account_id = p_account_id AND session_value.rig_id = p_rig_id
|
|
512
|
+
AND session_value.status IN ('queued','running','requires_action','recovering','waiting_capacity');
|
|
513
|
+
IF active_sessions > 0 THEN
|
|
514
|
+
RAISE EXCEPTION 'rig remains attached to % active sessions', active_sessions
|
|
515
|
+
USING ERRCODE = '23503';
|
|
516
|
+
END IF;
|
|
517
|
+
UPDATE rigs SET status = 'revoked', revoked_at = clock_timestamp(),
|
|
518
|
+
generation = generation + 1, updated_at = clock_timestamp() WHERE id = p_rig_id;
|
|
519
|
+
IF rig_row.authority_scope = 'user' THEN
|
|
520
|
+
UPDATE organization_user_resource_authorities SET status = 'revoked',
|
|
521
|
+
revoked_at = clock_timestamp(), generation = generation + 1,
|
|
522
|
+
updated_at = clock_timestamp()
|
|
523
|
+
WHERE id = rig_row.authority_id AND account_id = p_account_id AND status = 'active';
|
|
524
|
+
UPDATE organization_user_resource_grants SET status = 'revoked',
|
|
525
|
+
revoked_at = clock_timestamp(), generation = generation + 1,
|
|
526
|
+
updated_at = clock_timestamp()
|
|
527
|
+
WHERE authority_id = rig_row.authority_id AND account_id = p_account_id
|
|
528
|
+
AND status = 'active';
|
|
529
|
+
END IF;
|
|
530
|
+
ELSE RAISE EXCEPTION 'invalid rig mutation' USING ERRCODE = '22023'; END IF;
|
|
531
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
532
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
533
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
534
|
+
AND capability_kind = 'write';
|
|
535
|
+
IF p_operation = 'revoke' THEN RETURN NULL; END IF;
|
|
536
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
537
|
+
backend_pid, transaction_id, capability_kind
|
|
538
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
539
|
+
ON CONFLICT DO NOTHING;
|
|
540
|
+
result := scoped_rig_json(p_rig_id);
|
|
541
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
542
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
543
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
544
|
+
AND capability_kind = 'read';
|
|
545
|
+
RETURN result;
|
|
546
|
+
EXCEPTION WHEN OTHERS THEN
|
|
547
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
548
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
549
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
550
|
+
RAISE;
|
|
551
|
+
END
|
|
552
|
+
$$;
|
|
553
|
+
REVOKE ALL ON FUNCTION mutate_scoped_rig(
|
|
554
|
+
uuid, uuid, uuid, text, text, boolean, text, boolean, boolean
|
|
555
|
+
) FROM PUBLIC;
|
|
556
|
+
|
|
557
|
+
CREATE OR REPLACE FUNCTION finalize_scoped_enrollment(
|
|
558
|
+
p_account_id uuid, p_workspace_id uuid, p_scope text, p_pubkey text,
|
|
559
|
+
p_has_display boolean, p_allow_screen_control boolean, p_os text, p_arch text,
|
|
560
|
+
p_sandbox_name text, p_allow_organization boolean DEFAULT false
|
|
561
|
+
) RETURNS TABLE(enrollment_id uuid, sandbox_id uuid)
|
|
562
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
563
|
+
DECLARE
|
|
564
|
+
caller_subject text := nullif(pg_catalog.current_setting('opengeni.subject_id', true), '');
|
|
565
|
+
owner_membership organization_memberships%ROWTYPE;
|
|
566
|
+
existing_enrollment enrollments%ROWTYPE;
|
|
567
|
+
created_enrollment_id uuid := pg_catalog.gen_random_uuid();
|
|
568
|
+
created_authority_id uuid;
|
|
569
|
+
selected_enrollment_id uuid;
|
|
570
|
+
selected_sandbox_id uuid;
|
|
571
|
+
BEGIN
|
|
572
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
573
|
+
backend_pid, transaction_id, capability_kind
|
|
574
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
|
|
575
|
+
ON CONFLICT DO NOTHING;
|
|
576
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
577
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
578
|
+
OR p_workspace_id IS DISTINCT FROM nullif(
|
|
579
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
580
|
+
OR p_scope NOT IN ('organization', 'workspace', 'user')
|
|
581
|
+
THEN RAISE EXCEPTION 'invalid scoped enrollment request' USING ERRCODE = '42501';
|
|
582
|
+
END IF;
|
|
583
|
+
IF p_scope = 'organization' AND NOT p_allow_organization THEN
|
|
584
|
+
RAISE EXCEPTION 'organization machine enrollment requires account authority'
|
|
585
|
+
USING ERRCODE = '42501';
|
|
586
|
+
ELSIF p_scope = 'user' THEN
|
|
587
|
+
SELECT membership.* INTO STRICT owner_membership
|
|
588
|
+
FROM organization_memberships membership
|
|
589
|
+
WHERE membership.account_id = p_account_id AND membership.subject_id = caller_subject
|
|
590
|
+
AND membership.status = 'active' AND membership.revoked_at IS NULL FOR SHARE;
|
|
591
|
+
IF owner_membership.personal_workspace_id IS DISTINCT FROM p_workspace_id THEN
|
|
592
|
+
PERFORM 1 FROM workspace_memberships workspace_membership
|
|
593
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
594
|
+
AND workspace_membership.workspace_id = p_workspace_id
|
|
595
|
+
AND workspace_membership.subject_id = caller_subject FOR KEY SHARE;
|
|
596
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'machine owner lacks workspace access'
|
|
597
|
+
USING ERRCODE = '42501'; END IF;
|
|
598
|
+
END IF;
|
|
599
|
+
END IF;
|
|
600
|
+
|
|
601
|
+
SELECT enrollment.* INTO existing_enrollment FROM enrollments enrollment
|
|
602
|
+
WHERE enrollment.account_id = p_account_id
|
|
603
|
+
AND enrollment.authority_scope = p_scope
|
|
604
|
+
AND enrollment.pubkey = p_pubkey
|
|
605
|
+
AND ((p_scope = 'organization')
|
|
606
|
+
OR (p_scope = 'workspace' AND enrollment.workspace_id = p_workspace_id)
|
|
607
|
+
OR (p_scope = 'user'
|
|
608
|
+
AND enrollment.owner_organization_membership_id = owner_membership.id))
|
|
609
|
+
ORDER BY enrollment.created_at DESC LIMIT 1 FOR UPDATE;
|
|
610
|
+
|
|
611
|
+
IF existing_enrollment.id IS NULL THEN
|
|
612
|
+
IF p_scope = 'user' THEN
|
|
613
|
+
created_authority_id := pg_catalog.gen_random_uuid();
|
|
614
|
+
INSERT INTO organization_user_resource_authorities(
|
|
615
|
+
id, account_id, organization_membership_id, resource_kind, resource_id,
|
|
616
|
+
origin_workspace_id, generation, status
|
|
617
|
+
) VALUES (created_authority_id, p_account_id, owner_membership.id,
|
|
618
|
+
'connected_machine', created_enrollment_id, p_workspace_id, 1, 'active');
|
|
619
|
+
END IF;
|
|
620
|
+
INSERT INTO enrollments(
|
|
621
|
+
id, account_id, workspace_id, pubkey, exposure, has_display,
|
|
622
|
+
allow_screen_control, os, arch, status, authority_scope, authority_id,
|
|
623
|
+
owner_organization_membership_id, origin_workspace_id, generation
|
|
624
|
+
) VALUES (
|
|
625
|
+
created_enrollment_id, p_account_id, p_workspace_id, p_pubkey,
|
|
626
|
+
'whole-machine', p_has_display, p_allow_screen_control, p_os, p_arch, 'active',
|
|
627
|
+
p_scope, created_authority_id,
|
|
628
|
+
CASE WHEN p_scope = 'user' THEN owner_membership.id ELSE NULL END,
|
|
629
|
+
p_workspace_id, 1
|
|
630
|
+
);
|
|
631
|
+
selected_enrollment_id := created_enrollment_id;
|
|
632
|
+
ELSE
|
|
633
|
+
UPDATE enrollments SET exposure = 'whole-machine', has_display = p_has_display,
|
|
634
|
+
allow_screen_control = p_allow_screen_control, os = p_os, arch = p_arch,
|
|
635
|
+
status = 'active', revoked_at = NULL,
|
|
636
|
+
credential_generation = credential_generation + 1,
|
|
637
|
+
generation = generation + 1, connection_instance_id = NULL,
|
|
638
|
+
connection_lease_expires_at = NULL, updated_at = clock_timestamp()
|
|
639
|
+
WHERE id = existing_enrollment.id;
|
|
640
|
+
selected_enrollment_id := existing_enrollment.id;
|
|
641
|
+
END IF;
|
|
642
|
+
|
|
643
|
+
SELECT sandbox.id INTO selected_sandbox_id FROM sandboxes sandbox
|
|
644
|
+
WHERE sandbox.account_id = p_account_id
|
|
645
|
+
AND sandbox.enrollment_id = selected_enrollment_id
|
|
646
|
+
ORDER BY sandbox.created_at LIMIT 1 FOR SHARE;
|
|
647
|
+
IF selected_sandbox_id IS NULL THEN
|
|
648
|
+
selected_sandbox_id := pg_catalog.gen_random_uuid();
|
|
649
|
+
INSERT INTO sandboxes(id, account_id, workspace_id, kind, name, enrollment_id)
|
|
650
|
+
VALUES (selected_sandbox_id, p_account_id, p_workspace_id, 'selfhosted',
|
|
651
|
+
p_sandbox_name, selected_enrollment_id);
|
|
652
|
+
END IF;
|
|
653
|
+
enrollment_id := selected_enrollment_id;
|
|
654
|
+
sandbox_id := selected_sandbox_id;
|
|
655
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
656
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
657
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
658
|
+
AND capability_kind = 'write';
|
|
659
|
+
RETURN NEXT;
|
|
660
|
+
RETURN;
|
|
661
|
+
EXCEPTION WHEN OTHERS THEN
|
|
662
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
663
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
664
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
665
|
+
RAISE;
|
|
666
|
+
END
|
|
667
|
+
$$;
|
|
668
|
+
REVOKE ALL ON FUNCTION finalize_scoped_enrollment(
|
|
669
|
+
uuid, uuid, text, text, boolean, boolean, text, text, text, boolean
|
|
670
|
+
) FROM PUBLIC;
|
|
671
|
+
|
|
672
|
+
CREATE OR REPLACE FUNCTION list_scoped_enrollments(
|
|
673
|
+
p_account_id uuid, p_workspace_id uuid, p_enrollment_id uuid DEFAULT NULL,
|
|
674
|
+
p_status text DEFAULT 'active'
|
|
675
|
+
) RETURNS SETOF jsonb
|
|
676
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
677
|
+
DECLARE actor_membership_id uuid; enrollment_row record;
|
|
678
|
+
BEGIN
|
|
679
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
680
|
+
backend_pid, transaction_id, capability_kind
|
|
681
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
682
|
+
ON CONFLICT DO NOTHING;
|
|
683
|
+
actor_membership_id := scoped_compute_actor_membership(p_account_id, p_workspace_id);
|
|
684
|
+
IF p_status NOT IN ('active', 'revoked') THEN
|
|
685
|
+
RAISE EXCEPTION 'invalid enrollment status' USING ERRCODE = '22023';
|
|
686
|
+
END IF;
|
|
687
|
+
FOR enrollment_row IN
|
|
688
|
+
SELECT enrollment.*, sandbox.id AS sandbox_id, sandbox.name AS sandbox_name
|
|
689
|
+
FROM enrollments enrollment
|
|
690
|
+
LEFT JOIN LATERAL (
|
|
691
|
+
SELECT value.id, value.name FROM sandboxes value
|
|
692
|
+
WHERE value.enrollment_id = enrollment.id AND value.account_id = enrollment.account_id
|
|
693
|
+
ORDER BY value.created_at LIMIT 1
|
|
694
|
+
) sandbox ON true
|
|
695
|
+
WHERE enrollment.account_id = p_account_id AND enrollment.status = p_status
|
|
696
|
+
AND (p_enrollment_id IS NULL OR enrollment.id = p_enrollment_id)
|
|
697
|
+
AND (enrollment.authority_scope = 'organization'
|
|
698
|
+
OR (enrollment.authority_scope = 'workspace'
|
|
699
|
+
AND enrollment.workspace_id = p_workspace_id)
|
|
700
|
+
OR (enrollment.authority_scope = 'user'
|
|
701
|
+
AND enrollment.owner_organization_membership_id = actor_membership_id))
|
|
702
|
+
ORDER BY enrollment.created_at DESC, enrollment.id
|
|
703
|
+
LOOP
|
|
704
|
+
RETURN NEXT pg_catalog.jsonb_build_object(
|
|
705
|
+
'id', enrollment_row.id, 'accountId', enrollment_row.account_id,
|
|
706
|
+
'workspaceId', enrollment_row.workspace_id, 'scope', enrollment_row.authority_scope,
|
|
707
|
+
'generation', enrollment_row.generation, 'pubkey', enrollment_row.pubkey,
|
|
708
|
+
'exposure', enrollment_row.exposure, 'hasDisplay', enrollment_row.has_display,
|
|
709
|
+
'opStream', enrollment_row.op_stream,
|
|
710
|
+
'desktopUnavailableReason', enrollment_row.desktop_unavailable_reason,
|
|
711
|
+
'allowScreenControl', enrollment_row.allow_screen_control,
|
|
712
|
+
'operationPolicy', pg_catalog.jsonb_build_object(
|
|
713
|
+
'memoryMaxBytes', enrollment_row.operation_memory_max_bytes,
|
|
714
|
+
'memoryHighBytes', enrollment_row.operation_memory_high_bytes,
|
|
715
|
+
'cpuMaxMillicores', enrollment_row.operation_cpu_max_millicores,
|
|
716
|
+
'revision', enrollment_row.operation_policy_revision,
|
|
717
|
+
'updatedAt', enrollment_row.operation_policy_updated_at
|
|
718
|
+
),
|
|
719
|
+
'status', enrollment_row.status,
|
|
720
|
+
'credentialGeneration', enrollment_row.credential_generation,
|
|
721
|
+
'connectionInstanceId', enrollment_row.connection_instance_id,
|
|
722
|
+
'connectionGeneration', enrollment_row.connection_generation,
|
|
723
|
+
'connectionLeaseExpiresAt', enrollment_row.connection_lease_expires_at,
|
|
724
|
+
'connectionDuplicateDeniedCount', enrollment_row.connection_duplicate_denied_count,
|
|
725
|
+
'connectionDuplicateDeniedAt', enrollment_row.connection_duplicate_denied_at,
|
|
726
|
+
'os', enrollment_row.os, 'arch', enrollment_row.arch,
|
|
727
|
+
'lastSeenAt', enrollment_row.last_seen_at,
|
|
728
|
+
'wentOfflineAt', enrollment_row.went_offline_at,
|
|
729
|
+
'wentOfflineReason', enrollment_row.went_offline_reason,
|
|
730
|
+
'agentVersion', enrollment_row.agent_version,
|
|
731
|
+
'agentBinarySha256', enrollment_row.agent_binary_sha256,
|
|
732
|
+
'agentUpdateChannel', enrollment_row.agent_update_channel,
|
|
733
|
+
'agentCapabilities', enrollment_row.agent_capabilities,
|
|
734
|
+
'agentUpdate', NULL, 'sandboxId', enrollment_row.sandbox_id,
|
|
735
|
+
'sandboxName', enrollment_row.sandbox_name,
|
|
736
|
+
'createdAt', enrollment_row.created_at, 'revokedAt', enrollment_row.revoked_at,
|
|
737
|
+
'updatedAt', enrollment_row.updated_at
|
|
738
|
+
);
|
|
739
|
+
END LOOP;
|
|
740
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
741
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
742
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
743
|
+
AND capability_kind = 'read';
|
|
744
|
+
RETURN;
|
|
745
|
+
EXCEPTION WHEN OTHERS THEN
|
|
746
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
747
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
748
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
749
|
+
RAISE;
|
|
750
|
+
END
|
|
751
|
+
$$;
|
|
752
|
+
REVOKE ALL ON FUNCTION list_scoped_enrollments(uuid, uuid, uuid, text) FROM PUBLIC;
|
|
753
|
+
|
|
754
|
+
CREATE OR REPLACE FUNCTION get_scoped_sandbox(
|
|
755
|
+
p_account_id uuid, p_workspace_id uuid, p_sandbox_id uuid
|
|
756
|
+
) RETURNS jsonb
|
|
757
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
758
|
+
DECLARE actor_membership_id uuid; result jsonb;
|
|
759
|
+
BEGIN
|
|
760
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
761
|
+
backend_pid, transaction_id, capability_kind
|
|
762
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
763
|
+
ON CONFLICT DO NOTHING;
|
|
764
|
+
actor_membership_id := scoped_compute_actor_membership(p_account_id, p_workspace_id);
|
|
765
|
+
SELECT pg_catalog.jsonb_build_object(
|
|
766
|
+
'id', sandbox.id, 'accountId', sandbox.account_id,
|
|
767
|
+
'workspaceId', sandbox.workspace_id, 'kind', sandbox.kind, 'name', sandbox.name,
|
|
768
|
+
'enrollmentId', sandbox.enrollment_id, 'createdAt', sandbox.created_at,
|
|
769
|
+
'updatedAt', sandbox.updated_at, 'scope', enrollment.authority_scope,
|
|
770
|
+
'generation', enrollment.generation
|
|
771
|
+
) INTO result
|
|
772
|
+
FROM sandboxes sandbox
|
|
773
|
+
LEFT JOIN enrollments enrollment
|
|
774
|
+
ON enrollment.id = sandbox.enrollment_id AND enrollment.account_id = sandbox.account_id
|
|
775
|
+
WHERE sandbox.id = p_sandbox_id AND sandbox.account_id = p_account_id
|
|
776
|
+
AND (
|
|
777
|
+
sandbox.kind <> 'selfhosted'
|
|
778
|
+
AND sandbox.workspace_id = p_workspace_id
|
|
779
|
+
OR sandbox.kind = 'selfhosted' AND enrollment.status = 'active' AND (
|
|
780
|
+
enrollment.authority_scope = 'organization'
|
|
781
|
+
OR (enrollment.authority_scope = 'workspace'
|
|
782
|
+
AND enrollment.workspace_id = p_workspace_id)
|
|
783
|
+
OR (enrollment.authority_scope = 'user'
|
|
784
|
+
AND enrollment.owner_organization_membership_id = actor_membership_id)
|
|
785
|
+
)
|
|
786
|
+
);
|
|
787
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
788
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
789
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
790
|
+
AND capability_kind = 'read';
|
|
791
|
+
RETURN result;
|
|
792
|
+
EXCEPTION WHEN OTHERS THEN
|
|
793
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
794
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
795
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
796
|
+
RAISE;
|
|
797
|
+
END
|
|
798
|
+
$$;
|
|
799
|
+
REVOKE ALL ON FUNCTION get_scoped_sandbox(uuid, uuid, uuid) FROM PUBLIC;
|
|
800
|
+
|
|
801
|
+
CREATE OR REPLACE FUNCTION authorize_scoped_sandbox_attach(
|
|
802
|
+
p_account_id uuid, p_workspace_id uuid, p_sandbox_id uuid
|
|
803
|
+
) RETURNS boolean
|
|
804
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
805
|
+
DECLARE
|
|
806
|
+
actor_membership_id uuid;
|
|
807
|
+
sandbox_row sandboxes%ROWTYPE;
|
|
808
|
+
enrollment_row enrollments%ROWTYPE;
|
|
809
|
+
authorized boolean := false;
|
|
810
|
+
BEGIN
|
|
811
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
812
|
+
backend_pid, transaction_id, capability_kind
|
|
813
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
814
|
+
ON CONFLICT DO NOTHING;
|
|
815
|
+
actor_membership_id := scoped_compute_actor_membership(p_account_id, p_workspace_id);
|
|
816
|
+
SELECT sandbox.* INTO sandbox_row FROM sandboxes sandbox
|
|
817
|
+
WHERE sandbox.id = p_sandbox_id AND sandbox.account_id = p_account_id FOR SHARE;
|
|
818
|
+
IF sandbox_row.id IS NOT NULL AND sandbox_row.kind <> 'selfhosted' THEN
|
|
819
|
+
authorized := sandbox_row.workspace_id = p_workspace_id;
|
|
820
|
+
ELSIF sandbox_row.id IS NOT NULL THEN
|
|
821
|
+
SELECT enrollment.* INTO enrollment_row FROM enrollments enrollment
|
|
822
|
+
WHERE enrollment.id = sandbox_row.enrollment_id
|
|
823
|
+
AND enrollment.account_id = p_account_id AND enrollment.status = 'active'
|
|
824
|
+
FOR SHARE;
|
|
825
|
+
authorized := enrollment_row.id IS NOT NULL AND (
|
|
826
|
+
enrollment_row.authority_scope = 'organization'
|
|
827
|
+
OR (enrollment_row.authority_scope = 'workspace'
|
|
828
|
+
AND enrollment_row.workspace_id = p_workspace_id)
|
|
829
|
+
OR (enrollment_row.authority_scope = 'user'
|
|
830
|
+
AND enrollment_row.owner_organization_membership_id = actor_membership_id)
|
|
831
|
+
);
|
|
832
|
+
END IF;
|
|
833
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
834
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
835
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
836
|
+
AND capability_kind = 'read';
|
|
837
|
+
RETURN authorized;
|
|
838
|
+
EXCEPTION WHEN OTHERS THEN
|
|
839
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
840
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
841
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
842
|
+
RAISE;
|
|
843
|
+
END
|
|
844
|
+
$$;
|
|
845
|
+
REVOKE ALL ON FUNCTION authorize_scoped_sandbox_attach(uuid, uuid, uuid) FROM PUBLIC;
|
|
846
|
+
|
|
847
|
+
CREATE OR REPLACE FUNCTION materialize_scoped_rig_version_for_attempt(
|
|
848
|
+
p_account_id uuid, p_workspace_id uuid, p_session_id uuid, p_turn_id uuid,
|
|
849
|
+
p_attempt_id uuid, p_execution_generation integer
|
|
850
|
+
) RETURNS jsonb
|
|
851
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
852
|
+
DECLARE
|
|
853
|
+
session_row sessions%ROWTYPE;
|
|
854
|
+
rig_row rigs%ROWTYPE;
|
|
855
|
+
version_row rig_versions%ROWTYPE;
|
|
856
|
+
initiating_subject text;
|
|
857
|
+
resolved_count integer;
|
|
858
|
+
result jsonb;
|
|
859
|
+
BEGIN
|
|
860
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
861
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
862
|
+
OR p_workspace_id IS DISTINCT FROM nullif(
|
|
863
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
864
|
+
THEN RAISE EXCEPTION 'rig runtime scope mismatch' USING ERRCODE = '42501'; END IF;
|
|
865
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
866
|
+
backend_pid, transaction_id, capability_kind
|
|
867
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'runtime')
|
|
868
|
+
ON CONFLICT DO NOTHING;
|
|
869
|
+
SELECT session_value.* INTO STRICT session_row
|
|
870
|
+
FROM sessions session_value
|
|
871
|
+
JOIN session_turns turn_value ON turn_value.id = p_turn_id
|
|
872
|
+
AND turn_value.account_id = session_value.account_id
|
|
873
|
+
AND turn_value.workspace_id = session_value.workspace_id
|
|
874
|
+
AND turn_value.session_id = session_value.id
|
|
875
|
+
JOIN session_turn_attempts attempt ON attempt.id = p_attempt_id
|
|
876
|
+
AND attempt.account_id = session_value.account_id
|
|
877
|
+
AND attempt.workspace_id = session_value.workspace_id
|
|
878
|
+
AND attempt.session_id = session_value.id AND attempt.turn_id = turn_value.id
|
|
879
|
+
WHERE session_value.id = p_session_id AND session_value.account_id = p_account_id
|
|
880
|
+
AND session_value.workspace_id = p_workspace_id
|
|
881
|
+
AND session_value.active_turn_id = p_turn_id
|
|
882
|
+
AND turn_value.active_attempt_id = p_attempt_id
|
|
883
|
+
AND turn_value.execution_generation = p_execution_generation
|
|
884
|
+
AND turn_value.status = 'running'
|
|
885
|
+
AND attempt.execution_generation = p_execution_generation
|
|
886
|
+
AND attempt.state IN ('claimed','running') AND attempt.closed_at IS NULL
|
|
887
|
+
AND attempt.quiesced_at IS NULL
|
|
888
|
+
FOR SHARE OF session_value, turn_value, attempt;
|
|
889
|
+
initiating_subject := coalesce(
|
|
890
|
+
nullif(pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''),
|
|
891
|
+
nullif(pg_catalog.current_setting('opengeni.subject_id', true), '')
|
|
892
|
+
);
|
|
893
|
+
SELECT rig.* INTO STRICT rig_row FROM rigs rig
|
|
894
|
+
WHERE rig.id = session_row.rig_id AND rig.account_id = p_account_id
|
|
895
|
+
AND rig.status = 'active' FOR SHARE;
|
|
896
|
+
SELECT version.* INTO STRICT version_row FROM rig_versions version
|
|
897
|
+
WHERE version.id = session_row.rig_version_id AND version.rig_id = rig_row.id
|
|
898
|
+
AND version.account_id = p_account_id FOR SHARE;
|
|
899
|
+
IF rig_row.authority_scope = 'workspace'
|
|
900
|
+
AND rig_row.workspace_id IS DISTINCT FROM p_workspace_id
|
|
901
|
+
THEN RAISE EXCEPTION 'workspace rig is outside the runtime workspace'
|
|
902
|
+
USING ERRCODE = '42501';
|
|
903
|
+
ELSIF rig_row.authority_scope = 'user' THEN
|
|
904
|
+
SELECT count(*)::integer INTO resolved_count
|
|
905
|
+
FROM resolve_session_attempt_personal_resources(
|
|
906
|
+
p_account_id, p_workspace_id, p_attempt_id
|
|
907
|
+
) resolved
|
|
908
|
+
WHERE resolved.resource_kind = 'rig' AND resolved.resource_id = rig_row.id
|
|
909
|
+
AND resolved.resource_version_id = version_row.id
|
|
910
|
+
AND resolved.authority_id = rig_row.authority_id
|
|
911
|
+
AND resolved.authority_generation = rig_row.generation;
|
|
912
|
+
IF resolved_count <> 1 THEN
|
|
913
|
+
RAISE EXCEPTION 'personal rig grant is not exact or current'
|
|
914
|
+
USING ERRCODE = '42501';
|
|
915
|
+
END IF;
|
|
916
|
+
END IF;
|
|
917
|
+
result := pg_catalog.jsonb_build_object(
|
|
918
|
+
'rigName', rig_row.name,
|
|
919
|
+
'version', pg_catalog.jsonb_build_object(
|
|
920
|
+
'id', version_row.id, 'rigId', version_row.rig_id,
|
|
921
|
+
'version', version_row.version, 'image', version_row.image,
|
|
922
|
+
'setupScript', version_row.setup_script, 'checks', version_row.checks,
|
|
923
|
+
'credentialHooks', version_row.credential_hooks,
|
|
924
|
+
'defaultVariableSetIds', version_row.default_variable_set_ids,
|
|
925
|
+
'changelog', version_row.changelog, 'providerImages', version_row.provider_images,
|
|
926
|
+
'createdBy', version_row.created_by, 'active', version_row.active,
|
|
927
|
+
'createdAt', version_row.created_at
|
|
928
|
+
)
|
|
929
|
+
);
|
|
930
|
+
INSERT INTO audit_events(
|
|
931
|
+
account_id, workspace_id, subject_id, action, target_type, target_id,
|
|
932
|
+
metadata, metadata_codec_version
|
|
933
|
+
) VALUES (
|
|
934
|
+
p_account_id, p_workspace_id, initiating_subject, 'rig.materialized', 'rig',
|
|
935
|
+
rig_row.id::text, pg_catalog.jsonb_build_object(
|
|
936
|
+
'scope', rig_row.authority_scope, 'generation', rig_row.generation,
|
|
937
|
+
'versionId', version_row.id, 'sessionId', p_session_id,
|
|
938
|
+
'turnId', p_turn_id, 'attemptId', p_attempt_id,
|
|
939
|
+
'executionGeneration', p_execution_generation
|
|
940
|
+
), 1
|
|
941
|
+
);
|
|
942
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
943
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
944
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
945
|
+
AND capability_kind = 'runtime';
|
|
946
|
+
RETURN result;
|
|
947
|
+
EXCEPTION WHEN OTHERS THEN
|
|
948
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
949
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
950
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
951
|
+
RAISE;
|
|
952
|
+
END
|
|
953
|
+
$$;
|
|
954
|
+
REVOKE ALL ON FUNCTION materialize_scoped_rig_version_for_attempt(
|
|
955
|
+
uuid, uuid, uuid, uuid, uuid, integer
|
|
956
|
+
) FROM PUBLIC;
|
|
957
|
+
|
|
958
|
+
CREATE TABLE session_attempt_connected_machine_authorizations (
|
|
959
|
+
attempt_id uuid NOT NULL REFERENCES session_turn_attempts(id) ON DELETE CASCADE,
|
|
960
|
+
account_id uuid NOT NULL,
|
|
961
|
+
workspace_id uuid NOT NULL,
|
|
962
|
+
session_id uuid NOT NULL,
|
|
963
|
+
turn_id uuid NOT NULL,
|
|
964
|
+
execution_generation integer NOT NULL,
|
|
965
|
+
initiating_human_subject_id text NOT NULL,
|
|
966
|
+
owner_organization_membership_id uuid NOT NULL,
|
|
967
|
+
membership_authorization_revision bigint NOT NULL,
|
|
968
|
+
enrollment_id uuid NOT NULL,
|
|
969
|
+
sandbox_id uuid NOT NULL,
|
|
970
|
+
authority_id uuid NOT NULL,
|
|
971
|
+
authority_generation bigint NOT NULL,
|
|
972
|
+
enrollment_generation bigint NOT NULL,
|
|
973
|
+
session_visibility text NOT NULL,
|
|
974
|
+
session_authority_epoch bigint NOT NULL,
|
|
975
|
+
grant_id uuid NOT NULL,
|
|
976
|
+
grant_generation bigint NOT NULL,
|
|
977
|
+
grant_mode text NOT NULL,
|
|
978
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
979
|
+
PRIMARY KEY (attempt_id, enrollment_id),
|
|
980
|
+
CONSTRAINT session_attempt_connected_machine_attempt_fk FOREIGN KEY (
|
|
981
|
+
account_id, workspace_id, session_id, turn_id, attempt_id
|
|
982
|
+
) REFERENCES session_turn_attempts(
|
|
983
|
+
account_id, workspace_id, session_id, turn_id, id
|
|
984
|
+
) ON DELETE CASCADE,
|
|
985
|
+
CONSTRAINT session_attempt_connected_machine_owner_fk FOREIGN KEY (
|
|
986
|
+
owner_organization_membership_id, account_id
|
|
987
|
+
) REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
|
|
988
|
+
CONSTRAINT session_attempt_connected_machine_authority_fk FOREIGN KEY (
|
|
989
|
+
authority_id, account_id, owner_organization_membership_id
|
|
990
|
+
) REFERENCES organization_user_resource_authorities(
|
|
991
|
+
id, account_id, organization_membership_id
|
|
992
|
+
) ON DELETE RESTRICT,
|
|
993
|
+
CONSTRAINT session_attempt_connected_machine_grant_fk FOREIGN KEY (
|
|
994
|
+
grant_id, account_id
|
|
995
|
+
) REFERENCES organization_user_resource_grants(
|
|
996
|
+
id, account_id
|
|
997
|
+
) ON DELETE RESTRICT
|
|
998
|
+
);
|
|
999
|
+
ALTER TABLE session_attempt_connected_machine_authorizations ENABLE ROW LEVEL SECURITY;
|
|
1000
|
+
ALTER TABLE session_attempt_connected_machine_authorizations FORCE ROW LEVEL SECURITY;
|
|
1001
|
+
CREATE POLICY scoped_compute_capability_read
|
|
1002
|
+
ON session_attempt_connected_machine_authorizations FOR SELECT
|
|
1003
|
+
USING (opengeni_private.scoped_compute_capability_active());
|
|
1004
|
+
CREATE POLICY scoped_compute_capability_insert
|
|
1005
|
+
ON session_attempt_connected_machine_authorizations FOR INSERT
|
|
1006
|
+
WITH CHECK (opengeni_private.scoped_compute_capability_active('write'));
|
|
1007
|
+
|
|
1008
|
+
CREATE OR REPLACE FUNCTION admit_session_attempt_personal_machine() RETURNS trigger
|
|
1009
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
1010
|
+
DECLARE
|
|
1011
|
+
session_row sessions%ROWTYPE;
|
|
1012
|
+
turn_row session_turns%ROWTYPE;
|
|
1013
|
+
enrollment_row enrollments%ROWTYPE;
|
|
1014
|
+
sandbox_row sandboxes%ROWTYPE;
|
|
1015
|
+
member_row organization_memberships%ROWTYPE;
|
|
1016
|
+
grant_row organization_user_resource_grants%ROWTYPE;
|
|
1017
|
+
initiating_subject text;
|
|
1018
|
+
affected integer;
|
|
1019
|
+
BEGIN
|
|
1020
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
1021
|
+
backend_pid, transaction_id, capability_kind
|
|
1022
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
|
|
1023
|
+
ON CONFLICT DO NOTHING;
|
|
1024
|
+
SELECT session_value.* INTO STRICT session_row FROM sessions session_value
|
|
1025
|
+
WHERE session_value.id = NEW.session_id AND session_value.account_id = NEW.account_id
|
|
1026
|
+
AND session_value.workspace_id = NEW.workspace_id FOR SHARE;
|
|
1027
|
+
IF session_row.active_sandbox_id IS NULL THEN
|
|
1028
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1029
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1030
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1031
|
+
RETURN NEW;
|
|
1032
|
+
END IF;
|
|
1033
|
+
SELECT sandbox.* INTO sandbox_row FROM sandboxes sandbox
|
|
1034
|
+
WHERE sandbox.id = session_row.active_sandbox_id AND sandbox.account_id = NEW.account_id
|
|
1035
|
+
AND sandbox.kind = 'selfhosted' FOR SHARE;
|
|
1036
|
+
IF sandbox_row.enrollment_id IS NULL THEN
|
|
1037
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1038
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1039
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1040
|
+
RETURN NEW;
|
|
1041
|
+
END IF;
|
|
1042
|
+
SELECT enrollment.* INTO enrollment_row FROM enrollments enrollment
|
|
1043
|
+
WHERE enrollment.id = sandbox_row.enrollment_id AND enrollment.account_id = NEW.account_id
|
|
1044
|
+
AND enrollment.authority_scope = 'user' AND enrollment.status = 'active' FOR SHARE;
|
|
1045
|
+
IF enrollment_row.id IS NULL THEN
|
|
1046
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1047
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1048
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1049
|
+
RETURN NEW;
|
|
1050
|
+
END IF;
|
|
1051
|
+
SELECT turn_value.* INTO STRICT turn_row FROM session_turns turn_value
|
|
1052
|
+
WHERE turn_value.id = NEW.turn_id AND turn_value.account_id = NEW.account_id
|
|
1053
|
+
AND turn_value.workspace_id = NEW.workspace_id
|
|
1054
|
+
AND turn_value.session_id = NEW.session_id FOR SHARE;
|
|
1055
|
+
IF NEW.state NOT IN ('claimed', 'running') OR NEW.closed_at IS NOT NULL
|
|
1056
|
+
OR NEW.quiesced_at IS NOT NULL OR session_row.active_turn_id IS DISTINCT FROM NEW.turn_id
|
|
1057
|
+
OR turn_row.active_attempt_id IS DISTINCT FROM NEW.id
|
|
1058
|
+
OR turn_row.execution_generation IS DISTINCT FROM NEW.execution_generation
|
|
1059
|
+
OR NEW.authority_visibility IS DISTINCT FROM session_row.visibility
|
|
1060
|
+
OR NEW.authority_epoch IS DISTINCT FROM session_row.authority_epoch
|
|
1061
|
+
THEN RAISE EXCEPTION 'personal machine requires exact current attempt authority'
|
|
1062
|
+
USING ERRCODE = '42501'; END IF;
|
|
1063
|
+
initiating_subject := coalesce(nullif(btrim(turn_row.initiating_human_subject_id), ''),
|
|
1064
|
+
CASE WHEN turn_row.initiator_kind = 'subject'
|
|
1065
|
+
THEN nullif(btrim(turn_row.initiator_subject_id), '') END);
|
|
1066
|
+
SELECT membership.* INTO STRICT member_row FROM organization_memberships membership
|
|
1067
|
+
WHERE membership.account_id = NEW.account_id AND membership.subject_id = initiating_subject
|
|
1068
|
+
AND membership.status = 'active' AND membership.revoked_at IS NULL FOR SHARE;
|
|
1069
|
+
IF member_row.id IS DISTINCT FROM enrollment_row.owner_organization_membership_id THEN
|
|
1070
|
+
RAISE EXCEPTION 'only the personal machine owner may attach it'
|
|
1071
|
+
USING ERRCODE = '42501';
|
|
1072
|
+
END IF;
|
|
1073
|
+
IF member_row.personal_workspace_id IS DISTINCT FROM NEW.workspace_id THEN
|
|
1074
|
+
PERFORM 1 FROM workspace_memberships workspace_membership
|
|
1075
|
+
WHERE workspace_membership.account_id = NEW.account_id
|
|
1076
|
+
AND workspace_membership.workspace_id = NEW.workspace_id
|
|
1077
|
+
AND workspace_membership.subject_id = initiating_subject FOR KEY SHARE;
|
|
1078
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'machine owner lacks target workspace access'
|
|
1079
|
+
USING ERRCODE = '42501'; END IF;
|
|
1080
|
+
END IF;
|
|
1081
|
+
PERFORM 1 FROM organization_user_resource_authorities authority
|
|
1082
|
+
WHERE authority.id = enrollment_row.authority_id AND authority.account_id = NEW.account_id
|
|
1083
|
+
AND authority.organization_membership_id = member_row.id
|
|
1084
|
+
AND authority.resource_kind = 'connected_machine'
|
|
1085
|
+
AND authority.resource_id = enrollment_row.id
|
|
1086
|
+
AND authority.generation = enrollment_row.generation
|
|
1087
|
+
AND authority.status = 'active' AND authority.revoked_at IS NULL FOR SHARE;
|
|
1088
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'personal machine authority is stale'
|
|
1089
|
+
USING ERRCODE = '42501'; END IF;
|
|
1090
|
+
SELECT grant_value.* INTO grant_row FROM organization_user_resource_grants grant_value
|
|
1091
|
+
WHERE grant_value.account_id = NEW.account_id
|
|
1092
|
+
AND grant_value.authority_id = enrollment_row.authority_id
|
|
1093
|
+
AND grant_value.owner_organization_membership_id = member_row.id
|
|
1094
|
+
AND grant_value.workspace_id = NEW.workspace_id
|
|
1095
|
+
AND grant_value.action = 'connected_machine.use'
|
|
1096
|
+
AND grant_value.context = session_row.visibility AND grant_value.status = 'active'
|
|
1097
|
+
AND (grant_value.expires_at IS NULL OR grant_value.expires_at > clock_timestamp())
|
|
1098
|
+
AND ((grant_value.mode IN ('once','session')
|
|
1099
|
+
AND grant_value.session_id = NEW.session_id
|
|
1100
|
+
AND grant_value.authority_epoch = session_row.authority_epoch)
|
|
1101
|
+
OR (grant_value.mode = 'always' AND grant_value.session_id IS NULL
|
|
1102
|
+
AND grant_value.authority_epoch IS NULL))
|
|
1103
|
+
ORDER BY CASE grant_value.mode WHEN 'once' THEN 1 WHEN 'session' THEN 2 ELSE 3 END,
|
|
1104
|
+
grant_value.generation DESC, grant_value.id LIMIT 1 FOR UPDATE;
|
|
1105
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'personal machine use requires explicit grant'
|
|
1106
|
+
USING ERRCODE = '42501'; END IF;
|
|
1107
|
+
INSERT INTO session_attempt_connected_machine_authorizations(
|
|
1108
|
+
attempt_id, account_id, workspace_id, session_id, turn_id, execution_generation,
|
|
1109
|
+
initiating_human_subject_id, owner_organization_membership_id,
|
|
1110
|
+
membership_authorization_revision, enrollment_id, sandbox_id, authority_id,
|
|
1111
|
+
authority_generation, enrollment_generation, session_visibility,
|
|
1112
|
+
session_authority_epoch, grant_id, grant_generation, grant_mode
|
|
1113
|
+
) SELECT NEW.id, NEW.account_id, NEW.workspace_id, NEW.session_id, NEW.turn_id,
|
|
1114
|
+
NEW.execution_generation, initiating_subject, member_row.id,
|
|
1115
|
+
member_row.authorization_revision, enrollment_row.id, sandbox_row.id,
|
|
1116
|
+
authority.id, authority.generation, enrollment_row.generation,
|
|
1117
|
+
session_row.visibility, session_row.authority_epoch,
|
|
1118
|
+
grant_row.id, grant_row.generation, grant_row.mode
|
|
1119
|
+
FROM organization_user_resource_authorities authority
|
|
1120
|
+
WHERE authority.id = enrollment_row.authority_id AND authority.account_id = NEW.account_id;
|
|
1121
|
+
IF grant_row.mode = 'once' THEN
|
|
1122
|
+
UPDATE organization_user_resource_grants SET status = 'consumed',
|
|
1123
|
+
updated_at = clock_timestamp()
|
|
1124
|
+
WHERE id = grant_row.id AND account_id = NEW.account_id
|
|
1125
|
+
AND generation = grant_row.generation AND status = 'active';
|
|
1126
|
+
GET DIAGNOSTICS affected = ROW_COUNT;
|
|
1127
|
+
IF affected <> 1 THEN RAISE EXCEPTION 'once machine grant lost first-use race'
|
|
1128
|
+
USING ERRCODE = '40001'; END IF;
|
|
1129
|
+
INSERT INTO personal_resource_once_consumption_receipts(
|
|
1130
|
+
grant_id, account_id, attempt_id, workspace_id, session_id, turn_id,
|
|
1131
|
+
execution_generation, authority_id, authority_generation, grant_generation
|
|
1132
|
+
) SELECT grant_row.id, NEW.account_id, NEW.id, NEW.workspace_id, NEW.session_id,
|
|
1133
|
+
NEW.turn_id, NEW.execution_generation, authority.id, authority.generation,
|
|
1134
|
+
grant_row.generation FROM organization_user_resource_authorities authority
|
|
1135
|
+
WHERE authority.id = enrollment_row.authority_id AND authority.account_id = NEW.account_id;
|
|
1136
|
+
END IF;
|
|
1137
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1138
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1139
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
1140
|
+
AND capability_kind = 'write';
|
|
1141
|
+
RETURN NEW;
|
|
1142
|
+
EXCEPTION WHEN OTHERS THEN
|
|
1143
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1144
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1145
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1146
|
+
RAISE;
|
|
1147
|
+
END
|
|
1148
|
+
$$;
|
|
1149
|
+
DROP TRIGGER IF EXISTS z_session_attempt_personal_machine_admission ON session_turn_attempts;
|
|
1150
|
+
CREATE TRIGGER z_session_attempt_personal_machine_admission
|
|
1151
|
+
AFTER INSERT ON session_turn_attempts FOR EACH ROW
|
|
1152
|
+
EXECUTE FUNCTION admit_session_attempt_personal_machine();
|
|
1153
|
+
REVOKE ALL ON FUNCTION admit_session_attempt_personal_machine() FROM PUBLIC;
|
|
1154
|
+
|
|
1155
|
+
CREATE OR REPLACE FUNCTION authorize_session_attempt_personal_machine(
|
|
1156
|
+
p_account_id uuid, p_workspace_id uuid, p_session_id uuid, p_turn_id uuid,
|
|
1157
|
+
p_attempt_id uuid, p_execution_generation integer, p_enrollment_id uuid
|
|
1158
|
+
) RETURNS boolean
|
|
1159
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
1160
|
+
DECLARE
|
|
1161
|
+
session_row sessions%ROWTYPE;
|
|
1162
|
+
turn_row session_turns%ROWTYPE;
|
|
1163
|
+
attempt_row session_turn_attempts%ROWTYPE;
|
|
1164
|
+
enrollment_row enrollments%ROWTYPE;
|
|
1165
|
+
sandbox_row sandboxes%ROWTYPE;
|
|
1166
|
+
member_row organization_memberships%ROWTYPE;
|
|
1167
|
+
authority_row organization_user_resource_authorities%ROWTYPE;
|
|
1168
|
+
grant_row organization_user_resource_grants%ROWTYPE;
|
|
1169
|
+
authorization_row session_attempt_connected_machine_authorizations%ROWTYPE;
|
|
1170
|
+
initiating_subject text;
|
|
1171
|
+
caller_subject text := coalesce(
|
|
1172
|
+
nullif(pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''),
|
|
1173
|
+
nullif(pg_catalog.current_setting('opengeni.subject_id', true), '')
|
|
1174
|
+
);
|
|
1175
|
+
affected integer;
|
|
1176
|
+
BEGIN
|
|
1177
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
1178
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
1179
|
+
OR p_workspace_id IS DISTINCT FROM nullif(
|
|
1180
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
1181
|
+
THEN RAISE EXCEPTION 'machine runtime scope mismatch' USING ERRCODE = '42501'; END IF;
|
|
1182
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
1183
|
+
backend_pid, transaction_id, capability_kind
|
|
1184
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
|
|
1185
|
+
ON CONFLICT DO NOTHING;
|
|
1186
|
+
SELECT session_value.* INTO STRICT session_row FROM sessions session_value
|
|
1187
|
+
WHERE session_value.id = p_session_id AND session_value.account_id = p_account_id
|
|
1188
|
+
AND session_value.workspace_id = p_workspace_id FOR SHARE;
|
|
1189
|
+
SELECT turn_value.* INTO STRICT turn_row FROM session_turns turn_value
|
|
1190
|
+
WHERE turn_value.id = p_turn_id AND turn_value.account_id = p_account_id
|
|
1191
|
+
AND turn_value.workspace_id = p_workspace_id
|
|
1192
|
+
AND turn_value.session_id = p_session_id FOR SHARE;
|
|
1193
|
+
SELECT attempt_value.* INTO STRICT attempt_row FROM session_turn_attempts attempt_value
|
|
1194
|
+
WHERE attempt_value.id = p_attempt_id AND attempt_value.account_id = p_account_id
|
|
1195
|
+
AND attempt_value.workspace_id = p_workspace_id
|
|
1196
|
+
AND attempt_value.session_id = p_session_id
|
|
1197
|
+
AND attempt_value.turn_id = p_turn_id FOR SHARE;
|
|
1198
|
+
IF attempt_row.execution_generation IS DISTINCT FROM p_execution_generation
|
|
1199
|
+
OR attempt_row.state NOT IN ('claimed', 'running')
|
|
1200
|
+
OR attempt_row.closed_at IS NOT NULL OR attempt_row.quiesced_at IS NOT NULL
|
|
1201
|
+
OR session_row.active_turn_id IS DISTINCT FROM p_turn_id
|
|
1202
|
+
OR turn_row.active_attempt_id IS DISTINCT FROM p_attempt_id
|
|
1203
|
+
OR turn_row.execution_generation IS DISTINCT FROM p_execution_generation
|
|
1204
|
+
OR attempt_row.authority_visibility IS DISTINCT FROM session_row.visibility
|
|
1205
|
+
OR attempt_row.authority_epoch IS DISTINCT FROM session_row.authority_epoch
|
|
1206
|
+
OR EXISTS (
|
|
1207
|
+
SELECT 1 FROM session_attempt_interruptions interruption
|
|
1208
|
+
WHERE interruption.attempt_id = p_attempt_id
|
|
1209
|
+
AND interruption.account_id = p_account_id
|
|
1210
|
+
AND interruption.workspace_id = p_workspace_id
|
|
1211
|
+
AND interruption.state IN ('pending', 'delivered', 'acknowledged')
|
|
1212
|
+
)
|
|
1213
|
+
THEN RAISE EXCEPTION 'personal machine requires exact current attempt authority'
|
|
1214
|
+
USING ERRCODE = '42501'; END IF;
|
|
1215
|
+
initiating_subject := coalesce(
|
|
1216
|
+
nullif(btrim(turn_row.initiating_human_subject_id), ''),
|
|
1217
|
+
CASE WHEN turn_row.initiator_kind = 'subject'
|
|
1218
|
+
THEN nullif(btrim(turn_row.initiator_subject_id), '') END
|
|
1219
|
+
);
|
|
1220
|
+
IF caller_subject IS DISTINCT FROM initiating_subject THEN
|
|
1221
|
+
RAISE EXCEPTION 'personal machine caller is not the frozen initiating human'
|
|
1222
|
+
USING ERRCODE = '42501';
|
|
1223
|
+
END IF;
|
|
1224
|
+
SELECT enrollment.* INTO STRICT enrollment_row FROM enrollments enrollment
|
|
1225
|
+
WHERE enrollment.id = p_enrollment_id AND enrollment.account_id = p_account_id
|
|
1226
|
+
AND enrollment.authority_scope = 'user' AND enrollment.status = 'active'
|
|
1227
|
+
AND enrollment.revoked_at IS NULL FOR SHARE;
|
|
1228
|
+
SELECT sandbox.* INTO STRICT sandbox_row FROM sandboxes sandbox
|
|
1229
|
+
WHERE sandbox.account_id = p_account_id AND sandbox.enrollment_id = p_enrollment_id
|
|
1230
|
+
AND sandbox.kind = 'selfhosted' ORDER BY sandbox.created_at, sandbox.id LIMIT 1 FOR SHARE;
|
|
1231
|
+
SELECT membership.* INTO STRICT member_row FROM organization_memberships membership
|
|
1232
|
+
WHERE membership.account_id = p_account_id AND membership.subject_id = initiating_subject
|
|
1233
|
+
AND membership.status = 'active' AND membership.revoked_at IS NULL FOR SHARE;
|
|
1234
|
+
IF member_row.id IS DISTINCT FROM enrollment_row.owner_organization_membership_id THEN
|
|
1235
|
+
RAISE EXCEPTION 'only the personal machine owner may use it'
|
|
1236
|
+
USING ERRCODE = '42501';
|
|
1237
|
+
END IF;
|
|
1238
|
+
IF member_row.personal_workspace_id IS DISTINCT FROM p_workspace_id THEN
|
|
1239
|
+
PERFORM 1 FROM workspace_memberships workspace_membership
|
|
1240
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
1241
|
+
AND workspace_membership.workspace_id = p_workspace_id
|
|
1242
|
+
AND workspace_membership.subject_id = initiating_subject FOR KEY SHARE;
|
|
1243
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'machine owner lacks target workspace access'
|
|
1244
|
+
USING ERRCODE = '42501'; END IF;
|
|
1245
|
+
END IF;
|
|
1246
|
+
SELECT authority.* INTO STRICT authority_row
|
|
1247
|
+
FROM organization_user_resource_authorities authority
|
|
1248
|
+
WHERE authority.id = enrollment_row.authority_id AND authority.account_id = p_account_id
|
|
1249
|
+
AND authority.organization_membership_id = member_row.id
|
|
1250
|
+
AND authority.resource_kind = 'connected_machine'
|
|
1251
|
+
AND authority.resource_id = enrollment_row.id
|
|
1252
|
+
AND authority.generation = enrollment_row.generation
|
|
1253
|
+
AND authority.status = 'active' AND authority.revoked_at IS NULL FOR SHARE;
|
|
1254
|
+
SELECT authorization_value.* INTO authorization_row
|
|
1255
|
+
FROM session_attempt_connected_machine_authorizations authorization_value
|
|
1256
|
+
WHERE authorization_value.attempt_id = p_attempt_id
|
|
1257
|
+
AND authorization_value.enrollment_id = p_enrollment_id FOR SHARE;
|
|
1258
|
+
IF authorization_row.attempt_id IS NOT NULL THEN
|
|
1259
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1260
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1261
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
1262
|
+
AND capability_kind = 'write';
|
|
1263
|
+
RETURN true;
|
|
1264
|
+
END IF;
|
|
1265
|
+
SELECT grant_value.* INTO grant_row FROM organization_user_resource_grants grant_value
|
|
1266
|
+
WHERE grant_value.account_id = p_account_id
|
|
1267
|
+
AND grant_value.authority_id = authority_row.id
|
|
1268
|
+
AND grant_value.owner_organization_membership_id = member_row.id
|
|
1269
|
+
AND grant_value.workspace_id = p_workspace_id
|
|
1270
|
+
AND grant_value.action = 'connected_machine.use'
|
|
1271
|
+
AND grant_value.context = session_row.visibility AND grant_value.status = 'active'
|
|
1272
|
+
AND (grant_value.expires_at IS NULL OR grant_value.expires_at > clock_timestamp())
|
|
1273
|
+
AND ((grant_value.mode IN ('once', 'session')
|
|
1274
|
+
AND grant_value.session_id = p_session_id
|
|
1275
|
+
AND grant_value.authority_epoch = session_row.authority_epoch)
|
|
1276
|
+
OR (grant_value.mode = 'always' AND grant_value.session_id IS NULL
|
|
1277
|
+
AND grant_value.authority_epoch IS NULL))
|
|
1278
|
+
ORDER BY CASE grant_value.mode WHEN 'once' THEN 1 WHEN 'session' THEN 2 ELSE 3 END,
|
|
1279
|
+
grant_value.generation DESC, grant_value.id LIMIT 1 FOR UPDATE;
|
|
1280
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'personal machine use requires explicit grant'
|
|
1281
|
+
USING ERRCODE = '42501'; END IF;
|
|
1282
|
+
INSERT INTO session_attempt_connected_machine_authorizations(
|
|
1283
|
+
attempt_id, account_id, workspace_id, session_id, turn_id, execution_generation,
|
|
1284
|
+
initiating_human_subject_id, owner_organization_membership_id,
|
|
1285
|
+
membership_authorization_revision, enrollment_id, sandbox_id, authority_id,
|
|
1286
|
+
authority_generation, enrollment_generation, session_visibility,
|
|
1287
|
+
session_authority_epoch, grant_id, grant_generation, grant_mode
|
|
1288
|
+
) VALUES (
|
|
1289
|
+
p_attempt_id, p_account_id, p_workspace_id, p_session_id, p_turn_id,
|
|
1290
|
+
p_execution_generation, initiating_subject, member_row.id,
|
|
1291
|
+
member_row.authorization_revision, enrollment_row.id, sandbox_row.id,
|
|
1292
|
+
authority_row.id, authority_row.generation, enrollment_row.generation,
|
|
1293
|
+
session_row.visibility, session_row.authority_epoch,
|
|
1294
|
+
grant_row.id, grant_row.generation, grant_row.mode
|
|
1295
|
+
) ON CONFLICT (attempt_id, enrollment_id) DO NOTHING;
|
|
1296
|
+
GET DIAGNOSTICS affected = ROW_COUNT;
|
|
1297
|
+
IF affected = 1 AND grant_row.mode = 'once' THEN
|
|
1298
|
+
UPDATE organization_user_resource_grants SET status = 'consumed',
|
|
1299
|
+
updated_at = clock_timestamp()
|
|
1300
|
+
WHERE id = grant_row.id AND account_id = p_account_id
|
|
1301
|
+
AND generation = grant_row.generation AND status = 'active';
|
|
1302
|
+
GET DIAGNOSTICS affected = ROW_COUNT;
|
|
1303
|
+
IF affected <> 1 THEN RAISE EXCEPTION 'once machine grant lost first-use race'
|
|
1304
|
+
USING ERRCODE = '40001'; END IF;
|
|
1305
|
+
INSERT INTO personal_resource_once_consumption_receipts(
|
|
1306
|
+
grant_id, account_id, attempt_id, workspace_id, session_id, turn_id,
|
|
1307
|
+
execution_generation, authority_id, authority_generation, grant_generation
|
|
1308
|
+
) VALUES (
|
|
1309
|
+
grant_row.id, p_account_id, p_attempt_id, p_workspace_id, p_session_id,
|
|
1310
|
+
p_turn_id, p_execution_generation, authority_row.id,
|
|
1311
|
+
authority_row.generation, grant_row.generation
|
|
1312
|
+
);
|
|
1313
|
+
END IF;
|
|
1314
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1315
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1316
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
1317
|
+
AND capability_kind = 'write';
|
|
1318
|
+
RETURN true;
|
|
1319
|
+
EXCEPTION WHEN OTHERS THEN
|
|
1320
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1321
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1322
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1323
|
+
RAISE;
|
|
1324
|
+
END
|
|
1325
|
+
$$;
|
|
1326
|
+
REVOKE ALL ON FUNCTION authorize_session_attempt_personal_machine(
|
|
1327
|
+
uuid, uuid, uuid, uuid, uuid, integer, uuid
|
|
1328
|
+
) FROM PUBLIC;
|
|
1329
|
+
|
|
1330
|
+
CREATE OR REPLACE FUNCTION assert_session_attempt_personal_machine(
|
|
1331
|
+
p_account_id uuid, p_workspace_id uuid, p_session_id uuid, p_turn_id uuid,
|
|
1332
|
+
p_attempt_id uuid, p_execution_generation integer, p_enrollment_id uuid,
|
|
1333
|
+
p_require_active_sandbox boolean
|
|
1334
|
+
) RETURNS boolean
|
|
1335
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
1336
|
+
DECLARE
|
|
1337
|
+
authorization_row session_attempt_connected_machine_authorizations%ROWTYPE;
|
|
1338
|
+
caller_subject text := coalesce(
|
|
1339
|
+
nullif(pg_catalog.current_setting('opengeni.initiating_human_subject_id', true), ''),
|
|
1340
|
+
nullif(pg_catalog.current_setting('opengeni.subject_id', true), '')
|
|
1341
|
+
);
|
|
1342
|
+
BEGIN
|
|
1343
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
1344
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
1345
|
+
OR p_workspace_id IS DISTINCT FROM nullif(
|
|
1346
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
1347
|
+
THEN RAISE EXCEPTION 'machine runtime scope mismatch' USING ERRCODE = '42501'; END IF;
|
|
1348
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
1349
|
+
backend_pid, transaction_id, capability_kind
|
|
1350
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'runtime')
|
|
1351
|
+
ON CONFLICT DO NOTHING;
|
|
1352
|
+
SELECT authorization_value.* INTO authorization_row
|
|
1353
|
+
FROM session_attempt_connected_machine_authorizations authorization_value
|
|
1354
|
+
WHERE authorization_value.attempt_id = p_attempt_id
|
|
1355
|
+
AND authorization_value.account_id = p_account_id
|
|
1356
|
+
AND authorization_value.workspace_id = p_workspace_id
|
|
1357
|
+
AND authorization_value.session_id = p_session_id
|
|
1358
|
+
AND authorization_value.turn_id = p_turn_id
|
|
1359
|
+
AND authorization_value.execution_generation = p_execution_generation
|
|
1360
|
+
AND authorization_value.enrollment_id = p_enrollment_id;
|
|
1361
|
+
IF authorization_row.attempt_id IS NULL THEN
|
|
1362
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1363
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1364
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
1365
|
+
AND capability_kind = 'runtime';
|
|
1366
|
+
RETURN false;
|
|
1367
|
+
END IF;
|
|
1368
|
+
IF caller_subject IS DISTINCT FROM authorization_row.initiating_human_subject_id
|
|
1369
|
+
OR NOT EXISTS (
|
|
1370
|
+
SELECT 1 FROM sessions session_value
|
|
1371
|
+
JOIN session_turns turn_value ON turn_value.id = p_turn_id
|
|
1372
|
+
AND turn_value.account_id = session_value.account_id
|
|
1373
|
+
AND turn_value.workspace_id = session_value.workspace_id
|
|
1374
|
+
AND turn_value.session_id = session_value.id
|
|
1375
|
+
JOIN session_turn_attempts attempt ON attempt.id = p_attempt_id
|
|
1376
|
+
AND attempt.turn_id = turn_value.id AND attempt.session_id = session_value.id
|
|
1377
|
+
AND attempt.account_id = session_value.account_id
|
|
1378
|
+
AND attempt.workspace_id = session_value.workspace_id
|
|
1379
|
+
JOIN sandboxes sandbox ON sandbox.id = authorization_row.sandbox_id
|
|
1380
|
+
AND sandbox.account_id = session_value.account_id
|
|
1381
|
+
WHERE session_value.id = p_session_id AND session_value.account_id = p_account_id
|
|
1382
|
+
AND session_value.workspace_id = p_workspace_id
|
|
1383
|
+
AND session_value.active_turn_id = p_turn_id
|
|
1384
|
+
AND (NOT p_require_active_sandbox
|
|
1385
|
+
OR session_value.active_sandbox_id = authorization_row.sandbox_id)
|
|
1386
|
+
AND session_value.visibility = authorization_row.session_visibility
|
|
1387
|
+
AND session_value.authority_epoch = authorization_row.session_authority_epoch
|
|
1388
|
+
AND turn_value.active_attempt_id = p_attempt_id
|
|
1389
|
+
AND turn_value.execution_generation = p_execution_generation
|
|
1390
|
+
AND turn_value.status = 'running'
|
|
1391
|
+
AND attempt.execution_generation = p_execution_generation
|
|
1392
|
+
AND attempt.state IN ('claimed','running') AND attempt.closed_at IS NULL
|
|
1393
|
+
AND attempt.quiesced_at IS NULL
|
|
1394
|
+
AND sandbox.enrollment_id = p_enrollment_id
|
|
1395
|
+
)
|
|
1396
|
+
OR EXISTS (
|
|
1397
|
+
SELECT 1 FROM session_attempt_interruptions interruption
|
|
1398
|
+
WHERE interruption.attempt_id = p_attempt_id AND interruption.account_id = p_account_id
|
|
1399
|
+
AND interruption.workspace_id = p_workspace_id
|
|
1400
|
+
AND interruption.state IN ('pending','delivered','acknowledged')
|
|
1401
|
+
)
|
|
1402
|
+
OR NOT EXISTS (
|
|
1403
|
+
SELECT 1 FROM organization_memberships membership
|
|
1404
|
+
WHERE membership.id = authorization_row.owner_organization_membership_id
|
|
1405
|
+
AND membership.account_id = p_account_id
|
|
1406
|
+
AND membership.subject_id = authorization_row.initiating_human_subject_id
|
|
1407
|
+
AND membership.status = 'active' AND membership.revoked_at IS NULL
|
|
1408
|
+
AND membership.authorization_revision
|
|
1409
|
+
= authorization_row.membership_authorization_revision
|
|
1410
|
+
AND (membership.personal_workspace_id = p_workspace_id OR EXISTS (
|
|
1411
|
+
SELECT 1 FROM workspace_memberships workspace_membership
|
|
1412
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
1413
|
+
AND workspace_membership.workspace_id = p_workspace_id
|
|
1414
|
+
AND workspace_membership.subject_id = membership.subject_id
|
|
1415
|
+
))
|
|
1416
|
+
)
|
|
1417
|
+
OR NOT EXISTS (
|
|
1418
|
+
SELECT 1 FROM enrollments enrollment
|
|
1419
|
+
WHERE enrollment.id = p_enrollment_id AND enrollment.account_id = p_account_id
|
|
1420
|
+
AND enrollment.authority_scope = 'user'
|
|
1421
|
+
AND enrollment.owner_organization_membership_id
|
|
1422
|
+
= authorization_row.owner_organization_membership_id
|
|
1423
|
+
AND enrollment.authority_id = authorization_row.authority_id
|
|
1424
|
+
AND enrollment.generation = authorization_row.enrollment_generation
|
|
1425
|
+
AND enrollment.status = 'active' AND enrollment.revoked_at IS NULL
|
|
1426
|
+
)
|
|
1427
|
+
OR NOT EXISTS (
|
|
1428
|
+
SELECT 1 FROM organization_user_resource_authorities authority
|
|
1429
|
+
WHERE authority.id = authorization_row.authority_id
|
|
1430
|
+
AND authority.account_id = p_account_id
|
|
1431
|
+
AND authority.organization_membership_id
|
|
1432
|
+
= authorization_row.owner_organization_membership_id
|
|
1433
|
+
AND authority.resource_kind = 'connected_machine'
|
|
1434
|
+
AND authority.resource_id = p_enrollment_id
|
|
1435
|
+
AND authority.generation = authorization_row.authority_generation
|
|
1436
|
+
AND authority.status = 'active' AND authority.revoked_at IS NULL
|
|
1437
|
+
)
|
|
1438
|
+
OR NOT EXISTS (
|
|
1439
|
+
SELECT 1 FROM organization_user_resource_grants grant_value
|
|
1440
|
+
WHERE grant_value.id = authorization_row.grant_id
|
|
1441
|
+
AND grant_value.account_id = p_account_id
|
|
1442
|
+
AND grant_value.authority_id = authorization_row.authority_id
|
|
1443
|
+
AND grant_value.owner_organization_membership_id
|
|
1444
|
+
= authorization_row.owner_organization_membership_id
|
|
1445
|
+
AND grant_value.workspace_id = p_workspace_id
|
|
1446
|
+
AND grant_value.generation = authorization_row.grant_generation
|
|
1447
|
+
AND grant_value.action = 'connected_machine.use'
|
|
1448
|
+
AND grant_value.context = authorization_row.session_visibility
|
|
1449
|
+
AND grant_value.mode = authorization_row.grant_mode
|
|
1450
|
+
AND (grant_value.expires_at IS NULL OR grant_value.expires_at > clock_timestamp())
|
|
1451
|
+
AND ((authorization_row.grant_mode = 'once' AND grant_value.status = 'consumed'
|
|
1452
|
+
AND grant_value.session_id = p_session_id
|
|
1453
|
+
AND grant_value.authority_epoch = authorization_row.session_authority_epoch
|
|
1454
|
+
AND EXISTS (SELECT 1 FROM personal_resource_once_consumption_receipts receipt
|
|
1455
|
+
WHERE receipt.grant_id = grant_value.id AND receipt.attempt_id = p_attempt_id
|
|
1456
|
+
AND receipt.account_id = p_account_id))
|
|
1457
|
+
OR (authorization_row.grant_mode = 'session' AND grant_value.status = 'active'
|
|
1458
|
+
AND grant_value.session_id = p_session_id
|
|
1459
|
+
AND grant_value.authority_epoch = authorization_row.session_authority_epoch)
|
|
1460
|
+
OR (authorization_row.grant_mode = 'always' AND grant_value.status = 'active'
|
|
1461
|
+
AND grant_value.session_id IS NULL AND grant_value.authority_epoch IS NULL))
|
|
1462
|
+
)
|
|
1463
|
+
THEN RAISE EXCEPTION 'personal machine authority is no longer live'
|
|
1464
|
+
USING ERRCODE = '42501'; END IF;
|
|
1465
|
+
INSERT INTO audit_events(
|
|
1466
|
+
account_id, workspace_id, subject_id, action, target_type, target_id,
|
|
1467
|
+
metadata, metadata_codec_version
|
|
1468
|
+
) VALUES (
|
|
1469
|
+
p_account_id, p_workspace_id, authorization_row.initiating_human_subject_id,
|
|
1470
|
+
'connected_machine.used', 'enrollment', p_enrollment_id::text,
|
|
1471
|
+
pg_catalog.jsonb_build_object(
|
|
1472
|
+
'ownerOrganizationMembershipId', authorization_row.owner_organization_membership_id,
|
|
1473
|
+
'scope', 'user', 'sessionId', p_session_id, 'turnId', p_turn_id,
|
|
1474
|
+
'attemptId', p_attempt_id, 'executionGeneration', p_execution_generation,
|
|
1475
|
+
'generation', authorization_row.enrollment_generation
|
|
1476
|
+
), 1
|
|
1477
|
+
);
|
|
1478
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1479
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1480
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
1481
|
+
AND capability_kind = 'runtime';
|
|
1482
|
+
RETURN true;
|
|
1483
|
+
EXCEPTION WHEN OTHERS THEN
|
|
1484
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1485
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1486
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1487
|
+
RAISE;
|
|
1488
|
+
END
|
|
1489
|
+
$$;
|
|
1490
|
+
REVOKE ALL ON FUNCTION assert_session_attempt_personal_machine(
|
|
1491
|
+
uuid, uuid, uuid, uuid, uuid, integer, uuid, boolean
|
|
1492
|
+
) FROM PUBLIC;
|
|
1493
|
+
|
|
1494
|
+
CREATE OR REPLACE FUNCTION list_scoped_machine_dependent_sessions(
|
|
1495
|
+
p_account_id uuid,
|
|
1496
|
+
p_origin_workspace_id uuid,
|
|
1497
|
+
p_sandbox_id uuid
|
|
1498
|
+
) RETURNS TABLE(
|
|
1499
|
+
session_id uuid,
|
|
1500
|
+
title text,
|
|
1501
|
+
active_turn_id uuid,
|
|
1502
|
+
sandbox_backend text
|
|
1503
|
+
)
|
|
1504
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
1505
|
+
BEGIN
|
|
1506
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
1507
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
1508
|
+
OR p_origin_workspace_id IS DISTINCT FROM nullif(
|
|
1509
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
1510
|
+
THEN RAISE EXCEPTION 'machine removal scope mismatch' USING ERRCODE = '42501'; END IF;
|
|
1511
|
+
IF NOT EXISTS (
|
|
1512
|
+
SELECT 1 FROM sandboxes sandbox
|
|
1513
|
+
WHERE sandbox.id = p_sandbox_id AND sandbox.account_id = p_account_id
|
|
1514
|
+
AND sandbox.workspace_id = p_origin_workspace_id
|
|
1515
|
+
AND sandbox.kind = 'selfhosted' AND sandbox.enrollment_id IS NOT NULL
|
|
1516
|
+
) THEN RAISE EXCEPTION 'machine sandbox not found' USING ERRCODE = '42501'; END IF;
|
|
1517
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
1518
|
+
backend_pid, transaction_id, capability_kind
|
|
1519
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'read')
|
|
1520
|
+
ON CONFLICT DO NOTHING;
|
|
1521
|
+
RETURN QUERY
|
|
1522
|
+
SELECT session.id, session.title, session.active_turn_id, session.sandbox_backend
|
|
1523
|
+
FROM sessions session
|
|
1524
|
+
WHERE session.account_id = p_account_id
|
|
1525
|
+
AND (session.active_sandbox_id = p_sandbox_id
|
|
1526
|
+
OR session.sandbox_group_id = p_sandbox_id)
|
|
1527
|
+
ORDER BY session.created_at, session.id
|
|
1528
|
+
FOR NO KEY UPDATE;
|
|
1529
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1530
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1531
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
1532
|
+
AND capability_kind = 'read';
|
|
1533
|
+
EXCEPTION WHEN OTHERS THEN
|
|
1534
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1535
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1536
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1537
|
+
RAISE;
|
|
1538
|
+
END
|
|
1539
|
+
$$;
|
|
1540
|
+
REVOKE ALL ON FUNCTION list_scoped_machine_dependent_sessions(uuid, uuid, uuid)
|
|
1541
|
+
FROM PUBLIC;
|
|
1542
|
+
|
|
1543
|
+
CREATE OR REPLACE FUNCTION detach_scoped_machine_dependent_sessions(
|
|
1544
|
+
p_account_id uuid,
|
|
1545
|
+
p_origin_workspace_id uuid,
|
|
1546
|
+
p_sandbox_id uuid
|
|
1547
|
+
) RETURNS TABLE(session_id uuid, title text)
|
|
1548
|
+
LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
|
|
1549
|
+
DECLARE
|
|
1550
|
+
dependent_workspace_id uuid;
|
|
1551
|
+
detached_record record;
|
|
1552
|
+
next_activity_revision bigint;
|
|
1553
|
+
BEGIN
|
|
1554
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
1555
|
+
pg_catalog.current_setting('opengeni.account_id', true), '')::uuid
|
|
1556
|
+
OR p_origin_workspace_id IS DISTINCT FROM nullif(
|
|
1557
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), '')::uuid
|
|
1558
|
+
THEN RAISE EXCEPTION 'machine removal scope mismatch' USING ERRCODE = '42501'; END IF;
|
|
1559
|
+
IF NOT EXISTS (
|
|
1560
|
+
SELECT 1 FROM sandboxes sandbox
|
|
1561
|
+
WHERE sandbox.id = p_sandbox_id AND sandbox.account_id = p_account_id
|
|
1562
|
+
AND sandbox.workspace_id = p_origin_workspace_id
|
|
1563
|
+
AND sandbox.kind = 'selfhosted' AND sandbox.enrollment_id IS NOT NULL
|
|
1564
|
+
) THEN RAISE EXCEPTION 'machine sandbox not found' USING ERRCODE = '42501'; END IF;
|
|
1565
|
+
INSERT INTO opengeni_private.scoped_compute_capabilities(
|
|
1566
|
+
backend_pid, transaction_id, capability_kind
|
|
1567
|
+
) VALUES (pg_catalog.pg_backend_pid(), pg_catalog.pg_current_xact_id(), 'write')
|
|
1568
|
+
ON CONFLICT DO NOTHING;
|
|
1569
|
+
IF EXISTS (
|
|
1570
|
+
SELECT 1 FROM sessions session
|
|
1571
|
+
WHERE session.account_id = p_account_id
|
|
1572
|
+
AND (session.active_sandbox_id = p_sandbox_id
|
|
1573
|
+
OR session.sandbox_group_id = p_sandbox_id)
|
|
1574
|
+
AND session.active_turn_id IS NOT NULL
|
|
1575
|
+
) THEN RAISE EXCEPTION 'machine still has active dependent sessions'
|
|
1576
|
+
USING ERRCODE = '55000'; END IF;
|
|
1577
|
+
FOR dependent_workspace_id IN
|
|
1578
|
+
SELECT DISTINCT session.workspace_id
|
|
1579
|
+
FROM sessions session
|
|
1580
|
+
WHERE session.account_id = p_account_id
|
|
1581
|
+
AND (session.active_sandbox_id = p_sandbox_id
|
|
1582
|
+
OR (session.sandbox_group_id = p_sandbox_id
|
|
1583
|
+
AND session.sandbox_backend = 'selfhosted'))
|
|
1584
|
+
ORDER BY session.workspace_id
|
|
1585
|
+
LOOP
|
|
1586
|
+
PERFORM pg_catalog.set_config('opengeni.session_activity_gate_state', 'open', true);
|
|
1587
|
+
PERFORM pg_catalog.set_config(
|
|
1588
|
+
'opengeni.session_activity_gate_workspace_id', dependent_workspace_id::text, true
|
|
1589
|
+
);
|
|
1590
|
+
FOR detached_record IN
|
|
1591
|
+
UPDATE sessions session
|
|
1592
|
+
SET active_sandbox_id = NULL,
|
|
1593
|
+
active_epoch = session.active_epoch + 1,
|
|
1594
|
+
sandbox_backend = CASE
|
|
1595
|
+
WHEN session.sandbox_backend = 'selfhosted' THEN 'none'
|
|
1596
|
+
ELSE session.sandbox_backend
|
|
1597
|
+
END,
|
|
1598
|
+
updated_at = clock_timestamp()
|
|
1599
|
+
WHERE session.account_id = p_account_id
|
|
1600
|
+
AND session.workspace_id = dependent_workspace_id
|
|
1601
|
+
AND (session.active_sandbox_id = p_sandbox_id
|
|
1602
|
+
OR (session.sandbox_group_id = p_sandbox_id
|
|
1603
|
+
AND session.sandbox_backend = 'selfhosted'))
|
|
1604
|
+
RETURNING session.id, session.title
|
|
1605
|
+
LOOP
|
|
1606
|
+
session_id := detached_record.id;
|
|
1607
|
+
title := detached_record.title;
|
|
1608
|
+
RETURN NEXT;
|
|
1609
|
+
END LOOP;
|
|
1610
|
+
PERFORM pg_catalog.set_config('opengeni.session_activity_gate_state', 'finalizing', true);
|
|
1611
|
+
UPDATE workspace_session_activity_revisions counter
|
|
1612
|
+
SET revision = counter.revision + 1
|
|
1613
|
+
WHERE counter.workspace_id = dependent_workspace_id
|
|
1614
|
+
AND EXISTS (
|
|
1615
|
+
SELECT 1 FROM sessions pending
|
|
1616
|
+
WHERE pending.workspace_id = dependent_workspace_id
|
|
1617
|
+
AND pending.activity_revision_pending_xid
|
|
1618
|
+
= pg_catalog.pg_current_xact_id()::text::bigint
|
|
1619
|
+
)
|
|
1620
|
+
RETURNING counter.revision INTO next_activity_revision;
|
|
1621
|
+
UPDATE sessions pending
|
|
1622
|
+
SET activity_revision = next_activity_revision,
|
|
1623
|
+
activity_revision_pending_xid = NULL
|
|
1624
|
+
WHERE pending.workspace_id = dependent_workspace_id
|
|
1625
|
+
AND pending.activity_revision_pending_xid
|
|
1626
|
+
= pg_catalog.pg_current_xact_id()::text::bigint;
|
|
1627
|
+
END LOOP;
|
|
1628
|
+
PERFORM pg_catalog.set_config('opengeni.session_activity_gate_state', 'open', true);
|
|
1629
|
+
PERFORM pg_catalog.set_config(
|
|
1630
|
+
'opengeni.session_activity_gate_workspace_id', p_origin_workspace_id::text, true
|
|
1631
|
+
);
|
|
1632
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1633
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1634
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned()
|
|
1635
|
+
AND capability_kind = 'write';
|
|
1636
|
+
EXCEPTION WHEN OTHERS THEN
|
|
1637
|
+
DELETE FROM opengeni_private.scoped_compute_capabilities
|
|
1638
|
+
WHERE backend_pid = pg_catalog.pg_backend_pid()
|
|
1639
|
+
AND transaction_id = pg_catalog.pg_current_xact_id_if_assigned();
|
|
1640
|
+
RAISE;
|
|
1641
|
+
END
|
|
1642
|
+
$$;
|
|
1643
|
+
REVOKE ALL ON FUNCTION detach_scoped_machine_dependent_sessions(uuid, uuid, uuid)
|
|
1644
|
+
FROM PUBLIC;
|
|
1645
|
+
|
|
1646
|
+
DO $grants$
|
|
1647
|
+
BEGIN
|
|
1648
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
1649
|
+
-- Policies on ordinary runtime-visible tables call this predicate. EXECUTE
|
|
1650
|
+
-- only exposes false unless a same-transaction SECURITY DEFINER lifecycle
|
|
1651
|
+
-- inserted the unforgeable private capability row; the app role retains no
|
|
1652
|
+
-- table access to mint one.
|
|
1653
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.scoped_compute_capability_active(text)
|
|
1654
|
+
TO opengeni_app;
|
|
1655
|
+
GRANT EXECUTE ON FUNCTION list_scoped_rigs(uuid, uuid, uuid, text, text)
|
|
1656
|
+
TO opengeni_app;
|
|
1657
|
+
GRANT EXECUTE ON FUNCTION count_scoped_rigs(uuid, uuid, text) TO opengeni_app;
|
|
1658
|
+
GRANT EXECUTE ON FUNCTION create_scoped_rig(
|
|
1659
|
+
uuid, uuid, text, text, text, text, jsonb, boolean
|
|
1660
|
+
) TO opengeni_app;
|
|
1661
|
+
GRANT EXECUTE ON FUNCTION mutate_scoped_rig(
|
|
1662
|
+
uuid, uuid, uuid, text, text, boolean, text, boolean, boolean
|
|
1663
|
+
) TO opengeni_app;
|
|
1664
|
+
GRANT EXECUTE ON FUNCTION finalize_scoped_enrollment(
|
|
1665
|
+
uuid, uuid, text, text, boolean, boolean, text, text, text, boolean
|
|
1666
|
+
) TO opengeni_app;
|
|
1667
|
+
GRANT EXECUTE ON FUNCTION list_scoped_enrollments(uuid, uuid, uuid, text)
|
|
1668
|
+
TO opengeni_app;
|
|
1669
|
+
GRANT EXECUTE ON FUNCTION get_scoped_sandbox(uuid, uuid, uuid) TO opengeni_app;
|
|
1670
|
+
GRANT EXECUTE ON FUNCTION authorize_scoped_sandbox_attach(uuid, uuid, uuid)
|
|
1671
|
+
TO opengeni_app;
|
|
1672
|
+
GRANT EXECUTE ON FUNCTION materialize_scoped_rig_version_for_attempt(
|
|
1673
|
+
uuid, uuid, uuid, uuid, uuid, integer
|
|
1674
|
+
) TO opengeni_app;
|
|
1675
|
+
GRANT EXECUTE ON FUNCTION authorize_session_attempt_personal_machine(
|
|
1676
|
+
uuid, uuid, uuid, uuid, uuid, integer, uuid
|
|
1677
|
+
) TO opengeni_app;
|
|
1678
|
+
GRANT EXECUTE ON FUNCTION assert_session_attempt_personal_machine(
|
|
1679
|
+
uuid, uuid, uuid, uuid, uuid, integer, uuid, boolean
|
|
1680
|
+
) TO opengeni_app;
|
|
1681
|
+
GRANT EXECUTE ON FUNCTION list_scoped_machine_dependent_sessions(uuid, uuid, uuid)
|
|
1682
|
+
TO opengeni_app;
|
|
1683
|
+
GRANT EXECUTE ON FUNCTION detach_scoped_machine_dependent_sessions(uuid, uuid, uuid)
|
|
1684
|
+
TO opengeni_app;
|
|
1685
|
+
REVOKE ALL ON TABLE opengeni_private.scoped_compute_capabilities FROM opengeni_app;
|
|
1686
|
+
REVOKE ALL ON TABLE session_attempt_connected_machine_authorizations
|
|
1687
|
+
FROM opengeni_app;
|
|
1688
|
+
REVOKE ALL ON TABLE organization_user_resource_authorities FROM opengeni_app;
|
|
1689
|
+
REVOKE ALL ON TABLE organization_user_resource_grants FROM opengeni_app;
|
|
1690
|
+
END IF;
|
|
1691
|
+
END
|
|
1692
|
+
$grants$;
|
|
1693
|
+
|
|
1694
|
+
COMMENT ON COLUMN rigs.authority_scope IS
|
|
1695
|
+
'Explicit owner scope: organization, workspace, or organization+user.';
|
|
1696
|
+
COMMENT ON COLUMN enrollments.authority_scope IS
|
|
1697
|
+
'Connected Machine owner scope; human approval defaults to organization+user.';
|
|
1698
|
+
COMMENT ON FUNCTION assert_session_attempt_personal_machine(
|
|
1699
|
+
uuid, uuid, uuid, uuid, uuid, integer, uuid, boolean
|
|
1700
|
+
) IS 'Revalidates exact personal-machine owner, membership, grant, session authority, and generation immediately before machine use.';
|