fix(core): Validate node name when creating NodeOperationErrror (#11999)

This commit is contained in:
Iván Ovejero 2024-12-02 12:43:25 +01:00 committed by GitHub
parent 0ffc8591a0
commit e68c9da30c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 58 additions and 6 deletions

View file

@ -0,0 +1,43 @@
import { mock } from 'jest-mock-extended';
import type { INode } from 'n8n-workflow';
import { NodeOperationError, type Workflow } from 'n8n-workflow';
import { objectToError } from '../workflow-execute-additional-data';
describe('objectToError', () => {
describe('node error handling', () => {
it('should create `NodeOperationError` when node is found', () => {
const errorObject = {
message: 'Test error',
node: {
name: 'testNode',
},
};
const workflow = mock<Workflow>();
const node = mock<INode>();
workflow.getNode.mockReturnValue(node);
const result = objectToError(errorObject, workflow);
expect(workflow.getNode).toHaveBeenCalledWith('testNode');
expect(result).toBeInstanceOf(NodeOperationError);
});
it('should create `Error` when node is not found', () => {
const errorObject = {
message: 'Test error',
node: {
// missing `name`
},
};
const workflow = mock<Workflow>();
const result = objectToError(errorObject, workflow);
expect(workflow.getNode).not.toHaveBeenCalled();
expect(result).toBeInstanceOf(Error);
expect(result).not.toBeInstanceOf(NodeOperationError);
expect(result.message).toBe('Test error');
});
});
});

View file

@ -58,7 +58,7 @@ export function isStringArray(value: unknown): value is string[] {
export const isIntegerString = (value: string) => /^\d+$/.test(value);
export function isObjectLiteral(item: unknown): item is { [key: string]: string } {
export function isObjectLiteral(item: unknown): item is { [key: string]: unknown } {
return typeof item === 'object' && item !== null && !Array.isArray(item);
}

View file

@ -52,7 +52,7 @@ import type { IWorkflowErrorData, UpdateExecutionPayload } from '@/interfaces';
import { NodeTypes } from '@/node-types';
import { Push } from '@/push';
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
import { findSubworkflowStart, isWorkflowIdValid } from '@/utils';
import { findSubworkflowStart, isObjectLiteral, isWorkflowIdValid } from '@/utils';
import * as WorkflowHelpers from '@/workflow-helpers';
import { WorkflowRepository } from './databases/repositories/workflow.repository';
@ -80,11 +80,20 @@ export function objectToError(errorObject: unknown, workflow: Workflow): Error {
if (errorObject instanceof Error) {
// If it's already an Error instance, return it as is.
return errorObject;
} else if (errorObject && typeof errorObject === 'object' && 'message' in errorObject) {
} else if (
isObjectLiteral(errorObject) &&
'message' in errorObject &&
typeof errorObject.message === 'string'
) {
// If it's an object with a 'message' property, create a new Error instance.
let error: Error | undefined;
if ('node' in errorObject) {
const node = workflow.getNode((errorObject.node as { name: string }).name);
if (
'node' in errorObject &&
isObjectLiteral(errorObject.node) &&
typeof errorObject.node.name === 'string'
) {
const node = workflow.getNode(errorObject.node.name);
if (node) {
error = new NodeOperationError(
node,
@ -95,7 +104,7 @@ export function objectToError(errorObject: unknown, workflow: Workflow): Error {
}
if (error === undefined) {
error = new Error(errorObject.message as string);
error = new Error(errorObject.message);
}
if ('description' in errorObject) {