From b6497882ebad25e8cbfb3b08fab41a210358916f Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Mon, 2 Sep 2024 16:01:04 +0200 Subject: [PATCH] Prevent workflow version from bad update --- .../query-hooks/workflow-query-hook.module.ts | 14 ++++++ ...kflow-version-update-one.pre-query-hook.ts | 28 ++++++++++++ .../workflow-version-validation.exception.ts | 11 +++++ ...ow-version-validation.workspace-service.ts | 43 +++++++++++++++++++ .../workflow/common/workflow-common.module.ts | 2 + .../workflow-common.workspace-service.ts | 7 +++ 6 files changed, 105 insertions(+) create mode 100644 packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts create mode 100644 packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook.ts create mode 100644 packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception.ts create mode 100644 packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service.ts diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts new file mode 100644 index 000000000000..e280459ec369 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; + +import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook'; +import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; + +@Module({ + providers: [ + WorkflowVersionUpdateOnePreQueryHook, + WorkflowVersionValidationWorkspaceService, + WorkflowCommonWorkspaceService, + ], +}) +export class WorkflowQueryHookModule {} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook.ts new file mode 100644 index 000000000000..ffdde1a922f2 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook.ts @@ -0,0 +1,28 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service'; +import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; + +@WorkspaceQueryHook(`workflowVersion.updateOne`) +export class WorkflowVersionUpdateOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor( + private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, + ) {} + + async execute( + _authContext: AuthContext, + _objectName: string, + payload: UpdateOneResolverArgs, + ): Promise> { + await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForUpdateOne( + payload, + ); + + return payload; + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception.ts new file mode 100644 index 000000000000..b37d23ee9d93 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception.ts @@ -0,0 +1,11 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class WorkflowVersionValidationException extends CustomException { + constructor(message: string, code: WorkflowVersionValidationExceptionCode) { + super(message, code); + } +} + +export enum WorkflowVersionValidationExceptionCode { + FORBIDDEN = 'FORBIDDEN', +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service.ts new file mode 100644 index 000000000000..88aa0d76f145 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@nestjs/common'; + +import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { + WorkflowVersionValidationException, + WorkflowVersionValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception'; +import { + WorkflowVersionStatus, + WorkflowVersionWorkspaceEntity, +} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; + +@Injectable() +export class WorkflowVersionValidationWorkspaceService { + constructor( + private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService, + ) {} + + async validateWorkflowVersionForUpdateOne( + payload: UpdateOneResolverArgs, + ) { + const workflowVersion = + await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail( + payload.id, + ); + + if (workflowVersion.status !== WorkflowVersionStatus.DRAFT) { + throw new WorkflowVersionValidationException( + 'Only draft workflow versions can be updated', + WorkflowVersionValidationExceptionCode.FORBIDDEN, + ); + } + + if (payload.data.status !== workflowVersion.status) { + throw new WorkflowVersionValidationException( + 'Cannot update workflow version status manually', + WorkflowVersionValidationExceptionCode.FORBIDDEN, + ); + } + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts b/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts index 009da5aa8119..dfa97d4f7b80 100644 --- a/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts +++ b/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts @@ -1,8 +1,10 @@ import { Module } from '@nestjs/common'; +import { WorkflowQueryHookModule } from 'src/modules/workflow/common/query-hooks/workflow-query-hook.module'; import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; @Module({ + imports: [WorkflowQueryHookModule], providers: [WorkflowCommonWorkspaceService], exports: [WorkflowCommonWorkspaceService], }) diff --git a/packages/twenty-server/src/modules/workflow/common/workflow-common.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/workflow-common.workspace-service.ts index 9d325f01bceb..6cc0478e265c 100644 --- a/packages/twenty-server/src/modules/workflow/common/workflow-common.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/common/workflow-common.workspace-service.ts @@ -17,6 +17,13 @@ export class WorkflowCommonWorkspaceService { trigger: WorkflowTrigger; } > { + if (!workflowVersionId) { + throw new WorkflowTriggerException( + 'Workflow version ID is required', + WorkflowTriggerExceptionCode.INVALID_INPUT, + ); + } + const workflowVersionRepository = await this.twentyORMManager.getRepository( 'workflowVersion',