diff --git a/packages/components/nodes/agentflow/Condition/Condition.test.ts b/packages/components/nodes/agentflow/Condition/Condition.test.ts new file mode 100644 index 00000000000..b3a44f84e9f --- /dev/null +++ b/packages/components/nodes/agentflow/Condition/Condition.test.ts @@ -0,0 +1,93 @@ +import { nodeClass as Condition_Agentflow } from './Condition' +import { INodeData, INode, ICondition } from '../../../src/Interface' + +function createNodeData(inputs: any): INodeData { + return { + id: 'condition-node', + label: 'Condition', + name: 'conditionAgentflow', + type: 'Condition', + icon: 'condition.svg', + version: 1.0, + category: 'Agent Flows', + baseClasses: ['Condition'], + inputs + } +} + +describe('Condition Agentflow', () => { + let nodeClass: any + + beforeEach(() => { + nodeClass = new Condition_Agentflow() + }) + + it('should match regex operation for string conditions', async () => { + const nodeData = createNodeData({ + conditions: [ + { + type: 'string', + value1: 'Hello123', + operation: 'regex', + value2: '^Hello\\d+$' + } + ] + }) + + const result = await nodeClass.run(nodeData, '', { agentflowRuntime: { state: {} } }) + const matchedCondition = result.output.conditions.find( + (condition: any) => condition.operation === 'regex' && condition.value1 === 'Hello123' && condition.value2 === '^Hello\\d+$' + ) + const elseCondition = result.output.conditions.find( + (condition: any) => condition.operation === 'equal' && condition.value1 === '' && condition.value2 === '' + ) + expect(matchedCondition?.isFulfilled).toBe(true) + expect(elseCondition?.isFulfilled).toBe(false) + }) + + it('should return false for invalid regex patterns', async () => { + const nodeData = createNodeData({ + conditions: [ + { + type: 'string', + value1: 'Hello123', + operation: 'regex', + value2: '[invalid' + } + ] + }) + + const result = await nodeClass.run(nodeData, '', { agentflowRuntime: { state: {} } }) + const matchedCondition = result.output.conditions.find( + (condition: any) => condition.operation === 'regex' && condition.value1 === 'Hello123' && condition.value2 === '[invalid' + ) + const elseCondition = result.output.conditions.find( + (condition: any) => condition.operation === 'equal' && condition.value1 === '' && condition.value2 === '' + ) + expect(matchedCondition?.isFulfilled).toBe(false) + expect(elseCondition?.isFulfilled).toBe(true) + }) + + it('should return false when regex exceeds safety limits', async () => { + const nodeData = createNodeData({ + conditions: [ + { + type: 'string', + value1: 'Hello123', + operation: 'regex', + value2: 'a'.repeat(300) + } + ] + }) + + const result = await nodeClass.run(nodeData, '', { agentflowRuntime: { state: {} } }) + const matchedCondition = result.output.conditions.find( + (condition: any) => condition.operation === 'regex' && condition.value2 === 'a'.repeat(300) + ) + const elseCondition = result.output.conditions.find( + (condition: any) => condition.operation === 'equal' && condition.value1 === '' && condition.value2 === '' + ) + expect(matchedCondition?.isFulfilled).toBeFalsy() + expect(elseCondition?.isFulfilled).toBe(true) + }) +}) diff --git a/packages/components/nodes/agentflow/Condition/Condition.ts b/packages/components/nodes/agentflow/Condition/Condition.ts index 7ae1be06291..4a39acfa509 100644 --- a/packages/components/nodes/agentflow/Condition/Condition.ts +++ b/packages/components/nodes/agentflow/Condition/Condition.ts @@ -270,6 +270,33 @@ class Condition_Agentflow implements INode { endsWith: (value1: CommonType, value2: CommonType) => (value1 as string).endsWith(value2 as string), equal: (value1: CommonType, value2: CommonType) => value1 === value2, notEqual: (value1: CommonType, value2: CommonType) => value1 !== value2, + regex: (value1: CommonType, value2: CommonType) => { + const MAX_PATTERN_LENGTH = 256 + const MAX_INPUT_LENGTH = 10000 + const pattern = (value2 ?? '').toString() + const input = (value1 ?? '').toString() + if (pattern.length > MAX_PATTERN_LENGTH || input.length > MAX_INPUT_LENGTH) { + console.warn( + '[Condition_Agentflow] Regex condition skipped due to safety limits:', + { + patternLength: pattern.length, + inputLength: input.length, + maxPatternLength: 256, + maxInputLength: 10000 + } + ) + return false + } + try { + return new RegExp(pattern).test(input) + } catch (e) { + console.warn('[Condition_Agentflow] Invalid regex pattern in condition.', { + error: (e as Error)?.message, + pattern + }) + return false + } + }, larger: (value1: CommonType, value2: CommonType) => (Number(value1) || 0) > (Number(value2) || 0), largerEqual: (value1: CommonType, value2: CommonType) => (Number(value1) || 0) >= (Number(value2) || 0), smaller: (value1: CommonType, value2: CommonType) => (Number(value1) || 0) < (Number(value2) || 0),