@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,624 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Personal GitHub repository discovery is live. Persist only the owner's
|
|
3
|
+
-- explicit selected set and monotonic authority facts. Runtime Git and GitHub
|
|
4
|
+
-- API execution remain disabled until their separately reviewed consumers land.
|
|
5
|
+
|
|
6
|
+
SET LOCAL lock_timeout = '5s';
|
|
7
|
+
SET LOCAL statement_timeout = '10min';
|
|
8
|
+
|
|
9
|
+
CREATE TABLE personal_github_repository_selection_heads (
|
|
10
|
+
connection_id uuid PRIMARY KEY REFERENCES connections(id) ON DELETE CASCADE,
|
|
11
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
12
|
+
origin_workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
13
|
+
owner_subject_id text NOT NULL,
|
|
14
|
+
provider_principal_id text NOT NULL,
|
|
15
|
+
credential_binding_id uuid NOT NULL,
|
|
16
|
+
connection_authority_generation bigint NOT NULL,
|
|
17
|
+
generation bigint NOT NULL,
|
|
18
|
+
updated_by_subject_id text NOT NULL,
|
|
19
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
20
|
+
updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
21
|
+
CONSTRAINT personal_github_repository_selection_heads_tenant_uq
|
|
22
|
+
UNIQUE (account_id, origin_workspace_id, owner_subject_id, connection_id),
|
|
23
|
+
CONSTRAINT personal_github_repository_selection_heads_generation_chk CHECK (
|
|
24
|
+
connection_authority_generation > 0 AND generation > 0
|
|
25
|
+
AND octet_length(owner_subject_id) BETWEEN 1 AND 512
|
|
26
|
+
AND provider_principal_id ~ '^[1-9][0-9]*$'
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
CREATE INDEX personal_github_repository_selection_heads_owner_idx
|
|
30
|
+
ON personal_github_repository_selection_heads(account_id, owner_subject_id, connection_id);
|
|
31
|
+
|
|
32
|
+
CREATE TABLE personal_github_repository_selections (
|
|
33
|
+
connection_id uuid NOT NULL,
|
|
34
|
+
repository_id bigint NOT NULL,
|
|
35
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
36
|
+
origin_workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
37
|
+
owner_subject_id text NOT NULL,
|
|
38
|
+
canonical_full_name text NOT NULL,
|
|
39
|
+
canonical_https_uri text NOT NULL,
|
|
40
|
+
default_branch text NOT NULL,
|
|
41
|
+
visibility text NOT NULL,
|
|
42
|
+
private boolean NOT NULL,
|
|
43
|
+
archived boolean NOT NULL,
|
|
44
|
+
disabled boolean NOT NULL,
|
|
45
|
+
permissions jsonb NOT NULL,
|
|
46
|
+
selected_access text NOT NULL,
|
|
47
|
+
selection_generation bigint NOT NULL,
|
|
48
|
+
selected_by_subject_id text NOT NULL,
|
|
49
|
+
selected_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
50
|
+
verified_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
51
|
+
updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
52
|
+
PRIMARY KEY (connection_id, repository_id),
|
|
53
|
+
CONSTRAINT personal_github_repository_selections_head_fk FOREIGN KEY (
|
|
54
|
+
account_id, origin_workspace_id, owner_subject_id, connection_id
|
|
55
|
+
) REFERENCES personal_github_repository_selection_heads (
|
|
56
|
+
account_id, origin_workspace_id, owner_subject_id, connection_id
|
|
57
|
+
) ON DELETE CASCADE,
|
|
58
|
+
CONSTRAINT personal_github_repository_selections_shape_chk CHECK (
|
|
59
|
+
repository_id > 0 AND selection_generation > 0
|
|
60
|
+
AND selected_access IN ('read', 'write')
|
|
61
|
+
AND visibility IN ('public', 'private', 'internal')
|
|
62
|
+
AND private = (visibility = 'private')
|
|
63
|
+
AND octet_length(owner_subject_id) BETWEEN 1 AND 512
|
|
64
|
+
AND canonical_full_name ~ '^[A-Za-z0-9][A-Za-z0-9-]{0,38}/[A-Za-z0-9_.-]{1,100}$'
|
|
65
|
+
AND octet_length(canonical_full_name) BETWEEN 3 AND 140
|
|
66
|
+
AND octet_length(default_branch) BETWEEN 1 AND 255
|
|
67
|
+
AND canonical_https_uri = 'https://github.com/' || canonical_full_name
|
|
68
|
+
AND jsonb_typeof(permissions) = 'object'
|
|
69
|
+
AND permissions ?& ARRAY['pull','push','admin','maintain','triage']
|
|
70
|
+
AND permissions - ARRAY['pull','push','admin','maintain','triage']::text[] = '{}'::jsonb
|
|
71
|
+
AND jsonb_typeof(permissions -> 'pull') = 'boolean'
|
|
72
|
+
AND jsonb_typeof(permissions -> 'push') = 'boolean'
|
|
73
|
+
AND jsonb_typeof(permissions -> 'admin') = 'boolean'
|
|
74
|
+
AND jsonb_typeof(permissions -> 'maintain') = 'boolean'
|
|
75
|
+
AND jsonb_typeof(permissions -> 'triage') = 'boolean'
|
|
76
|
+
AND (
|
|
77
|
+
permissions -> 'pull' = 'true'::jsonb
|
|
78
|
+
OR permissions -> 'push' = 'true'::jsonb
|
|
79
|
+
OR permissions -> 'admin' = 'true'::jsonb
|
|
80
|
+
OR permissions -> 'maintain' = 'true'::jsonb
|
|
81
|
+
OR permissions -> 'triage' = 'true'::jsonb
|
|
82
|
+
)
|
|
83
|
+
AND (selected_access <> 'write' OR (
|
|
84
|
+
NOT archived AND NOT disabled
|
|
85
|
+
AND (
|
|
86
|
+
permissions -> 'push' = 'true'::jsonb
|
|
87
|
+
OR permissions -> 'admin' = 'true'::jsonb
|
|
88
|
+
OR permissions -> 'maintain' = 'true'::jsonb
|
|
89
|
+
)
|
|
90
|
+
))
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
CREATE INDEX personal_github_repository_selections_tenant_idx
|
|
94
|
+
ON personal_github_repository_selections(account_id, origin_workspace_id, connection_id);
|
|
95
|
+
|
|
96
|
+
CREATE TABLE personal_github_repository_selection_operations (
|
|
97
|
+
connection_id uuid NOT NULL,
|
|
98
|
+
idempotency_key text NOT NULL,
|
|
99
|
+
account_id uuid NOT NULL,
|
|
100
|
+
origin_workspace_id uuid NOT NULL,
|
|
101
|
+
owner_subject_id text NOT NULL,
|
|
102
|
+
request_digest bytea NOT NULL,
|
|
103
|
+
resulting_generation bigint NOT NULL,
|
|
104
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
105
|
+
PRIMARY KEY (connection_id, idempotency_key),
|
|
106
|
+
CONSTRAINT personal_github_repository_selection_operations_head_fk FOREIGN KEY (
|
|
107
|
+
account_id, origin_workspace_id, owner_subject_id, connection_id
|
|
108
|
+
) REFERENCES personal_github_repository_selection_heads (
|
|
109
|
+
account_id, origin_workspace_id, owner_subject_id, connection_id
|
|
110
|
+
) ON DELETE CASCADE,
|
|
111
|
+
CONSTRAINT personal_github_repository_selection_operations_shape_chk CHECK (
|
|
112
|
+
resulting_generation > 0
|
|
113
|
+
AND octet_length(idempotency_key) BETWEEN 1 AND 200
|
|
114
|
+
AND octet_length(owner_subject_id) BETWEEN 1 AND 512
|
|
115
|
+
AND octet_length(request_digest) = 32
|
|
116
|
+
)
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
ALTER TABLE personal_github_repository_selection_heads ENABLE ROW LEVEL SECURITY;
|
|
120
|
+
ALTER TABLE personal_github_repository_selection_heads FORCE ROW LEVEL SECURITY;
|
|
121
|
+
ALTER TABLE personal_github_repository_selections ENABLE ROW LEVEL SECURITY;
|
|
122
|
+
ALTER TABLE personal_github_repository_selections FORCE ROW LEVEL SECURITY;
|
|
123
|
+
ALTER TABLE personal_github_repository_selection_operations ENABLE ROW LEVEL SECURITY;
|
|
124
|
+
ALTER TABLE personal_github_repository_selection_operations FORCE ROW LEVEL SECURITY;
|
|
125
|
+
|
|
126
|
+
CREATE POLICY personal_github_repository_selection_heads_owner_isolation
|
|
127
|
+
ON personal_github_repository_selection_heads
|
|
128
|
+
USING (
|
|
129
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
130
|
+
AND origin_workspace_id = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
131
|
+
AND owner_subject_id = nullif(current_setting('opengeni.subject_id', true), '')
|
|
132
|
+
) WITH CHECK (
|
|
133
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
134
|
+
AND origin_workspace_id = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
135
|
+
AND owner_subject_id = nullif(current_setting('opengeni.subject_id', true), '')
|
|
136
|
+
);
|
|
137
|
+
CREATE POLICY personal_github_repository_selections_owner_isolation
|
|
138
|
+
ON personal_github_repository_selections
|
|
139
|
+
USING (
|
|
140
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
141
|
+
AND origin_workspace_id = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
142
|
+
AND owner_subject_id = nullif(current_setting('opengeni.subject_id', true), '')
|
|
143
|
+
) WITH CHECK (
|
|
144
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
145
|
+
AND origin_workspace_id = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
146
|
+
AND owner_subject_id = nullif(current_setting('opengeni.subject_id', true), '')
|
|
147
|
+
);
|
|
148
|
+
CREATE POLICY personal_github_repository_selection_operations_owner_isolation
|
|
149
|
+
ON personal_github_repository_selection_operations
|
|
150
|
+
USING (
|
|
151
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
152
|
+
AND origin_workspace_id = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
153
|
+
AND owner_subject_id = nullif(current_setting('opengeni.subject_id', true), '')
|
|
154
|
+
) WITH CHECK (
|
|
155
|
+
account_id = nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
156
|
+
AND origin_workspace_id = nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
157
|
+
AND owner_subject_id = nullif(current_setting('opengeni.subject_id', true), '')
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
DO $personal_github_repository_functions$
|
|
161
|
+
DECLARE
|
|
162
|
+
data_schema text := current_schema();
|
|
163
|
+
BEGIN
|
|
164
|
+
EXECUTE format($ddl$
|
|
165
|
+
CREATE FUNCTION %1$I.get_self_personal_github_repository_selection(
|
|
166
|
+
p_account_id uuid,
|
|
167
|
+
p_origin_workspace_id uuid,
|
|
168
|
+
p_owner_subject_id text,
|
|
169
|
+
p_connection_id uuid
|
|
170
|
+
) RETURNS jsonb
|
|
171
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
172
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
173
|
+
AS $body$
|
|
174
|
+
DECLARE
|
|
175
|
+
connection_row connections%%ROWTYPE;
|
|
176
|
+
head_row personal_github_repository_selection_heads%%ROWTYPE;
|
|
177
|
+
selected_rows jsonb;
|
|
178
|
+
BEGIN
|
|
179
|
+
IF p_account_id IS DISTINCT FROM
|
|
180
|
+
nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
181
|
+
OR p_origin_workspace_id IS DISTINCT FROM
|
|
182
|
+
nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
183
|
+
OR p_owner_subject_id IS DISTINCT FROM
|
|
184
|
+
nullif(current_setting('opengeni.subject_id', true), '')
|
|
185
|
+
THEN
|
|
186
|
+
RETURN NULL;
|
|
187
|
+
END IF;
|
|
188
|
+
SELECT connection_value.* INTO connection_row
|
|
189
|
+
FROM connections connection_value
|
|
190
|
+
WHERE connection_value.id = p_connection_id
|
|
191
|
+
AND connection_value.account_id = p_account_id
|
|
192
|
+
AND connection_value.origin_workspace_id = p_origin_workspace_id
|
|
193
|
+
AND connection_value.workspace_id = p_origin_workspace_id
|
|
194
|
+
AND connection_value.subject_id = p_owner_subject_id
|
|
195
|
+
AND connection_value.status = 'active'
|
|
196
|
+
AND connection_value.authority_scope = 'user'
|
|
197
|
+
AND connection_value.provider_domain = 'github.com'
|
|
198
|
+
AND connection_value.kind = 'oauth2'
|
|
199
|
+
AND connection_value.granted_scopes = '["repo"]'::jsonb
|
|
200
|
+
AND connection_value.metadata ->> 'credentialRole' = 'opengeni_github_personal'
|
|
201
|
+
AND connection_value.metadata ->> 'providerFamily' = 'github'
|
|
202
|
+
AND connection_value.metadata ->> 'providerPrincipalId' ~ '^[1-9][0-9]*$'
|
|
203
|
+
AND connection_value.metadata ->> 'credentialBindingId'
|
|
204
|
+
~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$';
|
|
205
|
+
IF NOT FOUND THEN RETURN NULL; END IF;
|
|
206
|
+
SELECT head.* INTO head_row
|
|
207
|
+
FROM personal_github_repository_selection_heads head
|
|
208
|
+
WHERE head.connection_id = p_connection_id
|
|
209
|
+
AND head.account_id = p_account_id
|
|
210
|
+
AND head.origin_workspace_id = p_origin_workspace_id
|
|
211
|
+
AND head.owner_subject_id = p_owner_subject_id;
|
|
212
|
+
IF NOT FOUND THEN
|
|
213
|
+
RETURN jsonb_build_object(
|
|
214
|
+
'connectionAuthorityGeneration', connection_row.authority_generation,
|
|
215
|
+
'credentialBindingId', connection_row.metadata ->> 'credentialBindingId',
|
|
216
|
+
'providerPrincipalId', connection_row.metadata ->> 'providerPrincipalId',
|
|
217
|
+
'selectionGeneration', 0,
|
|
218
|
+
'repositories', '[]'::jsonb
|
|
219
|
+
);
|
|
220
|
+
END IF;
|
|
221
|
+
SELECT coalesce(jsonb_agg(jsonb_build_object(
|
|
222
|
+
'repositoryId', selected.repository_id::text,
|
|
223
|
+
'fullName', selected.canonical_full_name,
|
|
224
|
+
'canonicalUrl', selected.canonical_https_uri,
|
|
225
|
+
'defaultBranch', selected.default_branch,
|
|
226
|
+
'visibility', selected.visibility,
|
|
227
|
+
'private', selected.private,
|
|
228
|
+
'archived', selected.archived,
|
|
229
|
+
'disabled', selected.disabled,
|
|
230
|
+
'permissions', selected.permissions,
|
|
231
|
+
'selectedAccess', selected.selected_access,
|
|
232
|
+
'selectionGeneration', selected.selection_generation,
|
|
233
|
+
'selectedAt', selected.selected_at,
|
|
234
|
+
'lastVerifiedAt', selected.verified_at
|
|
235
|
+
) ORDER BY selected.canonical_full_name, selected.repository_id), '[]'::jsonb)
|
|
236
|
+
INTO selected_rows
|
|
237
|
+
FROM personal_github_repository_selections selected
|
|
238
|
+
WHERE selected.connection_id = p_connection_id
|
|
239
|
+
AND selected.account_id = p_account_id
|
|
240
|
+
AND selected.origin_workspace_id = p_origin_workspace_id
|
|
241
|
+
AND selected.owner_subject_id = p_owner_subject_id;
|
|
242
|
+
RETURN jsonb_build_object(
|
|
243
|
+
'connectionAuthorityGeneration', connection_row.authority_generation,
|
|
244
|
+
'credentialBindingId', head_row.credential_binding_id,
|
|
245
|
+
'providerPrincipalId', head_row.provider_principal_id,
|
|
246
|
+
'selectionGeneration', head_row.generation,
|
|
247
|
+
'repositories', selected_rows
|
|
248
|
+
);
|
|
249
|
+
END
|
|
250
|
+
$body$
|
|
251
|
+
$ddl$, data_schema);
|
|
252
|
+
|
|
253
|
+
EXECUTE format($ddl$
|
|
254
|
+
CREATE FUNCTION %1$I.mutate_self_personal_github_repository_selection(
|
|
255
|
+
p_account_id uuid,
|
|
256
|
+
p_origin_workspace_id uuid,
|
|
257
|
+
p_owner_subject_id text,
|
|
258
|
+
p_connection_id uuid,
|
|
259
|
+
p_expected_connection_authority_generation bigint,
|
|
260
|
+
p_expected_selection_generation bigint,
|
|
261
|
+
p_idempotency_key text,
|
|
262
|
+
p_repositories jsonb,
|
|
263
|
+
p_verify_only boolean DEFAULT false
|
|
264
|
+
) RETURNS jsonb
|
|
265
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
266
|
+
SET search_path = %1$I, pg_catalog, pg_temp
|
|
267
|
+
AS $body$
|
|
268
|
+
DECLARE
|
|
269
|
+
connection_row connections%%ROWTYPE;
|
|
270
|
+
head_row personal_github_repository_selection_heads%%ROWTYPE;
|
|
271
|
+
receipt_row personal_github_repository_selection_operations%%ROWTYPE;
|
|
272
|
+
item jsonb;
|
|
273
|
+
request_digest bytea;
|
|
274
|
+
current_generation bigint;
|
|
275
|
+
next_generation bigint;
|
|
276
|
+
authority_changed boolean;
|
|
277
|
+
BEGIN
|
|
278
|
+
IF p_account_id IS DISTINCT FROM
|
|
279
|
+
nullif(current_setting('opengeni.account_id', true), '')::uuid
|
|
280
|
+
OR p_origin_workspace_id IS DISTINCT FROM
|
|
281
|
+
nullif(current_setting('opengeni.workspace_id', true), '')::uuid
|
|
282
|
+
OR p_owner_subject_id IS DISTINCT FROM
|
|
283
|
+
nullif(current_setting('opengeni.subject_id', true), '')
|
|
284
|
+
THEN RAISE EXCEPTION 'personal GitHub repository selection is unavailable'
|
|
285
|
+
USING ERRCODE = '42501';
|
|
286
|
+
END IF;
|
|
287
|
+
IF p_expected_connection_authority_generation <= 0
|
|
288
|
+
OR p_expected_selection_generation < 0
|
|
289
|
+
OR octet_length(p_idempotency_key) NOT BETWEEN 1 AND 200
|
|
290
|
+
OR jsonb_typeof(p_repositories) <> 'array'
|
|
291
|
+
OR jsonb_array_length(p_repositories) > 100
|
|
292
|
+
THEN RAISE EXCEPTION 'invalid personal GitHub repository selection'
|
|
293
|
+
USING ERRCODE = '22023';
|
|
294
|
+
END IF;
|
|
295
|
+
IF EXISTS (
|
|
296
|
+
SELECT 1 FROM jsonb_array_elements(p_repositories) selected(value)
|
|
297
|
+
WHERE jsonb_typeof(value) <> 'object'
|
|
298
|
+
OR value - ARRAY[
|
|
299
|
+
'repositoryId','fullName','canonicalUrl','defaultBranch','visibility',
|
|
300
|
+
'private','archived','disabled','permissions','selectedAccess','lastVerifiedAt'
|
|
301
|
+
]::text[] <> '{}'::jsonb
|
|
302
|
+
OR NOT (value ?& ARRAY[
|
|
303
|
+
'repositoryId','fullName','canonicalUrl','defaultBranch','visibility',
|
|
304
|
+
'private','archived','disabled','permissions','selectedAccess','lastVerifiedAt'
|
|
305
|
+
])
|
|
306
|
+
OR value ->> 'repositoryId' !~ '^[0-9]+$'
|
|
307
|
+
OR (value ->> 'repositoryId')::numeric <= 0
|
|
308
|
+
OR value ->> 'fullName'
|
|
309
|
+
!~ '^[A-Za-z0-9][A-Za-z0-9-]{0,38}/[A-Za-z0-9_.-]{1,100}$'
|
|
310
|
+
OR value ->> 'canonicalUrl' IS DISTINCT FROM
|
|
311
|
+
'https://github.com/' || (value ->> 'fullName')
|
|
312
|
+
OR octet_length(value ->> 'defaultBranch') NOT BETWEEN 1 AND 255
|
|
313
|
+
OR value ->> 'visibility' NOT IN ('public','private','internal')
|
|
314
|
+
OR jsonb_typeof(value -> 'private') <> 'boolean'
|
|
315
|
+
OR jsonb_typeof(value -> 'archived') <> 'boolean'
|
|
316
|
+
OR jsonb_typeof(value -> 'disabled') <> 'boolean'
|
|
317
|
+
OR value -> 'private' IS DISTINCT FROM
|
|
318
|
+
to_jsonb((value ->> 'visibility') = 'private')
|
|
319
|
+
OR value ->> 'selectedAccess' NOT IN ('read','write')
|
|
320
|
+
OR jsonb_typeof(value -> 'permissions') <> 'object'
|
|
321
|
+
OR NOT (value -> 'permissions' ?& ARRAY['pull','push','admin','maintain','triage'])
|
|
322
|
+
OR EXISTS (
|
|
323
|
+
SELECT 1 FROM jsonb_each(value -> 'permissions') permission(key, permission_value)
|
|
324
|
+
WHERE key NOT IN ('pull','push','admin','maintain','triage')
|
|
325
|
+
OR jsonb_typeof(permission_value) <> 'boolean'
|
|
326
|
+
)
|
|
327
|
+
OR NOT (
|
|
328
|
+
value -> 'permissions' -> 'pull' = 'true'::jsonb
|
|
329
|
+
OR value -> 'permissions' -> 'push' = 'true'::jsonb
|
|
330
|
+
OR value -> 'permissions' -> 'admin' = 'true'::jsonb
|
|
331
|
+
OR value -> 'permissions' -> 'maintain' = 'true'::jsonb
|
|
332
|
+
OR value -> 'permissions' -> 'triage' = 'true'::jsonb
|
|
333
|
+
)
|
|
334
|
+
OR (
|
|
335
|
+
value ->> 'selectedAccess' = 'write'
|
|
336
|
+
AND (
|
|
337
|
+
value -> 'archived' = 'true'::jsonb
|
|
338
|
+
OR value -> 'disabled' = 'true'::jsonb
|
|
339
|
+
OR NOT (
|
|
340
|
+
value -> 'permissions' -> 'push' = 'true'::jsonb
|
|
341
|
+
OR value -> 'permissions' -> 'admin' = 'true'::jsonb
|
|
342
|
+
OR value -> 'permissions' -> 'maintain' = 'true'::jsonb
|
|
343
|
+
)
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
OR (value ->> 'lastVerifiedAt')::timestamptz IS NULL
|
|
347
|
+
) OR (
|
|
348
|
+
SELECT count(*) FROM jsonb_array_elements(p_repositories)
|
|
349
|
+
) <> (
|
|
350
|
+
SELECT count(DISTINCT value ->> 'repositoryId')
|
|
351
|
+
FROM jsonb_array_elements(p_repositories) selected(value)
|
|
352
|
+
) OR (
|
|
353
|
+
SELECT count(*) FROM jsonb_array_elements(p_repositories)
|
|
354
|
+
) <> (
|
|
355
|
+
SELECT count(DISTINCT lower(value ->> 'fullName'))
|
|
356
|
+
FROM jsonb_array_elements(p_repositories) selected(value)
|
|
357
|
+
)
|
|
358
|
+
THEN RAISE EXCEPTION 'invalid personal GitHub repository selection'
|
|
359
|
+
USING ERRCODE = '22023';
|
|
360
|
+
END IF;
|
|
361
|
+
|
|
362
|
+
PERFORM pg_advisory_xact_lock(hashtextextended(
|
|
363
|
+
'personal-github-repositories:' || p_connection_id::text, 0
|
|
364
|
+
));
|
|
365
|
+
SELECT connection_value.* INTO connection_row
|
|
366
|
+
FROM connections connection_value
|
|
367
|
+
WHERE connection_value.id = p_connection_id
|
|
368
|
+
AND connection_value.account_id = p_account_id
|
|
369
|
+
AND connection_value.origin_workspace_id = p_origin_workspace_id
|
|
370
|
+
AND connection_value.workspace_id = p_origin_workspace_id
|
|
371
|
+
AND connection_value.subject_id = p_owner_subject_id
|
|
372
|
+
AND connection_value.status = 'active'
|
|
373
|
+
AND connection_value.authority_scope = 'user'
|
|
374
|
+
AND connection_value.provider_domain = 'github.com'
|
|
375
|
+
AND connection_value.kind = 'oauth2'
|
|
376
|
+
AND connection_value.granted_scopes = '["repo"]'::jsonb
|
|
377
|
+
AND connection_value.authority_generation = p_expected_connection_authority_generation
|
|
378
|
+
AND connection_value.metadata ->> 'credentialRole' = 'opengeni_github_personal'
|
|
379
|
+
AND connection_value.metadata ->> 'providerFamily' = 'github'
|
|
380
|
+
AND connection_value.metadata ->> 'providerPrincipalId' ~ '^[1-9][0-9]*$'
|
|
381
|
+
AND connection_value.metadata ->> 'credentialBindingId'
|
|
382
|
+
~* '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
|
383
|
+
FOR SHARE;
|
|
384
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'personal GitHub repository selection is unavailable'
|
|
385
|
+
USING ERRCODE = '42501'; END IF;
|
|
386
|
+
|
|
387
|
+
SELECT head.* INTO head_row
|
|
388
|
+
FROM personal_github_repository_selection_heads head
|
|
389
|
+
WHERE head.connection_id = p_connection_id
|
|
390
|
+
FOR UPDATE;
|
|
391
|
+
current_generation := CASE WHEN FOUND THEN head_row.generation ELSE 0 END;
|
|
392
|
+
request_digest := digest(convert_to(jsonb_build_object(
|
|
393
|
+
'expectedConnectionAuthorityGeneration', p_expected_connection_authority_generation,
|
|
394
|
+
'expectedSelectionGeneration', p_expected_selection_generation,
|
|
395
|
+
'verifyOnly', p_verify_only,
|
|
396
|
+
'repositories', coalesce((
|
|
397
|
+
SELECT jsonb_agg(
|
|
398
|
+
jsonb_build_array(
|
|
399
|
+
value ->> 'repositoryId',
|
|
400
|
+
lower(value ->> 'fullName'),
|
|
401
|
+
value ->> 'selectedAccess'
|
|
402
|
+
) ORDER BY (value ->> 'repositoryId')::numeric
|
|
403
|
+
)
|
|
404
|
+
FROM jsonb_array_elements(p_repositories) incoming(value)
|
|
405
|
+
), '[]'::jsonb)
|
|
406
|
+
)::text, 'UTF8'), 'sha256');
|
|
407
|
+
IF FOUND THEN
|
|
408
|
+
SELECT operation.* INTO receipt_row
|
|
409
|
+
FROM personal_github_repository_selection_operations operation
|
|
410
|
+
WHERE operation.connection_id = p_connection_id
|
|
411
|
+
AND operation.idempotency_key = p_idempotency_key;
|
|
412
|
+
IF FOUND THEN
|
|
413
|
+
IF receipt_row.request_digest IS DISTINCT FROM request_digest THEN
|
|
414
|
+
RAISE EXCEPTION 'personal GitHub repository idempotency key was reused'
|
|
415
|
+
USING ERRCODE = '23505';
|
|
416
|
+
END IF;
|
|
417
|
+
IF current_generation IS DISTINCT FROM receipt_row.resulting_generation THEN
|
|
418
|
+
RAISE EXCEPTION 'personal GitHub repository selection changed'
|
|
419
|
+
USING ERRCODE = '40001';
|
|
420
|
+
END IF;
|
|
421
|
+
RETURN get_self_personal_github_repository_selection(
|
|
422
|
+
p_account_id, p_origin_workspace_id, p_owner_subject_id, p_connection_id
|
|
423
|
+
);
|
|
424
|
+
END IF;
|
|
425
|
+
END IF;
|
|
426
|
+
IF current_generation IS DISTINCT FROM p_expected_selection_generation THEN
|
|
427
|
+
RAISE EXCEPTION 'personal GitHub repository selection changed'
|
|
428
|
+
USING ERRCODE = '40001';
|
|
429
|
+
END IF;
|
|
430
|
+
IF p_verify_only AND current_generation = 0
|
|
431
|
+
AND jsonb_array_length(p_repositories) = 0
|
|
432
|
+
THEN
|
|
433
|
+
RETURN get_self_personal_github_repository_selection(
|
|
434
|
+
p_account_id, p_origin_workspace_id, p_owner_subject_id, p_connection_id
|
|
435
|
+
);
|
|
436
|
+
END IF;
|
|
437
|
+
IF p_verify_only AND (
|
|
438
|
+
(SELECT count(*) FROM personal_github_repository_selections selected
|
|
439
|
+
WHERE selected.connection_id = p_connection_id)
|
|
440
|
+
<> jsonb_array_length(p_repositories)
|
|
441
|
+
OR EXISTS (
|
|
442
|
+
SELECT 1 FROM personal_github_repository_selections selected
|
|
443
|
+
WHERE selected.connection_id = p_connection_id
|
|
444
|
+
AND NOT EXISTS (
|
|
445
|
+
SELECT 1 FROM jsonb_array_elements(p_repositories) incoming(value)
|
|
446
|
+
WHERE incoming.value ->> 'repositoryId' = selected.repository_id::text
|
|
447
|
+
AND incoming.value ->> 'selectedAccess' = selected.selected_access
|
|
448
|
+
)
|
|
449
|
+
)
|
|
450
|
+
) THEN RAISE EXCEPTION 'personal GitHub verify set changed'
|
|
451
|
+
USING ERRCODE = '40001'; END IF;
|
|
452
|
+
|
|
453
|
+
SELECT current_generation = 0 OR EXISTS (
|
|
454
|
+
(SELECT selected.repository_id::text, selected.canonical_https_uri,
|
|
455
|
+
selected.selected_access
|
|
456
|
+
FROM personal_github_repository_selections selected
|
|
457
|
+
WHERE selected.connection_id = p_connection_id
|
|
458
|
+
EXCEPT
|
|
459
|
+
SELECT value ->> 'repositoryId', value ->> 'canonicalUrl', value ->> 'selectedAccess'
|
|
460
|
+
FROM jsonb_array_elements(p_repositories) incoming(value))
|
|
461
|
+
UNION ALL
|
|
462
|
+
(SELECT value ->> 'repositoryId', value ->> 'canonicalUrl', value ->> 'selectedAccess'
|
|
463
|
+
FROM jsonb_array_elements(p_repositories) incoming(value)
|
|
464
|
+
EXCEPT
|
|
465
|
+
SELECT selected.repository_id::text, selected.canonical_https_uri,
|
|
466
|
+
selected.selected_access
|
|
467
|
+
FROM personal_github_repository_selections selected
|
|
468
|
+
WHERE selected.connection_id = p_connection_id)
|
|
469
|
+
) INTO authority_changed;
|
|
470
|
+
next_generation := CASE
|
|
471
|
+
WHEN authority_changed THEN current_generation + 1 ELSE current_generation END;
|
|
472
|
+
|
|
473
|
+
INSERT INTO personal_github_repository_selection_heads (
|
|
474
|
+
connection_id, account_id, origin_workspace_id, owner_subject_id,
|
|
475
|
+
provider_principal_id, credential_binding_id,
|
|
476
|
+
connection_authority_generation, generation, updated_by_subject_id
|
|
477
|
+
) VALUES (
|
|
478
|
+
p_connection_id, p_account_id, p_origin_workspace_id, p_owner_subject_id,
|
|
479
|
+
connection_row.metadata ->> 'providerPrincipalId',
|
|
480
|
+
(connection_row.metadata ->> 'credentialBindingId')::uuid,
|
|
481
|
+
connection_row.authority_generation, next_generation, p_owner_subject_id
|
|
482
|
+
) ON CONFLICT (connection_id) DO UPDATE SET
|
|
483
|
+
provider_principal_id = EXCLUDED.provider_principal_id,
|
|
484
|
+
credential_binding_id = EXCLUDED.credential_binding_id,
|
|
485
|
+
connection_authority_generation = EXCLUDED.connection_authority_generation,
|
|
486
|
+
generation = EXCLUDED.generation,
|
|
487
|
+
updated_by_subject_id = EXCLUDED.updated_by_subject_id,
|
|
488
|
+
updated_at = clock_timestamp();
|
|
489
|
+
|
|
490
|
+
FOR item IN SELECT value FROM jsonb_array_elements(p_repositories) incoming(value)
|
|
491
|
+
LOOP
|
|
492
|
+
INSERT INTO personal_github_repository_selections (
|
|
493
|
+
connection_id, repository_id, account_id, origin_workspace_id,
|
|
494
|
+
owner_subject_id, canonical_full_name, canonical_https_uri,
|
|
495
|
+
default_branch, visibility, private, archived, disabled, permissions,
|
|
496
|
+
selected_access, selection_generation, selected_by_subject_id,
|
|
497
|
+
selected_at, verified_at, updated_at
|
|
498
|
+
) VALUES (
|
|
499
|
+
p_connection_id, (item ->> 'repositoryId')::bigint, p_account_id,
|
|
500
|
+
p_origin_workspace_id, p_owner_subject_id, item ->> 'fullName',
|
|
501
|
+
item ->> 'canonicalUrl', item ->> 'defaultBranch', item ->> 'visibility',
|
|
502
|
+
(item ->> 'private')::boolean, (item ->> 'archived')::boolean,
|
|
503
|
+
(item ->> 'disabled')::boolean, item -> 'permissions',
|
|
504
|
+
item ->> 'selectedAccess', next_generation, p_owner_subject_id,
|
|
505
|
+
clock_timestamp(), (item ->> 'lastVerifiedAt')::timestamptz, clock_timestamp()
|
|
506
|
+
) ON CONFLICT (connection_id, repository_id) DO UPDATE SET
|
|
507
|
+
canonical_full_name = EXCLUDED.canonical_full_name,
|
|
508
|
+
canonical_https_uri = EXCLUDED.canonical_https_uri,
|
|
509
|
+
default_branch = EXCLUDED.default_branch,
|
|
510
|
+
visibility = EXCLUDED.visibility,
|
|
511
|
+
private = EXCLUDED.private,
|
|
512
|
+
archived = EXCLUDED.archived,
|
|
513
|
+
disabled = EXCLUDED.disabled,
|
|
514
|
+
permissions = EXCLUDED.permissions,
|
|
515
|
+
selected_access = EXCLUDED.selected_access,
|
|
516
|
+
selection_generation = CASE
|
|
517
|
+
WHEN personal_github_repository_selections.canonical_https_uri
|
|
518
|
+
IS DISTINCT FROM EXCLUDED.canonical_https_uri
|
|
519
|
+
OR personal_github_repository_selections.selected_access
|
|
520
|
+
IS DISTINCT FROM EXCLUDED.selected_access
|
|
521
|
+
THEN next_generation
|
|
522
|
+
ELSE personal_github_repository_selections.selection_generation
|
|
523
|
+
END,
|
|
524
|
+
selected_at = CASE
|
|
525
|
+
WHEN personal_github_repository_selections.canonical_https_uri
|
|
526
|
+
IS DISTINCT FROM EXCLUDED.canonical_https_uri
|
|
527
|
+
OR personal_github_repository_selections.selected_access
|
|
528
|
+
IS DISTINCT FROM EXCLUDED.selected_access
|
|
529
|
+
THEN EXCLUDED.selected_at
|
|
530
|
+
ELSE personal_github_repository_selections.selected_at
|
|
531
|
+
END,
|
|
532
|
+
verified_at = EXCLUDED.verified_at,
|
|
533
|
+
updated_at = clock_timestamp();
|
|
534
|
+
END LOOP;
|
|
535
|
+
IF NOT p_verify_only THEN
|
|
536
|
+
DELETE FROM personal_github_repository_selections selected
|
|
537
|
+
WHERE selected.connection_id = p_connection_id
|
|
538
|
+
AND NOT EXISTS (
|
|
539
|
+
SELECT 1 FROM jsonb_array_elements(p_repositories) incoming(value)
|
|
540
|
+
WHERE incoming.value ->> 'repositoryId' = selected.repository_id::text
|
|
541
|
+
);
|
|
542
|
+
END IF;
|
|
543
|
+
INSERT INTO personal_github_repository_selection_operations (
|
|
544
|
+
connection_id, idempotency_key, account_id, origin_workspace_id,
|
|
545
|
+
owner_subject_id, request_digest, resulting_generation
|
|
546
|
+
) VALUES (
|
|
547
|
+
p_connection_id, p_idempotency_key, p_account_id, p_origin_workspace_id,
|
|
548
|
+
p_owner_subject_id, request_digest, next_generation
|
|
549
|
+
);
|
|
550
|
+
RETURN get_self_personal_github_repository_selection(
|
|
551
|
+
p_account_id, p_origin_workspace_id, p_owner_subject_id, p_connection_id
|
|
552
|
+
);
|
|
553
|
+
END
|
|
554
|
+
$body$
|
|
555
|
+
$ddl$, data_schema);
|
|
556
|
+
END
|
|
557
|
+
$personal_github_repository_functions$;
|
|
558
|
+
|
|
559
|
+
DO $personal_github_repository_privileges$
|
|
560
|
+
DECLARE
|
|
561
|
+
data_schema text := current_schema();
|
|
562
|
+
BEGIN
|
|
563
|
+
EXECUTE format(
|
|
564
|
+
'REVOKE ALL ON FUNCTION %I.get_self_personal_github_repository_selection('
|
|
565
|
+
|| 'uuid,uuid,text,uuid) FROM PUBLIC', data_schema
|
|
566
|
+
);
|
|
567
|
+
EXECUTE format(
|
|
568
|
+
'REVOKE ALL ON FUNCTION %I.mutate_self_personal_github_repository_selection('
|
|
569
|
+
|| 'uuid,uuid,text,uuid,bigint,bigint,text,jsonb,boolean) FROM PUBLIC', data_schema
|
|
570
|
+
);
|
|
571
|
+
IF to_regrole('opengeni_app') IS NOT NULL THEN
|
|
572
|
+
EXECUTE format(
|
|
573
|
+
'REVOKE ALL ON TABLE %I.personal_github_repository_selection_heads, '
|
|
574
|
+
|| '%I.personal_github_repository_selections, '
|
|
575
|
+
|| '%I.personal_github_repository_selection_operations FROM opengeni_app',
|
|
576
|
+
data_schema, data_schema, data_schema
|
|
577
|
+
);
|
|
578
|
+
EXECUTE format(
|
|
579
|
+
'GRANT EXECUTE ON FUNCTION %I.get_self_personal_github_repository_selection('
|
|
580
|
+
|| 'uuid,uuid,text,uuid) TO opengeni_app', data_schema
|
|
581
|
+
);
|
|
582
|
+
EXECUTE format(
|
|
583
|
+
'GRANT EXECUTE ON FUNCTION %I.mutate_self_personal_github_repository_selection('
|
|
584
|
+
|| 'uuid,uuid,text,uuid,bigint,bigint,text,jsonb,boolean) TO opengeni_app', data_schema
|
|
585
|
+
);
|
|
586
|
+
END IF;
|
|
587
|
+
END
|
|
588
|
+
$personal_github_repository_privileges$;
|
|
589
|
+
|
|
590
|
+
COMMENT ON TABLE personal_github_repository_selection_heads IS
|
|
591
|
+
'Owner-only monotonic authority head for an explicit personal GitHub repository set.';
|
|
592
|
+
COMMENT ON TABLE personal_github_repository_selections IS
|
|
593
|
+
'Only explicitly selected personal GitHub repositories; never a private discovery catalog.';
|
|
594
|
+
|
|
595
|
+
-- Scheduled tasks already freeze user-owned connection.use authority in a
|
|
596
|
+
-- separate immutable ledger. Admit the dedicated personal-GitHub discriminator
|
|
597
|
+
-- into that existing lane; the exact repository set remains in the task's
|
|
598
|
+
-- accepted personal_connection_delegations snapshot and execution digest.
|
|
599
|
+
ALTER TABLE scheduled_task_connection_authority_snapshots
|
|
600
|
+
DROP CONSTRAINT scheduled_task_connection_authority_shape_chk,
|
|
601
|
+
ADD CONSTRAINT scheduled_task_connection_authority_shape_chk CHECK (
|
|
602
|
+
task_authority_revision > 0
|
|
603
|
+
AND execution_digest ~ '^[0-9a-f]{64}$'
|
|
604
|
+
AND octet_length(server_id) BETWEEN 1 AND 256
|
|
605
|
+
AND connection_generation > 0
|
|
606
|
+
AND (selected_kind IS NULL OR selected_kind IN ('oauth2','api_key','app_install','delegated'))
|
|
607
|
+
AND (connection_type IS NULL OR connection_type IN ('mcp', 'github_personal'))
|
|
608
|
+
AND membership_authorization_revision > 0
|
|
609
|
+
AND authority_generation > 0
|
|
610
|
+
AND grant_generation > 0
|
|
611
|
+
AND grant_mode IN ('once', 'session', 'always')
|
|
612
|
+
AND grant_context IN ('user_private', 'workspace_shared')
|
|
613
|
+
AND grant_context = session_visibility
|
|
614
|
+
AND session_visibility IN ('user_private', 'workspace_shared')
|
|
615
|
+
AND cardinality(selection_sources) > 0
|
|
616
|
+
) NOT VALID;
|
|
617
|
+
|
|
618
|
+
ALTER TABLE scheduled_task_connection_authority_snapshots
|
|
619
|
+
VALIDATE CONSTRAINT scheduled_task_connection_authority_shape_chk;
|
|
620
|
+
|
|
621
|
+
-- Per-occurrence repository-generation revalidation belongs to the scheduled
|
|
622
|
+
-- lifecycle phase. Keep the existing run-ledger discriminator unchanged so a
|
|
623
|
+
-- task definition can retain explicit personal GitHub authority while every
|
|
624
|
+
-- occurrence still fails closed before a provider consumer can run.
|