Add configurable recursion depth limit for Call Activities

Call Activities can create infinite loops through direct recursion (Process A calls itself) or indirect cycles (Process A → Process B → Process A), causing StackOverflowError and database exhaustion.

Changes

  • Configuration: Added maxCallActivityRecursionDepth property to ProcessEngineConfigurationImpl (default: 10, disable with ≤0)

  • Cycle detection: Before subprocess instantiation, CallActivityBehavior.checkCallActivityRecursion() traverses the superExecution chain to detect if the target process definition key already exists in the call hierarchy

  • Depth enforcement: Rejects calls when currentDepth + 1 > maxDepth to prevent excessively deep non-cyclic hierarchies

  • Case calls: Applied identical logic to CaseCallActivityBehavior for CMMN case invocations

Error messages

Cycles include full call chain for debugging:

Recursive Call Activity detected: Process 'processA' is already present in the call hierarchy.
Current call chain: processB -> processA -> processB (cycle detected at depth 2).
Configure 'maxCallActivityRecursionDepth' in ProcessEngineConfiguration to adjust the limit.

Depth violations show what would exceed limit:

Call Activity recursion depth limit exceeded: Maximum depth is 3, current depth is 3.
Attempting to call: processD. Current call chain: processA -> processB -> processC.

Configuration example

