@opengeni/db 0.36.1 → 3.1.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
- package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
- package/dist/{chunk-HSOWSYOX.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-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
- package/dist/chunk-PR2WMLOQ.js.map +1 -0
- package/dist/{chunk-Z7VYMNPZ.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.d.ts +10 -0
- package/dist/editable-artifact-durable-export.js +18 -3
- package/dist/editable-artifact-durable-export.js.map +1 -1
- 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 +1633 -87
- package/dist/index.js +22004 -8109
- 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/knowledge-source-sync-schema.d.ts +730 -0
- package/dist/knowledge-source-sync.d.ts +60 -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 +23 -9
- package/dist/schema.d.ts +24925 -13697
- package/dist/schema.js +103 -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 +42 -5
- package/dist/session-realtime-ledger.d.ts +3 -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/0240_model_context_user_messages.sql +204 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0243_google_drive_object_acl_authority.sql +554 -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-artifact-durable-export.ts +27 -0
- 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 +12001 -1699
- 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/knowledge-source-sync-schema.ts +83 -0
- package/src/knowledge-source-sync.ts +530 -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 +931 -24
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1315 -52
- package/src/schema.ts +3336 -438
- 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 +450 -98
- package/src/session-realtime-context.ts +19 -3
- package/src/session-realtime-ledger.ts +75 -12
- 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-5KTIEDX7.js.map +0 -1
- package/dist/chunk-FPVAD4CO.js +0 -117
- package/dist/chunk-FPVAD4CO.js.map +0 -1
- package/dist/chunk-HSOWSYOX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-VKLB2ZGI.js +0 -2389
- package/dist/chunk-VKLB2ZGI.js.map +0 -1
- package/dist/chunk-Z7VYMNPZ.js.map +0 -1
- /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
- /package/dist/{chunk-VTPRIXKG.js.map → chunk-NJVZPWXY.js.map} +0 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Activate explicit workspace and organization+user authority for provider
|
|
3
|
+
-- connections. Credential material remains in connections. This migration owns
|
|
4
|
+
-- only metadata authority, immutable generations, grants, and pre-use fencing.
|
|
5
|
+
|
|
6
|
+
SET LOCAL lock_timeout = '5s';
|
|
7
|
+
SET LOCAL statement_timeout = '10min';
|
|
8
|
+
|
|
9
|
+
ALTER TABLE "connections"
|
|
10
|
+
ADD COLUMN "authority_scope" text NOT NULL DEFAULT 'workspace',
|
|
11
|
+
ADD COLUMN "authority_id" uuid,
|
|
12
|
+
ADD COLUMN "owner_organization_membership_id" uuid,
|
|
13
|
+
ADD COLUMN "origin_workspace_id" uuid,
|
|
14
|
+
ADD COLUMN "authority_generation" bigint NOT NULL DEFAULT 1;
|
|
15
|
+
|
|
16
|
+
UPDATE "connections"
|
|
17
|
+
SET "origin_workspace_id" = "workspace_id"
|
|
18
|
+
WHERE "origin_workspace_id" IS NULL;
|
|
19
|
+
|
|
20
|
+
DO $backfill_personal_connection_authority$
|
|
21
|
+
DECLARE
|
|
22
|
+
connection_row record;
|
|
23
|
+
membership_id uuid;
|
|
24
|
+
authority_value uuid;
|
|
25
|
+
BEGIN
|
|
26
|
+
FOR connection_row IN
|
|
27
|
+
SELECT connection_value.id, connection_value.account_id,
|
|
28
|
+
connection_value.workspace_id, connection_value.subject_id
|
|
29
|
+
FROM connections connection_value
|
|
30
|
+
WHERE connection_value.subject_id IS NOT NULL
|
|
31
|
+
ORDER BY connection_value.account_id, connection_value.id
|
|
32
|
+
FOR UPDATE
|
|
33
|
+
LOOP
|
|
34
|
+
SELECT membership.id INTO membership_id
|
|
35
|
+
FROM organization_memberships membership
|
|
36
|
+
WHERE membership.account_id = connection_row.account_id
|
|
37
|
+
AND membership.subject_id = connection_row.subject_id
|
|
38
|
+
AND membership.status = 'active'
|
|
39
|
+
AND membership.revoked_at IS NULL;
|
|
40
|
+
|
|
41
|
+
IF membership_id IS NULL THEN
|
|
42
|
+
UPDATE connections
|
|
43
|
+
SET authority_scope = 'legacy_user', authority_id = NULL,
|
|
44
|
+
owner_organization_membership_id = NULL,
|
|
45
|
+
origin_workspace_id = connection_row.workspace_id,
|
|
46
|
+
authority_generation = 1
|
|
47
|
+
WHERE id = connection_row.id;
|
|
48
|
+
CONTINUE;
|
|
49
|
+
END IF;
|
|
50
|
+
|
|
51
|
+
authority_value := pg_catalog.gen_random_uuid();
|
|
52
|
+
INSERT INTO organization_user_resource_authorities (
|
|
53
|
+
id, account_id, organization_membership_id, resource_kind, resource_id,
|
|
54
|
+
origin_workspace_id, generation, status
|
|
55
|
+
) VALUES (
|
|
56
|
+
authority_value, connection_row.account_id, membership_id, 'connection',
|
|
57
|
+
connection_row.id, connection_row.workspace_id, 1, 'active'
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
UPDATE connections
|
|
61
|
+
SET authority_scope = 'user', authority_id = authority_value,
|
|
62
|
+
owner_organization_membership_id = membership_id,
|
|
63
|
+
origin_workspace_id = connection_row.workspace_id,
|
|
64
|
+
authority_generation = 1
|
|
65
|
+
WHERE id = connection_row.id;
|
|
66
|
+
END LOOP;
|
|
67
|
+
END
|
|
68
|
+
$backfill_personal_connection_authority$;
|
|
69
|
+
|
|
70
|
+
ALTER TABLE "connections"
|
|
71
|
+
ADD CONSTRAINT "connections_authority_scope_check"
|
|
72
|
+
CHECK ("authority_scope" IN ('workspace', 'user', 'legacy_user')) NOT VALID,
|
|
73
|
+
ADD CONSTRAINT "connections_authority_shape_check" CHECK (
|
|
74
|
+
(
|
|
75
|
+
"authority_scope" = 'workspace'
|
|
76
|
+
AND "subject_id" IS NULL
|
|
77
|
+
AND "authority_id" IS NULL
|
|
78
|
+
AND "owner_organization_membership_id" IS NULL
|
|
79
|
+
AND "origin_workspace_id" = "workspace_id"
|
|
80
|
+
) OR (
|
|
81
|
+
"authority_scope" = 'user'
|
|
82
|
+
AND "subject_id" IS NOT NULL
|
|
83
|
+
AND "authority_id" IS NOT NULL
|
|
84
|
+
AND "owner_organization_membership_id" IS NOT NULL
|
|
85
|
+
AND "origin_workspace_id" IS NOT NULL
|
|
86
|
+
) OR (
|
|
87
|
+
"authority_scope" = 'legacy_user'
|
|
88
|
+
AND "subject_id" IS NOT NULL
|
|
89
|
+
AND "authority_id" IS NULL
|
|
90
|
+
AND "owner_organization_membership_id" IS NULL
|
|
91
|
+
AND "origin_workspace_id" IS NOT NULL
|
|
92
|
+
)
|
|
93
|
+
) NOT VALID,
|
|
94
|
+
ADD CONSTRAINT "connections_authority_generation_check"
|
|
95
|
+
CHECK ("authority_generation" > 0) NOT VALID,
|
|
96
|
+
ADD CONSTRAINT "connections_authority_fk" FOREIGN KEY (
|
|
97
|
+
"authority_id", "account_id", "owner_organization_membership_id"
|
|
98
|
+
) REFERENCES "organization_user_resource_authorities"(
|
|
99
|
+
"id", "account_id", "organization_membership_id"
|
|
100
|
+
) ON DELETE RESTRICT NOT VALID,
|
|
101
|
+
ADD CONSTRAINT "connections_origin_workspace_fk" FOREIGN KEY (
|
|
102
|
+
"origin_workspace_id", "account_id"
|
|
103
|
+
) REFERENCES "workspaces"("id", "account_id")
|
|
104
|
+
ON DELETE SET NULL ("origin_workspace_id") NOT VALID;
|
|
105
|
+
|
|
106
|
+
ALTER TABLE "connections"
|
|
107
|
+
VALIDATE CONSTRAINT "connections_authority_scope_check",
|
|
108
|
+
VALIDATE CONSTRAINT "connections_authority_shape_check",
|
|
109
|
+
VALIDATE CONSTRAINT "connections_authority_generation_check",
|
|
110
|
+
VALIDATE CONSTRAINT "connections_authority_fk",
|
|
111
|
+
VALIDATE CONSTRAINT "connections_origin_workspace_fk";
|
|
112
|
+
|
|
113
|
+
CREATE UNIQUE INDEX "connections_authority_identity_uq"
|
|
114
|
+
ON "connections" ("account_id", "authority_id")
|
|
115
|
+
WHERE "authority_id" IS NOT NULL;
|
|
116
|
+
CREATE INDEX "connections_owner_authority_idx"
|
|
117
|
+
ON "connections" (
|
|
118
|
+
"account_id", "owner_organization_membership_id", "status", "updated_at", "id"
|
|
119
|
+
) WHERE "authority_scope" = 'user';
|
|
120
|
+
|
|
121
|
+
CREATE TABLE "connection_use_once_consumption_receipts" (
|
|
122
|
+
"grant_id" uuid PRIMARY KEY,
|
|
123
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
124
|
+
"authority_id" uuid NOT NULL,
|
|
125
|
+
"authority_generation" bigint NOT NULL,
|
|
126
|
+
"grant_generation" bigint NOT NULL,
|
|
127
|
+
"accepted_work_kind" text NOT NULL,
|
|
128
|
+
"accepted_work_id" uuid NOT NULL,
|
|
129
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
130
|
+
CONSTRAINT "connection_once_receipts_authority_fk" FOREIGN KEY (
|
|
131
|
+
"authority_id", "account_id"
|
|
132
|
+
) REFERENCES "organization_user_resource_authorities"("id", "account_id")
|
|
133
|
+
ON DELETE CASCADE,
|
|
134
|
+
CONSTRAINT "connection_once_receipts_grant_fk" FOREIGN KEY (
|
|
135
|
+
"grant_id", "account_id"
|
|
136
|
+
) REFERENCES "organization_user_resource_grants"("id", "account_id")
|
|
137
|
+
ON DELETE CASCADE,
|
|
138
|
+
CONSTRAINT "connection_once_receipts_generation_check" CHECK (
|
|
139
|
+
"authority_generation" > 0 AND "grant_generation" > 0
|
|
140
|
+
),
|
|
141
|
+
CONSTRAINT "connection_once_receipts_work_kind_check" CHECK (
|
|
142
|
+
"accepted_work_kind" IN ('turn', 'scheduled_task')
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
ALTER TABLE "connection_use_once_consumption_receipts" ENABLE ROW LEVEL SECURITY;
|
|
147
|
+
ALTER TABLE "connection_use_once_consumption_receipts" FORCE ROW LEVEL SECURITY;
|
|
148
|
+
CREATE POLICY "organization_isolation" ON "connection_use_once_consumption_receipts"
|
|
149
|
+
USING (
|
|
150
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
151
|
+
) WITH CHECK (
|
|
152
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
DO $connection_authority_routines$
|
|
156
|
+
DECLARE
|
|
157
|
+
data_schema text := current_schema();
|
|
158
|
+
BEGIN
|
|
159
|
+
EXECUTE format($ddl$
|
|
160
|
+
CREATE OR REPLACE FUNCTION opengeni_private.bind_connection_authority()
|
|
161
|
+
RETURNS trigger
|
|
162
|
+
LANGUAGE plpgsql
|
|
163
|
+
SECURITY DEFINER
|
|
164
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
165
|
+
AS $body$
|
|
166
|
+
DECLARE
|
|
167
|
+
caller_subject text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
168
|
+
membership_id uuid;
|
|
169
|
+
authority_value uuid;
|
|
170
|
+
identity_changed boolean;
|
|
171
|
+
BEGIN
|
|
172
|
+
IF TG_OP = 'INSERT' THEN
|
|
173
|
+
NEW.origin_workspace_id := NEW.workspace_id;
|
|
174
|
+
NEW.authority_generation := 1;
|
|
175
|
+
IF NEW.subject_id IS NULL THEN
|
|
176
|
+
NEW.authority_scope := 'workspace';
|
|
177
|
+
NEW.authority_id := NULL;
|
|
178
|
+
NEW.owner_organization_membership_id := NULL;
|
|
179
|
+
RETURN NEW;
|
|
180
|
+
END IF;
|
|
181
|
+
IF caller_subject IS DISTINCT FROM NEW.subject_id THEN
|
|
182
|
+
RAISE EXCEPTION 'personal connection owner must be the authenticated subject'
|
|
183
|
+
USING ERRCODE = '42501';
|
|
184
|
+
END IF;
|
|
185
|
+
SELECT membership.id INTO membership_id
|
|
186
|
+
FROM organization_memberships membership
|
|
187
|
+
WHERE membership.account_id = NEW.account_id
|
|
188
|
+
AND membership.subject_id = caller_subject
|
|
189
|
+
AND membership.status = 'active'
|
|
190
|
+
AND membership.revoked_at IS NULL
|
|
191
|
+
FOR SHARE;
|
|
192
|
+
IF membership_id IS NULL THEN
|
|
193
|
+
NEW.authority_scope := 'legacy_user';
|
|
194
|
+
NEW.authority_id := NULL;
|
|
195
|
+
NEW.owner_organization_membership_id := NULL;
|
|
196
|
+
RETURN NEW;
|
|
197
|
+
END IF;
|
|
198
|
+
authority_value := gen_random_uuid();
|
|
199
|
+
INSERT INTO organization_user_resource_authorities (
|
|
200
|
+
id, account_id, organization_membership_id, resource_kind, resource_id,
|
|
201
|
+
origin_workspace_id, generation, status
|
|
202
|
+
) VALUES (
|
|
203
|
+
authority_value, NEW.account_id, membership_id, 'connection', NEW.id,
|
|
204
|
+
NEW.workspace_id, 1, 'active'
|
|
205
|
+
);
|
|
206
|
+
NEW.authority_scope := 'user';
|
|
207
|
+
NEW.authority_id := authority_value;
|
|
208
|
+
NEW.owner_organization_membership_id := membership_id;
|
|
209
|
+
RETURN NEW;
|
|
210
|
+
END IF;
|
|
211
|
+
|
|
212
|
+
IF NEW.account_id IS DISTINCT FROM OLD.account_id
|
|
213
|
+
OR NEW.workspace_id IS DISTINCT FROM OLD.workspace_id
|
|
214
|
+
OR NEW.subject_id IS DISTINCT FROM OLD.subject_id
|
|
215
|
+
OR NEW.authority_scope IS DISTINCT FROM OLD.authority_scope
|
|
216
|
+
OR NEW.authority_id IS DISTINCT FROM OLD.authority_id
|
|
217
|
+
OR NEW.owner_organization_membership_id
|
|
218
|
+
IS DISTINCT FROM OLD.owner_organization_membership_id
|
|
219
|
+
OR NEW.origin_workspace_id IS DISTINCT FROM OLD.origin_workspace_id
|
|
220
|
+
THEN
|
|
221
|
+
RAISE EXCEPTION 'connection owner authority is immutable' USING ERRCODE = '23514';
|
|
222
|
+
END IF;
|
|
223
|
+
|
|
224
|
+
identity_changed := NEW.provider_domain IS DISTINCT FROM OLD.provider_domain
|
|
225
|
+
OR NEW.kind IS DISTINCT FROM OLD.kind
|
|
226
|
+
OR NEW.status IS DISTINCT FROM OLD.status;
|
|
227
|
+
IF identity_changed THEN
|
|
228
|
+
NEW.authority_generation := OLD.authority_generation + 1;
|
|
229
|
+
ELSIF NEW.authority_generation NOT IN (
|
|
230
|
+
OLD.authority_generation, OLD.authority_generation + 1
|
|
231
|
+
) THEN
|
|
232
|
+
RAISE EXCEPTION 'connection authority generation must be stable or advance once'
|
|
233
|
+
USING ERRCODE = '23514';
|
|
234
|
+
END IF;
|
|
235
|
+
RETURN NEW;
|
|
236
|
+
END
|
|
237
|
+
$body$
|
|
238
|
+
$ddl$, data_schema);
|
|
239
|
+
|
|
240
|
+
EXECUTE format($ddl$
|
|
241
|
+
CREATE TRIGGER connections_authority_binding
|
|
242
|
+
BEFORE INSERT OR UPDATE ON %1$I.connections
|
|
243
|
+
FOR EACH ROW EXECUTE FUNCTION opengeni_private.bind_connection_authority()
|
|
244
|
+
$ddl$, data_schema);
|
|
245
|
+
|
|
246
|
+
EXECUTE format($ddl$
|
|
247
|
+
CREATE OR REPLACE FUNCTION opengeni_private.validate_user_resource_grant_action()
|
|
248
|
+
RETURNS trigger
|
|
249
|
+
LANGUAGE plpgsql
|
|
250
|
+
SECURITY DEFINER
|
|
251
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
252
|
+
AS $body$
|
|
253
|
+
BEGIN
|
|
254
|
+
IF NEW.action <> 'connection.use' AND EXISTS (
|
|
255
|
+
SELECT 1
|
|
256
|
+
FROM organization_user_resource_authorities authority
|
|
257
|
+
WHERE authority.id = NEW.authority_id
|
|
258
|
+
AND authority.account_id = NEW.account_id
|
|
259
|
+
AND authority.resource_kind = 'connection'
|
|
260
|
+
) THEN
|
|
261
|
+
RAISE EXCEPTION 'connection grants require connection.use'
|
|
262
|
+
USING ERRCODE = '22023';
|
|
263
|
+
END IF;
|
|
264
|
+
RETURN NEW;
|
|
265
|
+
END
|
|
266
|
+
$body$
|
|
267
|
+
$ddl$, data_schema);
|
|
268
|
+
|
|
269
|
+
EXECUTE format($ddl$
|
|
270
|
+
CREATE TRIGGER organization_user_resource_grants_action_contract
|
|
271
|
+
BEFORE INSERT OR UPDATE OF account_id, authority_id, action
|
|
272
|
+
ON %1$I.organization_user_resource_grants
|
|
273
|
+
FOR EACH ROW
|
|
274
|
+
EXECUTE FUNCTION opengeni_private.validate_user_resource_grant_action()
|
|
275
|
+
$ddl$, data_schema);
|
|
276
|
+
|
|
277
|
+
EXECUTE format($ddl$
|
|
278
|
+
CREATE OR REPLACE FUNCTION %1$I.list_self_connection_authorities(
|
|
279
|
+
p_account_id uuid
|
|
280
|
+
) RETURNS TABLE (
|
|
281
|
+
authority_id uuid, authority_generation bigint, authority_status text,
|
|
282
|
+
grant_id uuid, target_workspace_id uuid, target_session_id uuid,
|
|
283
|
+
grant_mode text, grant_context text, grant_generation bigint,
|
|
284
|
+
grant_status text, expires_at timestamptz
|
|
285
|
+
)
|
|
286
|
+
LANGUAGE sql
|
|
287
|
+
SECURITY DEFINER
|
|
288
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
289
|
+
AS $body$
|
|
290
|
+
SELECT authority.authority_id, authority.authority_generation,
|
|
291
|
+
authority.authority_status, authority.grant_id,
|
|
292
|
+
authority.target_workspace_id, authority.target_session_id,
|
|
293
|
+
authority.grant_mode, authority.grant_context,
|
|
294
|
+
authority.grant_generation, authority.grant_status, authority.expires_at
|
|
295
|
+
FROM list_self_user_resource_authorities(p_account_id) authority
|
|
296
|
+
WHERE authority.resource_kind = 'connection'
|
|
297
|
+
AND (authority.grant_id IS NULL OR authority.action = 'connection.use')
|
|
298
|
+
$body$
|
|
299
|
+
$ddl$, data_schema);
|
|
300
|
+
|
|
301
|
+
EXECUTE format($ddl$
|
|
302
|
+
CREATE OR REPLACE FUNCTION %1$I.issue_self_connection_use_grant(
|
|
303
|
+
p_account_id uuid,
|
|
304
|
+
p_authority_id uuid,
|
|
305
|
+
p_workspace_id uuid,
|
|
306
|
+
p_mode text,
|
|
307
|
+
p_context text,
|
|
308
|
+
p_session_id uuid DEFAULT NULL,
|
|
309
|
+
p_workspace_shared_acknowledged boolean DEFAULT false
|
|
310
|
+
) RETURNS TABLE (
|
|
311
|
+
grant_id uuid, target_workspace_id uuid, target_session_id uuid,
|
|
312
|
+
action text, grant_mode text, grant_context text, grant_generation bigint,
|
|
313
|
+
grant_status text, expires_at timestamptz
|
|
314
|
+
)
|
|
315
|
+
LANGUAGE plpgsql
|
|
316
|
+
SECURITY DEFINER
|
|
317
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
318
|
+
AS $body$
|
|
319
|
+
BEGIN
|
|
320
|
+
PERFORM 1
|
|
321
|
+
FROM organization_user_resource_authorities authority
|
|
322
|
+
WHERE authority.id = p_authority_id
|
|
323
|
+
AND authority.account_id = p_account_id
|
|
324
|
+
AND authority.resource_kind = 'connection';
|
|
325
|
+
IF NOT FOUND THEN
|
|
326
|
+
RAISE EXCEPTION 'self-owned connection authority required' USING ERRCODE = '42501';
|
|
327
|
+
END IF;
|
|
328
|
+
RETURN QUERY SELECT * FROM issue_self_user_resource_grant(
|
|
329
|
+
p_account_id, p_authority_id, p_workspace_id, 'connection.use', p_mode,
|
|
330
|
+
p_context, p_session_id, p_workspace_shared_acknowledged
|
|
331
|
+
);
|
|
332
|
+
END
|
|
333
|
+
$body$
|
|
334
|
+
$ddl$, data_schema);
|
|
335
|
+
|
|
336
|
+
EXECUTE format($ddl$
|
|
337
|
+
CREATE OR REPLACE FUNCTION %1$I.revoke_self_connection_use_grant(
|
|
338
|
+
p_account_id uuid,
|
|
339
|
+
p_grant_id uuid
|
|
340
|
+
) RETURNS TABLE (
|
|
341
|
+
grant_id uuid, grant_generation bigint, grant_status text, revoked_at timestamptz
|
|
342
|
+
)
|
|
343
|
+
LANGUAGE plpgsql
|
|
344
|
+
SECURITY DEFINER
|
|
345
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
346
|
+
AS $body$
|
|
347
|
+
BEGIN
|
|
348
|
+
PERFORM 1
|
|
349
|
+
FROM organization_user_resource_grants grant_value
|
|
350
|
+
JOIN organization_user_resource_authorities authority
|
|
351
|
+
ON authority.id = grant_value.authority_id
|
|
352
|
+
AND authority.account_id = grant_value.account_id
|
|
353
|
+
WHERE grant_value.id = p_grant_id
|
|
354
|
+
AND grant_value.account_id = p_account_id
|
|
355
|
+
AND grant_value.action = 'connection.use'
|
|
356
|
+
AND authority.resource_kind = 'connection';
|
|
357
|
+
IF NOT FOUND THEN
|
|
358
|
+
RAISE EXCEPTION 'self-owned connection use grant required' USING ERRCODE = '42501';
|
|
359
|
+
END IF;
|
|
360
|
+
RETURN QUERY SELECT * FROM revoke_self_user_resource_grant(p_account_id, p_grant_id);
|
|
361
|
+
END
|
|
362
|
+
$body$
|
|
363
|
+
$ddl$, data_schema);
|
|
364
|
+
|
|
365
|
+
EXECUTE format($ddl$
|
|
366
|
+
CREATE OR REPLACE FUNCTION %1$I.resolve_connection_use_authority(
|
|
367
|
+
p_account_id uuid,
|
|
368
|
+
p_workspace_id uuid,
|
|
369
|
+
p_session_id uuid,
|
|
370
|
+
p_snapshot jsonb
|
|
371
|
+
) RETURNS TABLE (
|
|
372
|
+
authorization_status text,
|
|
373
|
+
denial_reason text,
|
|
374
|
+
connection_id uuid,
|
|
375
|
+
connection_generation bigint,
|
|
376
|
+
authority_scope text,
|
|
377
|
+
owner_subject_id text,
|
|
378
|
+
authority_id uuid,
|
|
379
|
+
grant_id uuid
|
|
380
|
+
)
|
|
381
|
+
LANGUAGE plpgsql
|
|
382
|
+
SECURITY DEFINER
|
|
383
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
384
|
+
AS $body$
|
|
385
|
+
#variable_conflict use_column
|
|
386
|
+
DECLARE
|
|
387
|
+
session_row record;
|
|
388
|
+
connection_row record;
|
|
389
|
+
membership_row record;
|
|
390
|
+
authority_row record;
|
|
391
|
+
grant_row record;
|
|
392
|
+
receipt_row record;
|
|
393
|
+
accepted_kind text := p_snapshot #>> '{acceptedWork,kind}';
|
|
394
|
+
accepted_id uuid := coalesce(
|
|
395
|
+
nullif(p_snapshot #>> '{acceptedWork,turnId}', '')::uuid,
|
|
396
|
+
nullif(p_snapshot #>> '{acceptedWork,taskId}', '')::uuid
|
|
397
|
+
);
|
|
398
|
+
snapshot_scope text := p_snapshot ->> 'scope';
|
|
399
|
+
snapshot_owner text := nullif(p_snapshot ->> 'ownerSubjectId', '');
|
|
400
|
+
snapshot_membership uuid := nullif(
|
|
401
|
+
p_snapshot ->> 'ownerOrganizationMembershipId', ''
|
|
402
|
+
)::uuid;
|
|
403
|
+
snapshot_authority uuid := nullif(
|
|
404
|
+
p_snapshot #>> '{userDelegation,authorityId}', ''
|
|
405
|
+
)::uuid;
|
|
406
|
+
snapshot_grant uuid := nullif(p_snapshot #>> '{userDelegation,grantId}', '')::uuid;
|
|
407
|
+
BEGIN
|
|
408
|
+
IF p_account_id IS DISTINCT FROM nullif(
|
|
409
|
+
current_setting('opengeni.account_id', true), ''
|
|
410
|
+
)::uuid
|
|
411
|
+
OR p_workspace_id IS DISTINCT FROM nullif(
|
|
412
|
+
current_setting('opengeni.workspace_id', true), ''
|
|
413
|
+
)::uuid
|
|
414
|
+
OR p_snapshot ->> 'organizationId' IS DISTINCT FROM p_account_id::text
|
|
415
|
+
OR p_snapshot ->> 'targetWorkspaceId' IS DISTINCT FROM p_workspace_id::text
|
|
416
|
+
OR p_snapshot ->> 'targetSessionId' IS DISTINCT FROM p_session_id::text
|
|
417
|
+
THEN
|
|
418
|
+
RAISE EXCEPTION 'connection use scope mismatch' USING ERRCODE = '42501';
|
|
419
|
+
END IF;
|
|
420
|
+
|
|
421
|
+
SELECT session_value.id, session_value.account_id, session_value.workspace_id,
|
|
422
|
+
session_value.visibility, session_value.authority_epoch, session_value.status
|
|
423
|
+
INTO session_row
|
|
424
|
+
FROM sessions session_value
|
|
425
|
+
WHERE session_value.id = p_session_id
|
|
426
|
+
AND session_value.account_id = p_account_id
|
|
427
|
+
AND session_value.workspace_id = p_workspace_id;
|
|
428
|
+
IF NOT FOUND OR session_row.status = 'cancelled' THEN
|
|
429
|
+
authorization_status := 'denied'; denial_reason := 'session_inactive';
|
|
430
|
+
RETURN NEXT; RETURN;
|
|
431
|
+
END IF;
|
|
432
|
+
IF session_row.visibility IS DISTINCT FROM p_snapshot ->> 'targetSessionVisibility' THEN
|
|
433
|
+
authorization_status := 'denied'; denial_reason := 'session_visibility_changed';
|
|
434
|
+
RETURN NEXT; RETURN;
|
|
435
|
+
END IF;
|
|
436
|
+
IF session_row.authority_epoch IS DISTINCT FROM (
|
|
437
|
+
p_snapshot ->> 'targetSessionAuthorityEpoch'
|
|
438
|
+
)::integer THEN
|
|
439
|
+
authorization_status := 'denied'; denial_reason := 'session_authority_epoch_changed';
|
|
440
|
+
RETURN NEXT; RETURN;
|
|
441
|
+
END IF;
|
|
442
|
+
IF accepted_kind = 'turn' AND NOT EXISTS (
|
|
443
|
+
SELECT 1 FROM session_turns turn_value
|
|
444
|
+
WHERE turn_value.id = accepted_id
|
|
445
|
+
AND turn_value.account_id = p_account_id
|
|
446
|
+
AND turn_value.workspace_id = p_workspace_id
|
|
447
|
+
AND turn_value.session_id = p_session_id
|
|
448
|
+
AND turn_value.status <> 'cancelled'
|
|
449
|
+
) THEN
|
|
450
|
+
authorization_status := 'denied'; denial_reason := 'session_identity_changed';
|
|
451
|
+
RETURN NEXT; RETURN;
|
|
452
|
+
ELSIF accepted_kind = 'scheduled_task' AND NOT EXISTS (
|
|
453
|
+
SELECT 1 FROM scheduled_tasks task
|
|
454
|
+
WHERE task.id = accepted_id
|
|
455
|
+
AND task.account_id = p_account_id
|
|
456
|
+
AND task.workspace_id = p_workspace_id
|
|
457
|
+
AND task.authority_revision = (
|
|
458
|
+
p_snapshot #>> '{acceptedWork,taskAuthorityRevision}'
|
|
459
|
+
)::bigint
|
|
460
|
+
AND task.status = 'active'
|
|
461
|
+
) THEN
|
|
462
|
+
authorization_status := 'denied'; denial_reason := 'session_identity_changed';
|
|
463
|
+
RETURN NEXT; RETURN;
|
|
464
|
+
END IF;
|
|
465
|
+
|
|
466
|
+
SELECT connection_value.id, connection_value.account_id,
|
|
467
|
+
connection_value.workspace_id, connection_value.origin_workspace_id,
|
|
468
|
+
connection_value.subject_id, connection_value.provider_domain,
|
|
469
|
+
connection_value.kind, connection_value.status,
|
|
470
|
+
connection_value.authority_scope, connection_value.authority_id,
|
|
471
|
+
connection_value.owner_organization_membership_id,
|
|
472
|
+
connection_value.authority_generation
|
|
473
|
+
INTO connection_row
|
|
474
|
+
FROM connections connection_value
|
|
475
|
+
WHERE connection_value.id = (p_snapshot ->> 'connectionId')::uuid
|
|
476
|
+
AND connection_value.account_id = p_account_id;
|
|
477
|
+
IF NOT FOUND THEN
|
|
478
|
+
authorization_status := 'denied'; denial_reason := 'connection_missing';
|
|
479
|
+
RETURN NEXT; RETURN;
|
|
480
|
+
END IF;
|
|
481
|
+
IF connection_row.origin_workspace_id::text IS DISTINCT FROM
|
|
482
|
+
p_snapshot ->> 'originWorkspaceId'
|
|
483
|
+
OR lower(connection_row.provider_domain) IS DISTINCT FROM lower(
|
|
484
|
+
p_snapshot ->> 'providerDomain'
|
|
485
|
+
)
|
|
486
|
+
OR connection_row.kind IS DISTINCT FROM p_snapshot ->> 'connectionKind'
|
|
487
|
+
OR connection_row.authority_scope IS DISTINCT FROM snapshot_scope
|
|
488
|
+
THEN
|
|
489
|
+
authorization_status := 'denied'; denial_reason := 'connection_identity_changed';
|
|
490
|
+
RETURN NEXT; RETURN;
|
|
491
|
+
END IF;
|
|
492
|
+
IF connection_row.authority_generation IS DISTINCT FROM (
|
|
493
|
+
p_snapshot ->> 'connectionGeneration'
|
|
494
|
+
)::bigint THEN
|
|
495
|
+
authorization_status := 'denied'; denial_reason := 'connection_generation_changed';
|
|
496
|
+
RETURN NEXT; RETURN;
|
|
497
|
+
END IF;
|
|
498
|
+
IF connection_row.status <> 'active' THEN
|
|
499
|
+
authorization_status := 'denied'; denial_reason := 'connection_status_inactive';
|
|
500
|
+
RETURN NEXT; RETURN;
|
|
501
|
+
END IF;
|
|
502
|
+
IF connection_row.subject_id IS DISTINCT FROM snapshot_owner
|
|
503
|
+
OR connection_row.owner_organization_membership_id
|
|
504
|
+
IS DISTINCT FROM snapshot_membership
|
|
505
|
+
THEN
|
|
506
|
+
authorization_status := 'denied'; denial_reason := 'connection_owner_changed';
|
|
507
|
+
RETURN NEXT; RETURN;
|
|
508
|
+
END IF;
|
|
509
|
+
|
|
510
|
+
connection_id := connection_row.id;
|
|
511
|
+
connection_generation := connection_row.authority_generation;
|
|
512
|
+
authority_scope := snapshot_scope;
|
|
513
|
+
owner_subject_id := snapshot_owner;
|
|
514
|
+
authority_id := snapshot_authority;
|
|
515
|
+
grant_id := snapshot_grant;
|
|
516
|
+
|
|
517
|
+
IF snapshot_scope = 'workspace' THEN
|
|
518
|
+
IF connection_row.workspace_id <> p_workspace_id
|
|
519
|
+
OR connection_row.origin_workspace_id <> p_workspace_id
|
|
520
|
+
OR connection_row.subject_id IS NOT NULL
|
|
521
|
+
OR snapshot_authority IS NOT NULL
|
|
522
|
+
OR snapshot_grant IS NOT NULL
|
|
523
|
+
THEN
|
|
524
|
+
authorization_status := 'denied'; denial_reason := 'connection_owner_changed';
|
|
525
|
+
RETURN NEXT; RETURN;
|
|
526
|
+
END IF;
|
|
527
|
+
authorization_status := 'authorized'; denial_reason := NULL;
|
|
528
|
+
RETURN NEXT; RETURN;
|
|
529
|
+
END IF;
|
|
530
|
+
|
|
531
|
+
SELECT membership.id, membership.account_id, membership.subject_id,
|
|
532
|
+
membership.status, membership.revoked_at
|
|
533
|
+
INTO membership_row
|
|
534
|
+
FROM organization_memberships membership
|
|
535
|
+
WHERE membership.id = snapshot_membership
|
|
536
|
+
AND membership.account_id = p_account_id
|
|
537
|
+
AND membership.subject_id = snapshot_owner;
|
|
538
|
+
IF NOT FOUND OR membership_row.status <> 'active' OR membership_row.revoked_at IS NOT NULL
|
|
539
|
+
OR NOT EXISTS (
|
|
540
|
+
SELECT 1 FROM organization_memberships membership
|
|
541
|
+
WHERE membership.id = snapshot_membership
|
|
542
|
+
AND (
|
|
543
|
+
membership.personal_workspace_id = p_workspace_id
|
|
544
|
+
OR EXISTS (
|
|
545
|
+
SELECT 1 FROM workspace_memberships workspace_membership
|
|
546
|
+
WHERE workspace_membership.account_id = p_account_id
|
|
547
|
+
AND workspace_membership.workspace_id = p_workspace_id
|
|
548
|
+
AND workspace_membership.subject_id = snapshot_owner
|
|
549
|
+
)
|
|
550
|
+
)
|
|
551
|
+
)
|
|
552
|
+
THEN
|
|
553
|
+
authorization_status := 'denied'; denial_reason := 'owner_membership_inactive';
|
|
554
|
+
RETURN NEXT; RETURN;
|
|
555
|
+
END IF;
|
|
556
|
+
|
|
557
|
+
SELECT authority.id, authority.account_id, authority.organization_membership_id,
|
|
558
|
+
authority.resource_kind, authority.resource_id, authority.origin_workspace_id,
|
|
559
|
+
authority.generation, authority.status, authority.revoked_at
|
|
560
|
+
INTO authority_row
|
|
561
|
+
FROM organization_user_resource_authorities authority
|
|
562
|
+
WHERE authority.id = snapshot_authority
|
|
563
|
+
AND authority.account_id = p_account_id;
|
|
564
|
+
IF NOT FOUND THEN
|
|
565
|
+
authorization_status := 'denied'; denial_reason := 'authority_missing';
|
|
566
|
+
RETURN NEXT; RETURN;
|
|
567
|
+
END IF;
|
|
568
|
+
IF authority_row.organization_membership_id <> snapshot_membership
|
|
569
|
+
OR authority_row.resource_kind <> 'connection'
|
|
570
|
+
OR authority_row.resource_id <> connection_row.id
|
|
571
|
+
OR authority_row.origin_workspace_id <> connection_row.origin_workspace_id
|
|
572
|
+
THEN
|
|
573
|
+
authorization_status := 'denied'; denial_reason := 'authority_identity_changed';
|
|
574
|
+
RETURN NEXT; RETURN;
|
|
575
|
+
END IF;
|
|
576
|
+
IF authority_row.generation IS DISTINCT FROM (
|
|
577
|
+
p_snapshot #>> '{userDelegation,authorityGeneration}'
|
|
578
|
+
)::bigint THEN
|
|
579
|
+
authorization_status := 'denied'; denial_reason := 'authority_generation_changed';
|
|
580
|
+
RETURN NEXT; RETURN;
|
|
581
|
+
END IF;
|
|
582
|
+
IF authority_row.status <> 'active' OR authority_row.revoked_at IS NOT NULL THEN
|
|
583
|
+
authorization_status := 'denied'; denial_reason := 'authority_status_inactive';
|
|
584
|
+
RETURN NEXT; RETURN;
|
|
585
|
+
END IF;
|
|
586
|
+
|
|
587
|
+
SELECT grant_value.id, grant_value.account_id, grant_value.authority_id,
|
|
588
|
+
grant_value.owner_organization_membership_id, grant_value.workspace_id,
|
|
589
|
+
grant_value.session_id, grant_value.action, grant_value.mode,
|
|
590
|
+
grant_value.context, grant_value.authority_epoch, grant_value.generation,
|
|
591
|
+
grant_value.status, grant_value.expires_at
|
|
592
|
+
INTO grant_row
|
|
593
|
+
FROM organization_user_resource_grants grant_value
|
|
594
|
+
WHERE grant_value.id = snapshot_grant
|
|
595
|
+
AND grant_value.account_id = p_account_id
|
|
596
|
+
FOR UPDATE;
|
|
597
|
+
IF NOT FOUND THEN
|
|
598
|
+
authorization_status := 'denied'; denial_reason := 'grant_missing';
|
|
599
|
+
RETURN NEXT; RETURN;
|
|
600
|
+
END IF;
|
|
601
|
+
IF grant_row.authority_id <> snapshot_authority
|
|
602
|
+
OR grant_row.owner_organization_membership_id <> snapshot_membership
|
|
603
|
+
OR grant_row.workspace_id <> p_workspace_id
|
|
604
|
+
OR grant_row.action <> 'connection.use'
|
|
605
|
+
OR grant_row.mode IS DISTINCT FROM p_snapshot #>> '{userDelegation,mode}'
|
|
606
|
+
OR grant_row.context IS DISTINCT FROM p_snapshot ->> 'targetSessionVisibility'
|
|
607
|
+
OR grant_row.session_id IS DISTINCT FROM nullif(
|
|
608
|
+
p_snapshot #>> '{userDelegation,sessionId}', ''
|
|
609
|
+
)::uuid
|
|
610
|
+
OR grant_row.authority_epoch IS DISTINCT FROM nullif(
|
|
611
|
+
p_snapshot #>> '{userDelegation,authorityEpoch}', ''
|
|
612
|
+
)::integer
|
|
613
|
+
THEN
|
|
614
|
+
authorization_status := 'denied'; denial_reason := 'grant_identity_changed';
|
|
615
|
+
RETURN NEXT; RETURN;
|
|
616
|
+
END IF;
|
|
617
|
+
IF grant_row.generation IS DISTINCT FROM (
|
|
618
|
+
p_snapshot #>> '{userDelegation,grantGeneration}'
|
|
619
|
+
)::bigint THEN
|
|
620
|
+
authorization_status := 'denied'; denial_reason := 'grant_generation_changed';
|
|
621
|
+
RETURN NEXT; RETURN;
|
|
622
|
+
END IF;
|
|
623
|
+
IF grant_row.expires_at IS NOT NULL AND grant_row.expires_at <= clock_timestamp() THEN
|
|
624
|
+
authorization_status := 'denied'; denial_reason := 'grant_expired';
|
|
625
|
+
RETURN NEXT; RETURN;
|
|
626
|
+
END IF;
|
|
627
|
+
|
|
628
|
+
IF grant_row.mode = 'once' THEN
|
|
629
|
+
SELECT receipt.accepted_work_kind, receipt.accepted_work_id
|
|
630
|
+
INTO receipt_row
|
|
631
|
+
FROM connection_use_once_consumption_receipts receipt
|
|
632
|
+
WHERE receipt.grant_id = grant_row.id;
|
|
633
|
+
IF FOUND THEN
|
|
634
|
+
IF receipt_row.accepted_work_kind IS DISTINCT FROM accepted_kind
|
|
635
|
+
OR receipt_row.accepted_work_id IS DISTINCT FROM accepted_id
|
|
636
|
+
THEN
|
|
637
|
+
authorization_status := 'denied'; denial_reason := 'grant_already_consumed';
|
|
638
|
+
RETURN NEXT; RETURN;
|
|
639
|
+
END IF;
|
|
640
|
+
ELSIF grant_row.status = 'active' THEN
|
|
641
|
+
UPDATE organization_user_resource_grants
|
|
642
|
+
SET status = 'consumed', updated_at = clock_timestamp()
|
|
643
|
+
WHERE id = grant_row.id AND account_id = p_account_id
|
|
644
|
+
AND generation = grant_row.generation AND status = 'active';
|
|
645
|
+
IF NOT FOUND THEN
|
|
646
|
+
authorization_status := 'denied'; denial_reason := 'grant_already_consumed';
|
|
647
|
+
RETURN NEXT; RETURN;
|
|
648
|
+
END IF;
|
|
649
|
+
INSERT INTO connection_use_once_consumption_receipts (
|
|
650
|
+
grant_id, account_id, authority_id, authority_generation,
|
|
651
|
+
grant_generation, accepted_work_kind, accepted_work_id
|
|
652
|
+
) VALUES (
|
|
653
|
+
grant_row.id, p_account_id, snapshot_authority, authority_row.generation,
|
|
654
|
+
grant_row.generation, accepted_kind, accepted_id
|
|
655
|
+
);
|
|
656
|
+
ELSE
|
|
657
|
+
authorization_status := 'denied'; denial_reason := 'grant_status_inactive';
|
|
658
|
+
RETURN NEXT; RETURN;
|
|
659
|
+
END IF;
|
|
660
|
+
ELSIF grant_row.status <> 'active' THEN
|
|
661
|
+
authorization_status := 'denied'; denial_reason := 'grant_status_inactive';
|
|
662
|
+
RETURN NEXT; RETURN;
|
|
663
|
+
END IF;
|
|
664
|
+
|
|
665
|
+
authorization_status := 'authorized'; denial_reason := NULL;
|
|
666
|
+
RETURN NEXT;
|
|
667
|
+
END
|
|
668
|
+
$body$
|
|
669
|
+
$ddl$, data_schema);
|
|
670
|
+
END
|
|
671
|
+
$connection_authority_routines$;
|
|
672
|
+
|
|
673
|
+
REVOKE ALL ON FUNCTION opengeni_private.bind_connection_authority() FROM PUBLIC;
|
|
674
|
+
REVOKE ALL ON FUNCTION opengeni_private.validate_user_resource_grant_action() FROM PUBLIC;
|
|
675
|
+
REVOKE ALL ON FUNCTION list_self_connection_authorities(uuid) FROM PUBLIC;
|
|
676
|
+
REVOKE ALL ON FUNCTION issue_self_connection_use_grant(
|
|
677
|
+
uuid, uuid, uuid, text, text, uuid, boolean
|
|
678
|
+
) FROM PUBLIC;
|
|
679
|
+
REVOKE ALL ON FUNCTION revoke_self_connection_use_grant(uuid, uuid) FROM PUBLIC;
|
|
680
|
+
REVOKE ALL ON FUNCTION resolve_connection_use_authority(uuid, uuid, uuid, jsonb) FROM PUBLIC;
|
|
681
|
+
|
|
682
|
+
DO $grants$
|
|
683
|
+
BEGIN
|
|
684
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
685
|
+
GRANT EXECUTE ON FUNCTION list_self_connection_authorities(uuid) TO opengeni_app;
|
|
686
|
+
GRANT EXECUTE ON FUNCTION issue_self_connection_use_grant(
|
|
687
|
+
uuid, uuid, uuid, text, text, uuid, boolean
|
|
688
|
+
) TO opengeni_app;
|
|
689
|
+
GRANT EXECUTE ON FUNCTION revoke_self_connection_use_grant(uuid, uuid) TO opengeni_app;
|
|
690
|
+
GRANT EXECUTE ON FUNCTION resolve_connection_use_authority(
|
|
691
|
+
uuid, uuid, uuid, jsonb
|
|
692
|
+
) TO opengeni_app;
|
|
693
|
+
REVOKE ALL ON TABLE connection_use_once_consumption_receipts FROM opengeni_app;
|
|
694
|
+
REVOKE ALL ON TABLE organization_user_resource_authorities FROM opengeni_app;
|
|
695
|
+
REVOKE ALL ON TABLE organization_user_resource_grants FROM opengeni_app;
|
|
696
|
+
END IF;
|
|
697
|
+
END
|
|
698
|
+
$grants$;
|
|
699
|
+
|
|
700
|
+
COMMENT ON COLUMN "connections"."authority_generation" IS
|
|
701
|
+
'Monotonic execution-authority generation. Token refresh does not advance it; reconnect, disconnect, provider/kind, and status transitions do.';
|
|
702
|
+
COMMENT ON TABLE "connection_use_once_consumption_receipts" IS
|
|
703
|
+
'Exact accepted turn/task that consumed one connection.use grant; contains no credential, quota, provider response, or usage value.';
|