@taskforcehq/taskforce 0.3.328 → 0.3.330
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/Taskforce.module.css +523 -79
- package/dist/TaskforceCore.js +237 -230
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
- package/dist/cli.js +34 -0
- package/dist/cliCloudTargetGuard.d.ts +5 -0
- package/dist/cliCloudTargetGuard.js +11 -0
- package/dist/components/features/AiProfilesModule.js +3 -5
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +217 -54
- package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
- package/dist/components/features/TaskforceAgentsModule.js +586 -116
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
- package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
- package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
- package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
- package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
- package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
- package/dist/components/features/planning/PlanningModule.js +2 -5
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
- package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
- package/dist/components/features/taskforceAgentEditorModel.js +5 -1
- package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
- package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +65 -10
- package/dist/components/task/TaskImageReviews.js +14 -5
- package/dist/components/task/TaskKanban.d.ts +6 -1
- package/dist/components/task/TaskKanban.js +152 -6
- package/dist/components/task/TaskList.d.ts +5 -0
- package/dist/components/task/TaskList.js +3 -3
- package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TopNoticeLayer.js +1 -1
- package/dist/components/views/AppShellHeader.js +32 -11
- package/dist/components/views/PlanComparisonPage.js +12 -0
- package/dist/components/views/StandaloneLayout.js +32 -55
- package/dist/components/views/WidgetView.js +3 -3
- package/dist/components/views/panels/PlanningDrawer.js +5 -12
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
- package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
- package/dist/config/envSchema.js +60 -1
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.js +46 -8
- package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
- package/dist/core/DeletedTaskLifecycleService.js +37 -6
- package/dist/core/McpTokenService.d.ts +23 -1
- package/dist/core/McpTokenService.js +93 -10
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
- package/dist/core/TaskChecklistCommandService.d.ts +27 -0
- package/dist/core/TaskChecklistCommandService.js +83 -5
- package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
- package/dist/core/TaskLifecycleCommandService.js +6 -2
- package/dist/core/Taskforce.d.ts +94 -2
- package/dist/core/Taskforce.js +760 -36
- package/dist/core/types.d.ts +14 -0
- package/dist/documentReviews/commandService.d.ts +2 -1
- package/dist/documentReviews/commandService.js +6 -3
- package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
- package/dist/hooks/sync/orchestratorShared.js +2 -0
- package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
- package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
- package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
- package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
- package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
- package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
- package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
- package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
- package/dist/hooks/sync/useSyncStatusControls.js +47 -11
- package/dist/hooks/tasks/taskHttpMutation.js +1 -0
- package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
- package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
- package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
- package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
- package/dist/hooks/tasks/useTaskFormActions.js +65 -12
- package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
- package/dist/hooks/ui/useSettingsModel.js +13 -2
- package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
- package/dist/hooks/ui/useSettingsPersistence.js +74 -47
- package/dist/hooks/useFilterSort.d.ts +7 -3
- package/dist/hooks/useFilterSort.js +15 -5
- package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
- package/dist/hooks/useSyncOrchestrator.js +111 -2
- package/dist/hooks/useTaskData.d.ts +40 -1
- package/dist/hooks/useTaskData.js +240 -9
- package/dist/hooks/useTaskMutations.d.ts +12 -2
- package/dist/hooks/useTaskMutations.js +266 -52
- package/dist/hooks/useTaskforce.d.ts +39 -9
- package/dist/hooks/useTaskforce.js +359 -40
- package/dist/hooks/useUiNotice.d.ts +4 -0
- package/dist/hooks/useUiNotice.js +4 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
- package/dist/mcp/clientRegistry.d.ts +2 -2
- package/dist/mcp/clientRegistry.js +1 -1
- package/dist/mcp/documentAssetRegistrar.js +53 -41
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
- package/dist/mcp/durableTaskMutationRouter.js +10 -0
- package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
- package/dist/mcp/httpProtocolRouting.d.ts +10 -0
- package/dist/mcp/httpProtocolRouting.js +19 -0
- package/dist/mcp/localCliHealth.d.ts +2 -2
- package/dist/mcp/localCliHealth.js +2 -2
- package/dist/mcp/localServiceProxy.d.ts +1 -0
- package/dist/mcp/localServiceProxy.js +530 -68
- package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
- package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
- package/dist/mcp/runtime.d.ts +54 -79
- package/dist/mcp/runtime.js +556 -139
- package/dist/mcp/taskPlanningRegistrar.js +64 -42
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/mcp/toolProfiles.d.ts +2 -0
- package/dist/mcp/toolProfiles.js +10 -0
- package/dist/mcp/toolRegistry.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +1 -0
- package/dist/mcp/workflowExecutionRegistrar.js +4 -4
- package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
- package/dist/migrations/taskSchemaMigrations.js +427 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +13 -13
- package/dist/runtime/appGates.js +36 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/cloudCollectionRead.d.ts +1 -1
- package/dist/server/cloudCollectionRead.js +2 -2
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.js +123 -14
- package/dist/server/localDatabaseIdentity.js +4 -1
- package/dist/server/localServiceLease.d.ts +3 -0
- package/dist/server/localServiceLease.js +11 -2
- package/dist/server/localServiceSessions.d.ts +14 -17
- package/dist/server/localServiceSessions.js +308 -94
- package/dist/server/localWorkspaceSyncServerRuntime.js +12 -7
- package/dist/server/rateLimit.d.ts +1 -0
- package/dist/server/rateLimit.js +4 -0
- package/dist/server/realtimeSyncWs.js +36 -12
- package/dist/server/routes/admin.d.ts +4 -0
- package/dist/server/routes/admin.js +113 -3
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.d.ts +7 -0
- package/dist/server/routes/agents.js +394 -39
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/billing.js +5 -1
- package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
- package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
- package/dist/server/routes/executorPhaseAApprovals.js +140 -0
- package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
- package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
- package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
- package/dist/server/routes/githubReviewEvidence.js +116 -0
- package/dist/server/routes/localService.d.ts +15 -4
- package/dist/server/routes/localService.js +138 -40
- package/dist/server/routes/modelConnections.d.ts +24 -0
- package/dist/server/routes/modelConnections.js +205 -0
- package/dist/server/routes/primitives.d.ts +2 -0
- package/dist/server/routes/shared.d.ts +19 -0
- package/dist/server/routes/shared.js +95 -19
- package/dist/server/routes/sync.js +1 -0
- package/dist/server/routes/syncAuxRoutes.js +9 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncPushRoutes.d.ts +1 -0
- package/dist/server/routes/syncPushRoutes.js +1 -0
- package/dist/server/routes/syncV3FeedRoutes.js +27 -16
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +45 -9
- package/dist/server/routes/tasks.js +124 -13
- package/dist/server/routes/workflows.js +9 -1
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/routes.js +59 -0
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +16 -0
- package/dist/service/localServiceClientLifecycle.js +36 -10
- package/dist/services/codexAppServerModelGateway.d.ts +161 -0
- package/dist/services/codexAppServerModelGateway.js +663 -0
- package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
- package/dist/services/codexDeviceCodeLoginManager.js +265 -0
- package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
- package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
- package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
- package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
- package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
- package/dist/services/executorPhaseAApprovalService.js +609 -0
- package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
- package/dist/services/executorPhaseADriftEvaluator.js +93 -0
- package/dist/services/executorPhaseAIssuerCore.d.ts +126 -0
- package/dist/services/executorPhaseAIssuerCore.js +295 -0
- package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
- package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
- package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
- package/dist/services/githubReviewEvidenceRuntime.js +30 -0
- package/dist/services/githubReviewEvidenceService.d.ts +93 -0
- package/dist/services/githubReviewEvidenceService.js +336 -0
- package/dist/services/modelGateway.d.ts +7 -0
- package/dist/services/modelProviderConnectionService.d.ts +71 -0
- package/dist/services/modelProviderConnectionService.js +279 -0
- package/dist/services/modelProviderCredentialHome.d.ts +32 -0
- package/dist/services/modelProviderCredentialHome.js +271 -0
- package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
- package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
- package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
- package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +8 -2
- package/dist/services/taskforceAgentMcpBridge.js +30 -27
- package/dist/shared/adminEdgeProxy.d.ts +5 -0
- package/dist/shared/adminEdgeProxy.js +94 -0
- package/dist/shared/adminProxySessionCookies.d.ts +16 -0
- package/dist/shared/adminProxySessionCookies.js +86 -0
- package/dist/shared/aiProfileColors.d.ts +31 -1
- package/dist/shared/aiProfileColors.js +14 -6
- package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
- package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
- package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
- package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
- package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
- package/dist/shared/executorPhaseADriftContracts.js +63 -0
- package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
- package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
- package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
- package/dist/shared/executorPhaseARunAuthorization.js +232 -0
- package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
- package/dist/shared/executorPhaseASchemaValidation.js +53 -0
- package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
- package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
- package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
- package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
- package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
- package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
- package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
- package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
- package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
- package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
- package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
- package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
- package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
- package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
- package/dist/shared/executorPhaseATiming.d.ts +1 -0
- package/dist/shared/executorPhaseATiming.js +1 -0
- package/dist/shared/planningIdentity.js +1 -1
- package/dist/shared/productLogoKeys.d.ts +2 -0
- package/dist/shared/productLogoKeys.js +18 -0
- package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
- package/dist/shared/taskforceAgentDefinition.js +6 -3
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +36 -3
- package/dist/shared/userFeatureGrants.d.ts +4 -0
- package/dist/shared/userFeatureGrants.js +7 -0
- package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
- package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
- package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
- package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
- package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
- package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
- package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
- package/dist/storage/modelProviderConnectionStore.js +446 -0
- package/dist/storage/postgresAdapter.d.ts +24 -3
- package/dist/storage/postgresAdapter.js +117 -14
- package/dist/storage/postgresWorker.js +22 -5
- package/dist/storage/postgresWorkerProtocol.d.ts +30 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
- package/dist/sync/cloudSyncApi.d.ts +4 -1
- package/dist/sync/cloudSyncApi.js +7 -2
- package/dist/sync/contentSyncState.d.ts +1 -1
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +67 -30
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
- package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
- package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
- package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
- package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
- package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
- package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +134 -43
- package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +11 -4
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +29 -0
- package/dist/sync/syncApplyHandlers.d.ts +2 -0
- package/dist/sync/syncApplyHandlers.js +10 -1
- package/dist/sync/syncService.d.ts +17 -0
- package/dist/sync/syncService.js +87 -19
- package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
- package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
- package/dist/sync/v3/combinedFeedCapability.js +8 -0
- package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
- package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
- package/dist/sync/v3/durableOperationReplay.js +18 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +14 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +4 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +62 -15
- package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +37 -2
- package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +11 -0
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +39 -10
- package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
- package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
- package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
- package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
- package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
- package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
- package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
- package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
- package/dist/sync/v3/localTaskMetadataClient.js +1 -0
- package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
- package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
- package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
- package/dist/sync/v3/localTaskStatusClient.js +6 -1
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +272 -24
- package/dist/sync/v3/syncDurabilityStore.d.ts +41 -0
- package/dist/sync/v3/syncDurabilityStore.js +199 -13
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
- package/dist/sync/v3/taskChecklistMutationService.d.ts +15 -2
- package/dist/sync/v3/taskChecklistMutationService.js +48 -1
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
- package/dist/sync/v3/taskMetadataMutationService.js +4 -0
- package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
- package/dist/sync/v3/taskRestoreMutationService.js +7 -4
- package/dist/sync/v3/taskStatusMutationService.d.ts +31 -1
- package/dist/sync/v3/taskStatusMutationService.js +123 -3
- package/dist/sync/v3/workflowAssignmentSync.d.ts +6 -0
- package/dist/sync/v3/workflowAssignmentSync.js +30 -0
- package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
- package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
- package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +18 -3
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +14 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +49 -25
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +13 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -57
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +20 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +106 -30
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +4 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +34 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +12 -0
- package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +5 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +55 -9
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
- package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
- package/dist/sync/workspacePullFeed.js +2 -1
- package/dist/sync/workspaceRepair.d.ts +8 -2
- package/dist/sync/workspaceRepair.js +222 -6
- package/dist/sync/workspaceSyncModel.d.ts +21 -0
- package/dist/sync/workspaceSyncModel.js +35 -7
- package/dist/sync/workspaceSyncState.d.ts +1 -0
- package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
- package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
- package/dist/types.d.ts +47 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/AiIdentityRosterCard-OcSz1PkK.js +1 -0
- package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTM6nIg_.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-DabEG8L4.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Coa8yVGM.js} +2 -2
- package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-BB0qhdix.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
- package/dist/ui/assets/PlanningModule-pRPjR7v5.js +1 -0
- package/dist/ui/assets/PlansPage-D86pZSSl.js +1 -0
- package/dist/ui/assets/TaskContextUpload-BVIkU9yT.js +1 -0
- package/dist/ui/assets/TaskSettings-Cv1mNhv_.js +12 -0
- package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
- package/dist/ui/assets/TaskforceAgentsModule-gmH-PD2q.js +24 -0
- package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DbfnHJ-f.js} +1 -1
- package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
- package/dist/ui/assets/index-CTsDBaef.js +7 -0
- package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-Bsq-mcEn.js} +1 -1
- package/dist/ui/branding/logos/letterhead_dark.png +0 -0
- package/dist/ui/branding/logos/letterhead_light.png +0 -0
- package/dist/ui/branding/logos/signature_dark.png +0 -0
- package/dist/ui/branding/logos/signature_light.png +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/utils/aiProfileDefaultLogo.js +16 -48
- package/dist/utils/httpSetCookie.d.ts +1 -0
- package/dist/utils/httpSetCookie.js +4 -1
- package/dist/utils/localRuntimeUrl.d.ts +1 -0
- package/dist/utils/localRuntimeUrl.js +14 -0
- package/dist/utils/productLogoRegistry.d.ts +2 -0
- package/dist/utils/productLogoRegistry.js +36 -0
- package/dist/utils/syncStatusPresentation.d.ts +4 -0
- package/dist/utils/syncStatusPresentation.js +17 -0
- package/dist/utils/taskActivity.d.ts +3 -2
- package/dist/utils/taskActivity.js +19 -2
- package/dist/utils/taskEditorReconciliation.d.ts +40 -0
- package/dist/utils/taskEditorReconciliation.js +217 -0
- package/dist/utils/taskEvents.d.ts +2 -0
- package/dist/utils/taskNormalization.d.ts +1 -0
- package/dist/utils/taskNormalization.js +39 -0
- package/dist/utils/taskSearch.js +2 -2
- package/dist/utils/uiNotice.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
- package/dist/utils/workspaceSyncPresentation.js +23 -17
- package/package.json +36 -6
- package/dist/ui/assets/AiIdentityRosterCard-MZs7lVED.js +0 -1
- package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
- package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
- package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
- package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
- package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
- package/dist/ui/assets/TaskforceAgentsModule-BazdUwxZ.js +0 -21
- package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
- package/dist/ui/assets/index-BUplSsv_.js +0 -7
- package/dist/ui/assets/index-gz2EXuoK.css +0 -1
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { canonicalizeExecutorPhaseAJson } from '../shared/executorPhaseAApprovalReceipt.js';
|
|
3
|
+
import { EXECUTOR_PHASE_A_CLEANUP_CAPABILITY_TTL_MS, EXECUTOR_PHASE_A_MAIN_CAPABILITY_TTL_MS, } from '../shared/executorPhaseARunAuthorization.js';
|
|
4
|
+
const verifiedCapabilityRecordBrand = Symbol('verifiedExecutorPhaseACapabilityRecord');
|
|
5
|
+
const verifiedGrantRecordBrand = Symbol('verifiedExecutorPhaseAGrantRecord');
|
|
6
|
+
function sha256(value) {
|
|
7
|
+
return createHash('sha256').update(canonicalizeExecutorPhaseAJson(value)).digest('hex');
|
|
8
|
+
}
|
|
9
|
+
export function executorPhaseACapabilityRecordFromVerified(artifact) {
|
|
10
|
+
const payload = artifact.payload;
|
|
11
|
+
return {
|
|
12
|
+
capabilityId: payload.capabilityId,
|
|
13
|
+
workspaceId: payload.workspaceId,
|
|
14
|
+
taskId: payload.taskId,
|
|
15
|
+
runId: payload.runId,
|
|
16
|
+
receiptId: payload.receiptId,
|
|
17
|
+
receiptSha256: payload.receiptSha256,
|
|
18
|
+
capabilityKind: payload.capabilityKind,
|
|
19
|
+
originalCapabilityId: payload.originalCapabilityId,
|
|
20
|
+
residualInventorySha256: payload.residualInventorySha256,
|
|
21
|
+
actorUserId: payload.actorUserId,
|
|
22
|
+
accountId: payload.accountId,
|
|
23
|
+
region: payload.region,
|
|
24
|
+
availabilityZone: payload.availabilityZone,
|
|
25
|
+
readPrincipalArn: payload.readPrincipalArn,
|
|
26
|
+
brokerKeyFingerprint: payload.brokerKeyFingerprint,
|
|
27
|
+
capabilitySha256: sha256(artifact),
|
|
28
|
+
preflightSha256: payload.preflightSha256,
|
|
29
|
+
logicalEnvelopeSha256: payload.logicalEnvelopeSha256,
|
|
30
|
+
sourceCommit: payload.sourceCommit,
|
|
31
|
+
roleMapSha256: payload.roleMapSha256,
|
|
32
|
+
oidcAudienceSha256: sha256(payload.oidcAudience),
|
|
33
|
+
issuedAt: payload.issuedAt,
|
|
34
|
+
expiresAt: payload.expiresAt,
|
|
35
|
+
mutationDeadline: payload.mutationDeadline,
|
|
36
|
+
cleanupDeadline: payload.cleanupDeadline,
|
|
37
|
+
status: 'active',
|
|
38
|
+
hardStoppedAt: null,
|
|
39
|
+
createdAt: payload.issuedAt,
|
|
40
|
+
updatedAt: payload.issuedAt,
|
|
41
|
+
[verifiedCapabilityRecordBrand]: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function executorPhaseAGrantRecordFromVerified(bundle, tokenId) {
|
|
45
|
+
const payload = bundle.grant.payload;
|
|
46
|
+
if (!/^token-[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/.test(tokenId)) {
|
|
47
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload token ID is invalid.');
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
grantId: payload.grantId,
|
|
51
|
+
capabilityId: payload.capabilityId,
|
|
52
|
+
workspaceId: payload.workspaceId,
|
|
53
|
+
taskId: payload.taskId,
|
|
54
|
+
runId: payload.runId,
|
|
55
|
+
receiptId: payload.receiptId,
|
|
56
|
+
phase: payload.phase,
|
|
57
|
+
roleArn: payload.roleArn,
|
|
58
|
+
grantSha256: bundle.grantSha256,
|
|
59
|
+
tokenId,
|
|
60
|
+
nonceId: payload.nonceId,
|
|
61
|
+
senderProofSha256: bundle.senderProofSha256,
|
|
62
|
+
brokerKeyFingerprint: payload.brokerKeyFingerprint,
|
|
63
|
+
sourceIdentity: payload.sourceIdentity,
|
|
64
|
+
sessionTagsSha256: sha256(payload.sessionTags),
|
|
65
|
+
policySha256: payload.policySha256,
|
|
66
|
+
issuedAt: payload.issuedAt,
|
|
67
|
+
expiresAt: payload.expiresAt,
|
|
68
|
+
usedAt: null,
|
|
69
|
+
status: 'issued',
|
|
70
|
+
createdAt: payload.issuedAt,
|
|
71
|
+
updatedAt: payload.issuedAt,
|
|
72
|
+
[verifiedGrantRecordBrand]: true,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export class ExecutorPhaseARunAuthorizationError extends Error {
|
|
76
|
+
code = 'executor_phase_a_run_authorization_invalid';
|
|
77
|
+
constructor(message) {
|
|
78
|
+
super(message);
|
|
79
|
+
this.name = 'ExecutorPhaseARunAuthorizationError';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function timestamp(value, field) {
|
|
83
|
+
const parsed = Date.parse(value);
|
|
84
|
+
if (!Number.isFinite(parsed))
|
|
85
|
+
throw new ExecutorPhaseARunAuthorizationError(`${field} is invalid.`);
|
|
86
|
+
return parsed;
|
|
87
|
+
}
|
|
88
|
+
function isUniqueConstraintError(error) {
|
|
89
|
+
const code = error && typeof error === 'object' && typeof error.code === 'string'
|
|
90
|
+
? String(error.code)
|
|
91
|
+
: '';
|
|
92
|
+
return code === '23505'
|
|
93
|
+
|| code === 'SQLITE_CONSTRAINT_UNIQUE'
|
|
94
|
+
|| code === 'SQLITE_CONSTRAINT_PRIMARYKEY';
|
|
95
|
+
}
|
|
96
|
+
function capabilityFromRow(row) {
|
|
97
|
+
return {
|
|
98
|
+
capabilityId: String(row.capability_id),
|
|
99
|
+
workspaceId: String(row.workspace_id),
|
|
100
|
+
taskId: String(row.task_id),
|
|
101
|
+
runId: String(row.run_id),
|
|
102
|
+
receiptId: String(row.receipt_id),
|
|
103
|
+
receiptSha256: String(row.receipt_sha256),
|
|
104
|
+
capabilityKind: String(row.capability_kind),
|
|
105
|
+
originalCapabilityId: row.original_capability_id == null ? null : String(row.original_capability_id),
|
|
106
|
+
residualInventorySha256: row.residual_inventory_sha256 == null ? null : String(row.residual_inventory_sha256),
|
|
107
|
+
actorUserId: String(row.actor_user_id),
|
|
108
|
+
accountId: String(row.account_id),
|
|
109
|
+
region: String(row.region),
|
|
110
|
+
availabilityZone: String(row.availability_zone),
|
|
111
|
+
readPrincipalArn: String(row.read_principal_arn),
|
|
112
|
+
brokerKeyFingerprint: String(row.broker_key_fingerprint),
|
|
113
|
+
capabilitySha256: String(row.capability_sha256),
|
|
114
|
+
preflightSha256: String(row.preflight_sha256),
|
|
115
|
+
logicalEnvelopeSha256: String(row.logical_envelope_sha256),
|
|
116
|
+
sourceCommit: String(row.source_commit),
|
|
117
|
+
roleMapSha256: String(row.role_map_sha256),
|
|
118
|
+
oidcAudienceSha256: String(row.oidc_audience_sha256),
|
|
119
|
+
issuedAt: String(row.issued_at),
|
|
120
|
+
expiresAt: String(row.expires_at),
|
|
121
|
+
mutationDeadline: String(row.mutation_deadline),
|
|
122
|
+
cleanupDeadline: String(row.cleanup_deadline),
|
|
123
|
+
status: String(row.status),
|
|
124
|
+
hardStoppedAt: row.hard_stopped_at == null ? null : String(row.hard_stopped_at),
|
|
125
|
+
createdAt: String(row.created_at),
|
|
126
|
+
updatedAt: String(row.updated_at),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function grantFromRow(row) {
|
|
130
|
+
return {
|
|
131
|
+
grantId: String(row.grant_id),
|
|
132
|
+
capabilityId: String(row.capability_id),
|
|
133
|
+
workspaceId: String(row.workspace_id),
|
|
134
|
+
taskId: String(row.task_id),
|
|
135
|
+
runId: String(row.run_id),
|
|
136
|
+
receiptId: String(row.receipt_id),
|
|
137
|
+
phase: String(row.phase),
|
|
138
|
+
roleArn: String(row.role_arn),
|
|
139
|
+
grantSha256: String(row.grant_sha256),
|
|
140
|
+
tokenId: String(row.token_id),
|
|
141
|
+
nonceId: String(row.nonce_id),
|
|
142
|
+
senderProofSha256: String(row.sender_proof_sha256),
|
|
143
|
+
brokerKeyFingerprint: String(row.broker_key_fingerprint),
|
|
144
|
+
sourceIdentity: String(row.source_identity),
|
|
145
|
+
sessionTagsSha256: String(row.session_tags_sha256),
|
|
146
|
+
policySha256: String(row.policy_sha256),
|
|
147
|
+
issuedAt: String(row.issued_at),
|
|
148
|
+
expiresAt: String(row.expires_at),
|
|
149
|
+
usedAt: row.used_at == null ? null : String(row.used_at),
|
|
150
|
+
status: String(row.status),
|
|
151
|
+
createdAt: String(row.created_at),
|
|
152
|
+
updatedAt: String(row.updated_at),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function nonceFromRow(row) {
|
|
156
|
+
return {
|
|
157
|
+
nonceId: String(row.nonce_id),
|
|
158
|
+
capabilityId: String(row.capability_id),
|
|
159
|
+
requestSha256: String(row.request_sha256),
|
|
160
|
+
phase: String(row.phase),
|
|
161
|
+
issuedAt: String(row.issued_at),
|
|
162
|
+
expiresAt: String(row.expires_at),
|
|
163
|
+
consumedAt: row.consumed_at == null ? null : String(row.consumed_at),
|
|
164
|
+
status: String(row.status),
|
|
165
|
+
createdAt: String(row.created_at),
|
|
166
|
+
updatedAt: String(row.updated_at),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
export class ExecutorPhaseARunAuthorizationStore {
|
|
170
|
+
db;
|
|
171
|
+
tenantId;
|
|
172
|
+
constructor(db, tenantId) {
|
|
173
|
+
this.db = db;
|
|
174
|
+
this.tenantId = tenantId;
|
|
175
|
+
}
|
|
176
|
+
findCapability(capabilityId) {
|
|
177
|
+
const row = this.db.prepare(`
|
|
178
|
+
SELECT * FROM executor_phase_a_run_capabilities
|
|
179
|
+
WHERE tenant_id = ? AND capability_id = ?
|
|
180
|
+
LIMIT 1
|
|
181
|
+
`).get(this.tenantId, capabilityId);
|
|
182
|
+
return row ? capabilityFromRow(row) : null;
|
|
183
|
+
}
|
|
184
|
+
persistCapability(candidate) {
|
|
185
|
+
this.assertCapability(candidate);
|
|
186
|
+
try {
|
|
187
|
+
this.db.prepare(`
|
|
188
|
+
INSERT INTO executor_phase_a_run_capabilities (
|
|
189
|
+
capability_id, tenant_id, workspace_id, task_id, run_id, receipt_id, receipt_sha256,
|
|
190
|
+
capability_kind, original_capability_id, residual_inventory_sha256, actor_user_id,
|
|
191
|
+
account_id, region, availability_zone, read_principal_arn, broker_key_fingerprint,
|
|
192
|
+
capability_sha256, preflight_sha256, logical_envelope_sha256, source_commit,
|
|
193
|
+
role_map_sha256, oidc_audience_sha256, issued_at, expires_at, mutation_deadline,
|
|
194
|
+
cleanup_deadline, status, hard_stopped_at, created_at, updated_at
|
|
195
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
196
|
+
`).run(candidate.capabilityId, this.tenantId, candidate.workspaceId, candidate.taskId, candidate.runId, candidate.receiptId, candidate.receiptSha256, candidate.capabilityKind, candidate.originalCapabilityId, candidate.residualInventorySha256, candidate.actorUserId, candidate.accountId, candidate.region, candidate.availabilityZone, candidate.readPrincipalArn, candidate.brokerKeyFingerprint, candidate.capabilitySha256, candidate.preflightSha256, candidate.logicalEnvelopeSha256, candidate.sourceCommit, candidate.roleMapSha256, candidate.oidcAudienceSha256, candidate.issuedAt, candidate.expiresAt, candidate.mutationDeadline, candidate.cleanupDeadline, candidate.status, candidate.hardStoppedAt, candidate.createdAt, candidate.updatedAt);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (!isUniqueConstraintError(error))
|
|
200
|
+
throw error;
|
|
201
|
+
throw new ExecutorPhaseARunAuthorizationError('The receipt, broker key, or capability is already bound to a Phase A run.');
|
|
202
|
+
}
|
|
203
|
+
return this.findCapability(candidate.capabilityId);
|
|
204
|
+
}
|
|
205
|
+
hardStop(capabilityId, stoppedAt) {
|
|
206
|
+
timestamp(stoppedAt, 'hardStoppedAt');
|
|
207
|
+
const stop = this.db.transaction(() => {
|
|
208
|
+
const result = this.db.prepare(`
|
|
209
|
+
UPDATE executor_phase_a_run_capabilities
|
|
210
|
+
SET status = 'awaiting-cleanup-approval', hard_stopped_at = ?, updated_at = ?
|
|
211
|
+
WHERE tenant_id = ? AND capability_id = ? AND capability_kind = 'main' AND status = 'active'
|
|
212
|
+
`).run(stoppedAt, stoppedAt, this.tenantId, capabilityId);
|
|
213
|
+
if (Number(result.changes ?? result.rowCount ?? 0) !== 1) {
|
|
214
|
+
throw new ExecutorPhaseARunAuthorizationError('Only one active main capability can be hard-stopped.');
|
|
215
|
+
}
|
|
216
|
+
this.db.prepare(`
|
|
217
|
+
UPDATE executor_phase_a_sender_nonces
|
|
218
|
+
SET status = 'revoked', updated_at = ?
|
|
219
|
+
WHERE tenant_id = ? AND capability_id = ? AND status = 'issued'
|
|
220
|
+
`).run(stoppedAt, this.tenantId, capabilityId);
|
|
221
|
+
this.db.prepare(`
|
|
222
|
+
UPDATE executor_phase_a_workload_grants
|
|
223
|
+
SET status = 'revoked', updated_at = ?
|
|
224
|
+
WHERE tenant_id = ? AND capability_id = ? AND status = 'issued'
|
|
225
|
+
`).run(stoppedAt, this.tenantId, capabilityId);
|
|
226
|
+
return this.findCapability(capabilityId);
|
|
227
|
+
});
|
|
228
|
+
return stop();
|
|
229
|
+
}
|
|
230
|
+
issueNonce(candidate) {
|
|
231
|
+
const issue = this.db.transaction(() => {
|
|
232
|
+
const capability = this.findCapability(candidate.capabilityId);
|
|
233
|
+
const issuedAt = timestamp(candidate.issuedAt, 'issuedAt');
|
|
234
|
+
const expiresAt = timestamp(candidate.expiresAt, 'expiresAt');
|
|
235
|
+
if (!capability || capability.status !== 'active') {
|
|
236
|
+
throw new ExecutorPhaseARunAuthorizationError('The sender nonce is not valid for an active capability.');
|
|
237
|
+
}
|
|
238
|
+
const phaseDeadline = timestamp(candidate.phase === 'cleanup' ? capability.cleanupDeadline : capability.mutationDeadline, candidate.phase === 'cleanup' ? 'cleanupDeadline' : 'mutationDeadline');
|
|
239
|
+
if (candidate.status !== 'issued' || candidate.consumedAt !== null
|
|
240
|
+
|| expiresAt <= issuedAt || expiresAt - issuedAt > 2 * 60 * 1000
|
|
241
|
+
|| issuedAt >= phaseDeadline || expiresAt > phaseDeadline
|
|
242
|
+
|| !/^[a-f0-9]{64}$/.test(candidate.requestSha256)
|
|
243
|
+
|| (capability.capabilityKind === 'cleanup-only' && candidate.phase !== 'cleanup')) {
|
|
244
|
+
throw new ExecutorPhaseARunAuthorizationError('The sender nonce is not valid for an active capability.');
|
|
245
|
+
}
|
|
246
|
+
const guard = this.db.prepare(`
|
|
247
|
+
UPDATE executor_phase_a_run_capabilities
|
|
248
|
+
SET updated_at = updated_at
|
|
249
|
+
WHERE tenant_id = ? AND capability_id = ? AND status = 'active'
|
|
250
|
+
`).run(this.tenantId, candidate.capabilityId);
|
|
251
|
+
if (Number(guard.changes ?? guard.rowCount ?? 0) !== 1) {
|
|
252
|
+
throw new ExecutorPhaseARunAuthorizationError('The run capability was revoked before nonce issuance.');
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
this.db.prepare(`
|
|
256
|
+
INSERT INTO executor_phase_a_sender_nonces (
|
|
257
|
+
nonce_id, tenant_id, capability_id, request_sha256, phase, issued_at, expires_at,
|
|
258
|
+
consumed_at, status, created_at, updated_at
|
|
259
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
260
|
+
`).run(candidate.nonceId, this.tenantId, candidate.capabilityId, candidate.requestSha256, candidate.phase, candidate.issuedAt, candidate.expiresAt, candidate.consumedAt, candidate.status, candidate.createdAt, candidate.updatedAt);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
if (!isUniqueConstraintError(error))
|
|
264
|
+
throw error;
|
|
265
|
+
throw new ExecutorPhaseARunAuthorizationError('The sender nonce is already registered.');
|
|
266
|
+
}
|
|
267
|
+
const row = this.db.prepare(`
|
|
268
|
+
SELECT * FROM executor_phase_a_sender_nonces WHERE tenant_id = ? AND nonce_id = ?
|
|
269
|
+
`).get(this.tenantId, candidate.nonceId);
|
|
270
|
+
return nonceFromRow(row);
|
|
271
|
+
});
|
|
272
|
+
return issue();
|
|
273
|
+
}
|
|
274
|
+
persistGrant(candidate, now) {
|
|
275
|
+
const persist = this.db.transaction(() => {
|
|
276
|
+
const capability = this.findCapability(candidate.capabilityId);
|
|
277
|
+
if (!capability || capability.status !== 'active') {
|
|
278
|
+
throw new ExecutorPhaseARunAuthorizationError('The run capability is unavailable or revoked.');
|
|
279
|
+
}
|
|
280
|
+
if (candidate.status !== 'issued' || candidate.usedAt !== null) {
|
|
281
|
+
throw new ExecutorPhaseARunAuthorizationError('A new workload grant must begin issued and unused.');
|
|
282
|
+
}
|
|
283
|
+
if (candidate.workspaceId !== capability.workspaceId || candidate.taskId !== capability.taskId
|
|
284
|
+
|| candidate.runId !== capability.runId || candidate.receiptId !== capability.receiptId
|
|
285
|
+
|| candidate.brokerKeyFingerprint !== capability.brokerKeyFingerprint) {
|
|
286
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant scope differs from its run capability.');
|
|
287
|
+
}
|
|
288
|
+
const nowMs = timestamp(now, 'now');
|
|
289
|
+
const issuedAt = timestamp(candidate.issuedAt, 'issuedAt');
|
|
290
|
+
const expiresAt = timestamp(candidate.expiresAt, 'expiresAt');
|
|
291
|
+
if (issuedAt !== nowMs || expiresAt <= issuedAt || expiresAt - issuedAt > 2 * 60 * 1000) {
|
|
292
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant lifetime is invalid.');
|
|
293
|
+
}
|
|
294
|
+
if (capability.capabilityKind === 'cleanup-only' && candidate.phase !== 'cleanup') {
|
|
295
|
+
throw new ExecutorPhaseARunAuthorizationError('A cleanup-only capability cannot issue a mutation grant.');
|
|
296
|
+
}
|
|
297
|
+
const deadline = candidate.phase === 'cleanup'
|
|
298
|
+
? timestamp(capability.cleanupDeadline, 'cleanupDeadline')
|
|
299
|
+
: timestamp(capability.mutationDeadline, 'mutationDeadline');
|
|
300
|
+
if (nowMs >= deadline || expiresAt > deadline) {
|
|
301
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant exceeds the approved phase deadline.');
|
|
302
|
+
}
|
|
303
|
+
const guard = this.db.prepare(`
|
|
304
|
+
UPDATE executor_phase_a_run_capabilities
|
|
305
|
+
SET updated_at = updated_at
|
|
306
|
+
WHERE tenant_id = ? AND capability_id = ? AND status = 'active'
|
|
307
|
+
`).run(this.tenantId, candidate.capabilityId);
|
|
308
|
+
if (Number(guard.changes ?? guard.rowCount ?? 0) !== 1) {
|
|
309
|
+
throw new ExecutorPhaseARunAuthorizationError('The run capability was revoked before grant issuance.');
|
|
310
|
+
}
|
|
311
|
+
const nonce = this.db.prepare(`
|
|
312
|
+
SELECT * FROM executor_phase_a_sender_nonces
|
|
313
|
+
WHERE tenant_id = ? AND capability_id = ? AND nonce_id = ?
|
|
314
|
+
`).get(this.tenantId, candidate.capabilityId, candidate.nonceId);
|
|
315
|
+
if (!nonce || nonce.status !== 'issued' || nonce.phase !== candidate.phase
|
|
316
|
+
|| timestamp(String(nonce.expires_at), 'nonceExpiresAt') <= nowMs) {
|
|
317
|
+
throw new ExecutorPhaseARunAuthorizationError('The sender nonce is missing, expired, consumed, or bound to another phase.');
|
|
318
|
+
}
|
|
319
|
+
const consumed = this.db.prepare(`
|
|
320
|
+
UPDATE executor_phase_a_sender_nonces
|
|
321
|
+
SET status = 'consumed', consumed_at = ?, updated_at = ?
|
|
322
|
+
WHERE tenant_id = ? AND capability_id = ? AND nonce_id = ? AND status = 'issued'
|
|
323
|
+
`).run(now, now, this.tenantId, candidate.capabilityId, candidate.nonceId);
|
|
324
|
+
if (Number(consumed.changes ?? consumed.rowCount ?? 0) !== 1) {
|
|
325
|
+
throw new ExecutorPhaseARunAuthorizationError('The sender nonce was already consumed.');
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
this.db.prepare(`
|
|
329
|
+
INSERT INTO executor_phase_a_workload_grants (
|
|
330
|
+
grant_id, tenant_id, capability_id, workspace_id, task_id, run_id, receipt_id,
|
|
331
|
+
phase, role_arn, grant_sha256, token_id, nonce_id, sender_proof_sha256, broker_key_fingerprint,
|
|
332
|
+
source_identity, session_tags_sha256, policy_sha256, issued_at, expires_at,
|
|
333
|
+
used_at, status, created_at, updated_at
|
|
334
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
335
|
+
`).run(candidate.grantId, this.tenantId, candidate.capabilityId, candidate.workspaceId, candidate.taskId, candidate.runId, candidate.receiptId, candidate.phase, candidate.roleArn, candidate.grantSha256, candidate.tokenId, candidate.nonceId, candidate.senderProofSha256, candidate.brokerKeyFingerprint, candidate.sourceIdentity, candidate.sessionTagsSha256, candidate.policySha256, candidate.issuedAt, candidate.expiresAt, candidate.usedAt, candidate.status, candidate.createdAt, candidate.updatedAt);
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
if (!isUniqueConstraintError(error))
|
|
339
|
+
throw error;
|
|
340
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant token or sender proof was already used.');
|
|
341
|
+
}
|
|
342
|
+
const row = this.db.prepare(`
|
|
343
|
+
SELECT * FROM executor_phase_a_workload_grants
|
|
344
|
+
WHERE tenant_id = ? AND grant_id = ?
|
|
345
|
+
`).get(this.tenantId, candidate.grantId);
|
|
346
|
+
return grantFromRow(row);
|
|
347
|
+
});
|
|
348
|
+
return persist();
|
|
349
|
+
}
|
|
350
|
+
redeemVerifiedGrant(bundle, requestId, requestSha256, canonicalResponseBytes, responseSha256, usedAt) {
|
|
351
|
+
if (!/^issuer-request-[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/.test(requestId)
|
|
352
|
+
|| !/^[a-f0-9]{64}$/.test(requestSha256)
|
|
353
|
+
|| createHash('sha256').update(canonicalResponseBytes).digest('hex') !== responseSha256) {
|
|
354
|
+
throw new ExecutorPhaseARunAuthorizationError('The issuer redemption record is invalid.');
|
|
355
|
+
}
|
|
356
|
+
timestamp(usedAt, 'usedAt');
|
|
357
|
+
const use = this.db.transaction(() => {
|
|
358
|
+
const readExisting = () => {
|
|
359
|
+
const existing = this.db.prepare(`
|
|
360
|
+
SELECT grant_id, grant_sha256, sender_proof_sha256, request_sha256,
|
|
361
|
+
canonical_response_bytes, response_sha256
|
|
362
|
+
FROM executor_phase_a_issuer_redemptions
|
|
363
|
+
WHERE tenant_id = ? AND request_id = ?
|
|
364
|
+
`).get(this.tenantId, requestId);
|
|
365
|
+
if (!existing)
|
|
366
|
+
return null;
|
|
367
|
+
if (String(existing.grant_id) !== bundle.grant.payload.grantId
|
|
368
|
+
|| String(existing.grant_sha256) !== bundle.grantSha256
|
|
369
|
+
|| String(existing.sender_proof_sha256) !== bundle.senderProofSha256
|
|
370
|
+
|| String(existing.request_sha256) !== requestSha256) {
|
|
371
|
+
throw new ExecutorPhaseARunAuthorizationError('The issuer request ID was already used for different redemption bytes.');
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
bytes: Buffer.from(existing.canonical_response_bytes),
|
|
375
|
+
digest: String(existing.response_sha256),
|
|
376
|
+
created: false,
|
|
377
|
+
status: 'used',
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
const existing = readExisting();
|
|
381
|
+
if (existing)
|
|
382
|
+
return existing;
|
|
383
|
+
const grantId = bundle.grant.payload.grantId;
|
|
384
|
+
const row = this.db.prepare(`
|
|
385
|
+
SELECT capability_id, phase, expires_at FROM executor_phase_a_workload_grants
|
|
386
|
+
WHERE tenant_id = ? AND grant_id = ? AND status = 'issued'
|
|
387
|
+
AND grant_sha256 = ? AND sender_proof_sha256 = ?
|
|
388
|
+
`).get(this.tenantId, grantId, bundle.grantSha256, bundle.senderProofSha256);
|
|
389
|
+
const capability = row?.capability_id ? this.findCapability(row.capability_id) : null;
|
|
390
|
+
const usedAtMs = timestamp(usedAt, 'usedAt');
|
|
391
|
+
const phaseDeadline = capability && row?.phase
|
|
392
|
+
? timestamp(row.phase === 'cleanup' ? capability.cleanupDeadline : capability.mutationDeadline, 'phaseDeadline')
|
|
393
|
+
: Number.NaN;
|
|
394
|
+
if (!row?.capability_id || !row.phase || !row.expires_at || !capability || capability.status !== 'active'
|
|
395
|
+
|| usedAtMs >= timestamp(row.expires_at, 'grantExpiresAt') || usedAtMs >= phaseDeadline) {
|
|
396
|
+
const retry = readExisting();
|
|
397
|
+
if (retry)
|
|
398
|
+
return retry;
|
|
399
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant is unavailable or revoked.');
|
|
400
|
+
}
|
|
401
|
+
const guard = this.db.prepare(`
|
|
402
|
+
UPDATE executor_phase_a_run_capabilities
|
|
403
|
+
SET updated_at = updated_at
|
|
404
|
+
WHERE tenant_id = ? AND capability_id = ? AND status = 'active'
|
|
405
|
+
`).run(this.tenantId, row.capability_id);
|
|
406
|
+
if (Number(guard.changes ?? guard.rowCount ?? 0) !== 1) {
|
|
407
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant capability was hard-stopped before redemption.');
|
|
408
|
+
}
|
|
409
|
+
const result = this.db.prepare(`
|
|
410
|
+
UPDATE executor_phase_a_workload_grants
|
|
411
|
+
SET status = 'used', used_at = ?, updated_at = ?
|
|
412
|
+
WHERE tenant_id = ? AND grant_id = ? AND status = 'issued'
|
|
413
|
+
`).run(usedAt, usedAt, this.tenantId, grantId);
|
|
414
|
+
if (Number(result.changes ?? result.rowCount ?? 0) !== 1) {
|
|
415
|
+
const retry = readExisting();
|
|
416
|
+
if (retry)
|
|
417
|
+
return retry;
|
|
418
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant was already consumed or revoked.');
|
|
419
|
+
}
|
|
420
|
+
const inserted = this.db.prepare(`
|
|
421
|
+
INSERT INTO executor_phase_a_issuer_redemptions (
|
|
422
|
+
request_id, tenant_id, grant_id, grant_sha256, sender_proof_sha256,
|
|
423
|
+
request_sha256, canonical_response_bytes, response_sha256, redeemed_at
|
|
424
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
425
|
+
ON CONFLICT DO NOTHING
|
|
426
|
+
`).run(requestId, this.tenantId, grantId, bundle.grantSha256, bundle.senderProofSha256, requestSha256, canonicalResponseBytes, responseSha256, usedAt);
|
|
427
|
+
if (Number(inserted.changes ?? inserted.rowCount ?? 0) !== 1) {
|
|
428
|
+
const retry = readExisting();
|
|
429
|
+
if (retry)
|
|
430
|
+
return retry;
|
|
431
|
+
throw new ExecutorPhaseARunAuthorizationError('The workload grant or issuer request was already redeemed.');
|
|
432
|
+
}
|
|
433
|
+
return { bytes: canonicalResponseBytes, digest: responseSha256, created: true, status: 'used' };
|
|
434
|
+
});
|
|
435
|
+
return use();
|
|
436
|
+
}
|
|
437
|
+
assertCapability(candidate) {
|
|
438
|
+
if (candidate.status !== 'active' || candidate.hardStoppedAt !== null) {
|
|
439
|
+
throw new ExecutorPhaseARunAuthorizationError('A new run capability must begin active and not hard-stopped.');
|
|
440
|
+
}
|
|
441
|
+
const issuedAt = timestamp(candidate.issuedAt, 'issuedAt');
|
|
442
|
+
const expiresAt = timestamp(candidate.expiresAt, 'expiresAt');
|
|
443
|
+
const mutationDeadline = timestamp(candidate.mutationDeadline, 'mutationDeadline');
|
|
444
|
+
const cleanupDeadline = timestamp(candidate.cleanupDeadline, 'cleanupDeadline');
|
|
445
|
+
const receipt = this.db.prepare(`
|
|
446
|
+
SELECT receipt_kind, original_capability_id, residual_inventory_sha256,
|
|
447
|
+
receipt_sha256, approved_at, expires_at
|
|
448
|
+
FROM executor_phase_a_approval_receipts
|
|
449
|
+
WHERE tenant_id = ? AND receipt_id = ?
|
|
450
|
+
LIMIT 1
|
|
451
|
+
`).get(this.tenantId, candidate.receiptId);
|
|
452
|
+
const receiptApprovedAt = receipt ? timestamp(String(receipt.approved_at), 'receipt.approvedAt') : NaN;
|
|
453
|
+
const receiptExpiresAt = receipt ? timestamp(String(receipt.expires_at), 'receipt.expiresAt') : NaN;
|
|
454
|
+
if (!receipt || String(receipt.receipt_sha256) !== candidate.receiptSha256
|
|
455
|
+
|| String(receipt.receipt_kind) !== candidate.capabilityKind
|
|
456
|
+
|| (receipt.original_capability_id == null ? null : String(receipt.original_capability_id)) !== candidate.originalCapabilityId
|
|
457
|
+
|| (receipt.residual_inventory_sha256 == null ? null : String(receipt.residual_inventory_sha256)) !== candidate.residualInventorySha256
|
|
458
|
+
|| issuedAt < receiptApprovedAt || issuedAt >= receiptExpiresAt || issuedAt >= cleanupDeadline) {
|
|
459
|
+
throw new ExecutorPhaseARunAuthorizationError('The run capability is not bound to a durable approval receipt.');
|
|
460
|
+
}
|
|
461
|
+
if (candidate.capabilityKind === 'main') {
|
|
462
|
+
if (candidate.originalCapabilityId !== null || candidate.residualInventorySha256 !== null
|
|
463
|
+
|| mutationDeadline !== receiptApprovedAt + 8 * 60 * 60 * 1000
|
|
464
|
+
|| cleanupDeadline !== receiptApprovedAt + EXECUTOR_PHASE_A_MAIN_CAPABILITY_TTL_MS
|
|
465
|
+
|| expiresAt !== cleanupDeadline) {
|
|
466
|
+
throw new ExecutorPhaseARunAuthorizationError('The main capability lifetime or ancestry is invalid.');
|
|
467
|
+
}
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const original = candidate.originalCapabilityId
|
|
471
|
+
? this.findCapability(candidate.originalCapabilityId)
|
|
472
|
+
: null;
|
|
473
|
+
if (!original || original.capabilityKind !== 'main' || original.status !== 'awaiting-cleanup-approval'
|
|
474
|
+
|| !candidate.residualInventorySha256 || !/^[a-f0-9]{64}$/.test(candidate.residualInventorySha256)
|
|
475
|
+
|| original.workspaceId !== candidate.workspaceId || original.taskId !== candidate.taskId
|
|
476
|
+
|| original.runId !== candidate.runId
|
|
477
|
+
|| original.accountId !== candidate.accountId || original.region !== candidate.region
|
|
478
|
+
|| original.availabilityZone !== candidate.availabilityZone
|
|
479
|
+
|| original.readPrincipalArn !== candidate.readPrincipalArn
|
|
480
|
+
|| original.brokerKeyFingerprint !== candidate.brokerKeyFingerprint
|
|
481
|
+
|| original.preflightSha256 !== candidate.preflightSha256
|
|
482
|
+
|| original.logicalEnvelopeSha256 !== candidate.logicalEnvelopeSha256
|
|
483
|
+
|| original.sourceCommit !== candidate.sourceCommit
|
|
484
|
+
|| original.roleMapSha256 !== candidate.roleMapSha256
|
|
485
|
+
|| original.oidcAudienceSha256 !== candidate.oidcAudienceSha256
|
|
486
|
+
|| original.receiptId === candidate.receiptId
|
|
487
|
+
|| mutationDeadline !== receiptApprovedAt || cleanupDeadline !== expiresAt
|
|
488
|
+
|| cleanupDeadline !== receiptApprovedAt + EXECUTOR_PHASE_A_CLEANUP_CAPABILITY_TTL_MS) {
|
|
489
|
+
throw new ExecutorPhaseARunAuthorizationError('The cleanup capability requires a hard-stopped main run and a distinct bounded receipt.');
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from './databaseAdapter.js';
|
|
2
|
+
export interface GitHubReviewEvidenceInstallationBinding {
|
|
3
|
+
workspaceId: string;
|
|
4
|
+
installationId: string;
|
|
5
|
+
accountId: string;
|
|
6
|
+
accountLogin: string;
|
|
7
|
+
accountType: string;
|
|
8
|
+
repositorySelection: string;
|
|
9
|
+
boundByUserId: string;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
updatedAt: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class GitHubReviewEvidenceInstallationConflictError extends Error {
|
|
14
|
+
readonly code = "github_installation_already_bound";
|
|
15
|
+
readonly statusCode = 409;
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
18
|
+
export declare class GitHubReviewEvidenceInstallationStore {
|
|
19
|
+
private readonly db;
|
|
20
|
+
private readonly tenantId;
|
|
21
|
+
private readonly now;
|
|
22
|
+
constructor(db: DatabaseAdapter, tenantId: string, now?: () => Date);
|
|
23
|
+
get(workspaceId: string): GitHubReviewEvidenceInstallationBinding | null;
|
|
24
|
+
put(input: Omit<GitHubReviewEvidenceInstallationBinding, 'createdAt' | 'updatedAt'>): GitHubReviewEvidenceInstallationBinding;
|
|
25
|
+
delete(workspaceId: string): boolean;
|
|
26
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export class GitHubReviewEvidenceInstallationConflictError extends Error {
|
|
2
|
+
code = 'github_installation_already_bound';
|
|
3
|
+
statusCode = 409;
|
|
4
|
+
constructor() {
|
|
5
|
+
super('This GitHub App installation is already bound to another workspace.');
|
|
6
|
+
this.name = 'GitHubReviewEvidenceInstallationConflictError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class GitHubReviewEvidenceInstallationStore {
|
|
10
|
+
db;
|
|
11
|
+
tenantId;
|
|
12
|
+
now;
|
|
13
|
+
constructor(db, tenantId, now = () => new Date()) {
|
|
14
|
+
this.db = db;
|
|
15
|
+
this.tenantId = tenantId;
|
|
16
|
+
this.now = now;
|
|
17
|
+
}
|
|
18
|
+
get(workspaceId) {
|
|
19
|
+
const normalizedWorkspaceId = String(workspaceId || '').trim();
|
|
20
|
+
if (!normalizedWorkspaceId)
|
|
21
|
+
return null;
|
|
22
|
+
const row = this.db.prepare(`
|
|
23
|
+
SELECT *
|
|
24
|
+
FROM github_review_evidence_installation_bindings
|
|
25
|
+
WHERE tenant_id = ? AND workspace_id = ?
|
|
26
|
+
LIMIT 1
|
|
27
|
+
`).get(this.tenantId, normalizedWorkspaceId);
|
|
28
|
+
if (!row)
|
|
29
|
+
return null;
|
|
30
|
+
return {
|
|
31
|
+
workspaceId: String(row.workspace_id || ''),
|
|
32
|
+
installationId: String(row.installation_id || ''),
|
|
33
|
+
accountId: String(row.account_id || ''),
|
|
34
|
+
accountLogin: String(row.account_login || ''),
|
|
35
|
+
accountType: String(row.account_type || ''),
|
|
36
|
+
repositorySelection: String(row.repository_selection || ''),
|
|
37
|
+
boundByUserId: String(row.bound_by_user_id || ''),
|
|
38
|
+
createdAt: String(row.created_at || ''),
|
|
39
|
+
updatedAt: String(row.updated_at || ''),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
put(input) {
|
|
43
|
+
const workspaceId = String(input.workspaceId || '').trim();
|
|
44
|
+
if (!workspaceId)
|
|
45
|
+
throw new Error('workspaceId is required.');
|
|
46
|
+
const installationId = String(input.installationId || '').trim();
|
|
47
|
+
const accountId = String(input.accountId || '').trim();
|
|
48
|
+
const accountLogin = String(input.accountLogin || '').trim();
|
|
49
|
+
const boundByUserId = String(input.boundByUserId || '').trim();
|
|
50
|
+
if (!installationId || !accountId || !accountLogin || !boundByUserId) {
|
|
51
|
+
throw new Error('Installation, account, and binding actor are required.');
|
|
52
|
+
}
|
|
53
|
+
const now = this.now().toISOString();
|
|
54
|
+
try {
|
|
55
|
+
this.db.prepare(`
|
|
56
|
+
INSERT INTO github_review_evidence_installation_bindings (
|
|
57
|
+
tenant_id, workspace_id, installation_id, account_id, account_login,
|
|
58
|
+
account_type, repository_selection, bound_by_user_id, created_at, updated_at
|
|
59
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
60
|
+
ON CONFLICT (tenant_id, workspace_id) DO UPDATE SET
|
|
61
|
+
installation_id = EXCLUDED.installation_id,
|
|
62
|
+
account_id = EXCLUDED.account_id,
|
|
63
|
+
account_login = EXCLUDED.account_login,
|
|
64
|
+
account_type = EXCLUDED.account_type,
|
|
65
|
+
repository_selection = EXCLUDED.repository_selection,
|
|
66
|
+
bound_by_user_id = EXCLUDED.bound_by_user_id,
|
|
67
|
+
updated_at = EXCLUDED.updated_at
|
|
68
|
+
`).run(this.tenantId, workspaceId, installationId, accountId, accountLogin, String(input.accountType || 'unknown').trim() || 'unknown', String(input.repositorySelection || 'selected').trim() || 'selected', boundByUserId, now, now);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = String(error?.message || '').toLowerCase();
|
|
72
|
+
if (message.includes('unique') || message.includes('duplicate')) {
|
|
73
|
+
throw new GitHubReviewEvidenceInstallationConflictError();
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
return this.get(workspaceId);
|
|
78
|
+
}
|
|
79
|
+
delete(workspaceId) {
|
|
80
|
+
const normalizedWorkspaceId = String(workspaceId || '').trim();
|
|
81
|
+
if (!normalizedWorkspaceId)
|
|
82
|
+
return false;
|
|
83
|
+
const result = this.db.prepare(`
|
|
84
|
+
DELETE FROM github_review_evidence_installation_bindings
|
|
85
|
+
WHERE tenant_id = ? AND workspace_id = ?
|
|
86
|
+
`).run(this.tenantId, normalizedWorkspaceId);
|
|
87
|
+
return Number(result?.changes || 0) > 0;
|
|
88
|
+
}
|
|
89
|
+
}
|