ProcessEngineConfiguration config = ...
config.setMaxCallActivityRecursionDepth(5);  // Allow up to 5 processes in hierarchy
config.setMaxCallActivityRecursionDepth(0);  // Disable check entirely

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • artifacts.cibseven.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.11/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.11/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.11 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.11/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/cibseven/cibseven org.codehaus.plexus.classworlds.launcher.Launcher clean test -Dtest=CallActivityRecursionTest -DfailIfNoTests=false (dns block)
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.11/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.11/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.11 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.11/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/cibseven/cibseven org.codehaus.plexus.classworlds.launcher.Launcher clean install -DskipTests -pl engine -am (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Problem

When using Call Activities in BPMN processes, it's possible to create recursive or cyclic process calls that lead to infinite loops:

  • Direct recursion: Process A calls itself via a Call Activity
  • Indirect recursion: Process A → calls Process B → calls Process A → calls Process B → ... (endless cycle)

Currently, the CIB Seven engine does not detect or prevent such recursive call chains. This can lead to:

  • StackOverflowError crashes
  • Database exhaustion (endless process instance creation)
  • System instability

Proposed Solution

Implement a configurable recursion depth limit for Call Activities that:

  1. Tracks the call hierarchy by walking up the superExecution chain when a Call Activity is about to start a subprocess
  2. Detects cycles by checking if the target ProcessDefinition (by key) already exists in the current call chain
  3. Enforces a maximum depth to prevent excessively deep (even non-cyclic) call hierarchies
  4. Is configurable via ProcessEngineConfiguration

Implementation Details

1. New Configuration Property

Add a new property to ProcessEngineConfigurationImpl:

protected int maxCallActivityRecursionDepth = 10; // default value, 0 or -1 = disabled

public int getMaxCallActivityRecursionDepth() { ... }
public void setMaxCallActivityRecursionDepth(int maxCallActivityRecursionDepth) { ... }

2. Recursion Check in CallActivityBehavior

Modify CallActivityBehavior.startInstance() in engine/src/main/java/org/cibseven/bpm/engine/impl/bpmn/behavior/CallActivityBehavior.java:

Before starting the subprocess, traverse the superExecution chain and:

  • Count the current depth
  • Collect all ProcessDefinition keys in the chain
  • Throw a ProcessEngineException if:
    • The target process key is already in the chain (cycle detected), OR
    • The maximum recursion depth is exceeded

3. Similar Check for CaseCallActivityBehavior

Apply the same logic to CaseCallActivityBehavior for CMMN case calls if applicable.

4. Unit Tests

Create tests that verify:

  • Direct recursion (Process A → Process A) is detected and prevented
  • Indirect recursion (Process A → Process B → Process A) is detected and prevented
  • Deep but non-cyclic call chains work up to the configured limit
  • The limit can be disabled by setting it to 0 or -1
  • Appropriate error messages are thrown

Example Error Message

ProcessEngineException: Recursive Call Activity detected: Process 'processA' is already present in the call hierarchy. 
Current call chain: processB -> processA -> processB (cycle detected at depth 2).
Configure 'maxCallActivityRecursionDepth' in ProcessEngineConfiguration to adjust the limit.

Acceptance Criteria

  • New configuration property maxCallActivityRecursionDepth added to ProcessEngineConfigurationImpl
  • Recursion check implemented in CallActivityBehavior.startInstance()
  • Clear and helpful exception message when recursion is detected
  • Unit tests for direct recursion, indirect recursion, and depth limit
  • Documentation updated (if applicable)

Related Code Locations

  • engine/src/main/java/org/cibseven/bpm/engine/impl/bpmn/behavior/CallActivityBehavior.java - Main implementation
  • engine/src/main/java/org/cibseven/bpm/engine/impl/cfg/ProcessEngineConfigurationImpl.java - Configuration
  • engine/src/main/java/org/cibseven/bpm/engine/impl/persistence/entity/ExecutionEntity.java - getSuperExecution() for hierarchy traversal
  • engine/src/test/java/org/cibseven/bpm/engine/test/bpmn/callactivity/CallActivityTest.java - Existing tests to extend

This pull request was created as a result of the following prompt from Copilot chat.

Problem

When using Call Activities in BPMN processes, it's possible to create recursive or cyclic process calls that lead to infinite loops:

  • Direct recursion: Process A calls itself via a Call Activity
  • Indirect recursion: Process A → calls Process B → calls Process A → calls Process B → ... (endless cycle)

Currently, the CIB Seven engine does not detect or prevent such recursive call chains. This can lead to:

  • StackOverflowError crashes
  • Database exhaustion (endless process instance creation)
  • System instability

Proposed Solution

Implement a configurable recursion depth limit for Call Activities that:

  1. Tracks the call hierarchy by walking up the superExecution chain when a Call Activity is about to start a subprocess
  2. Detects cycles by checking if the target ProcessDefinition (by key) already exists in the current call chain
  3. Enforces a maximum depth to prevent excessively deep (even non-cyclic) call hierarchies
  4. Is configurable via ProcessEngineConfiguration

Implementation Details

1. New Configuration Property

Add a new property to ProcessEngineConfigurationImpl:

protected int maxCallActivityRecursionDepth = 10; // default value, 0 or -1 = disabled

public int getMaxCallActivityRecursionDepth() { ... }
public void setMaxCallActivityRecursionDepth(int maxCallActivityRecursionDepth) { ... }

2. Recursion Check in CallActivityBehavior

Modify CallActivityBehavior.startInstance() in engine/src/main/java/org/cibseven/bpm/engine/impl/bpmn/behavior/CallActivityBehavior.java:

Before starting the subprocess, traverse the superExecution chain and:

  • Count the current depth
  • Collect all ProcessDefinition keys in the chain
  • Throw a ProcessEngineException if:
    • The target process key is already in the chain (cycle detected), OR
    • The maximum recursion depth is exceeded

3. Similar Check for CaseCallActivityBehavior

Apply the same logic to CaseCallActivityBehavior for CMMN case calls if applicable.

4. Unit Tests

Create tests that verify:

  • Direct recursion (Process A → Process A) is detected and prevented
  • Indirect recursion (Process A → Process B → Process A) is detected and prevented
  • Deep but non-cyclic call chains work up to the configured limit
  • The limit can be disabled by setting it to 0 or -1
  • Appropriate error messages are thrown

Example Error Message

ProcessEngineException: Recursive Call Activity detected: Process 'processA' is already present in the call hierarchy. 
Current call chain: processB -> processA -> processB (cycle detected at depth 2).
Configure 'maxCallActivityRecursionDepth' in ProcessEngineConfiguration to adjust the limit.

Acceptance Criteria

  • New configuration property maxCallActivityRecursionDepth added to ProcessEngineConfigurationImpl
  • Recursion check implemented in CallActivityBehavior.startInstance()
  • Clear and helpful exception message when recursion is detected
  • Unit tests for direct recursion, indirect recursion, and depth limit
  • Documentation updated (if applicable)

Related Code Locations

  • engine/src/main/java/org/cibseven/bpm/engine/impl/bpmn/behavior/CallActivityBehavior.java - Main implementation
  • engine/src/main/java/org/cibseven/bpm/engine/impl/cfg/ProcessEngineConfigurationImpl.java - Configuration
  • engine/src/main/java/org/cibseven/bpm/engine/impl/persistence/entity/ExecutionEntity.java - getSuperExecution() for hierarchy traversal
  • engine/src/test/java/org/cibseven/bpm/engine/test/bpmn/callactivity/CallActivityTest.java - Existing tests to extend

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Merge request reports

Loading