Skip to content

[backend] feat(chaining): step CRUD (#4824)#5243

Open
camrrx wants to merge 8 commits intorelease/currentfrom
issue/4824-step-crud
Open

[backend] feat(chaining): step CRUD (#4824)#5243
camrrx wants to merge 8 commits intorelease/currentfrom
issue/4824-step-crud

Conversation

@camrrx
Copy link
Copy Markdown
Member

@camrrx camrrx commented Mar 25, 2026

Proposed changes

  • In the new chaining it will be possible to create action (step) and event (conditions), on this PR I've done the CRUD of the step and the conditions (StepApi and ConditionApi).

Testing Instructions

  1. Create a workflow : Before creating steps or conditions, you need a workflow_id.
  2. Use postman for the following requests
  3. Create a step : POST localhost:3001/api/chaining/steps
{
 "workflow_id": "workflow-id",
 "step_action": "INJECT_EXECUTION",
 "limit_execution": 1,
 "data_step": {
   "type": "inject",
   "inject_title": "Inject",
   "inject_injector_contract": "injector_contract_id",
   "inject_enabled": true
 }
}
  1. Create a condition linked to the step : POST localhost:3001/api/chaining/conditions
    use the previously created step id as step_from
{
  "name": "blablaEvent",
  "description": "blabla description",
  "workflow_id": "workflow-id",
  "step_from": "step_id",
  "conditions": [
    { "temporary_id": "123", "type": "AND" },
    { "temporary_id": "0", "temporary_id_condition_parent": "123", "key_type": "text", "type": "IS_NOT_NULL"},
    { "temporary_id": "1", "temporary_id_condition_parent": "123", "key_type": "portscan.port", "type": "EQ", "value": "10" }
  ]
}
  1. Create a steo triggered by the condition : use the id of the root condition created above (condition_id)
{
  "workflow_id": "workflow-id",
  "step_action": "INJECT_EXECUTION",
  "limit_execution": 1,
  "condition_ids":["condition_id"],
  "data_step": {
    "type": "inject",
    "inject_title": "Step 2",
    "inject_injector_contract": "injector_contract_id",
    "inject_enabled": true
  }
}
  1. At this point, you should have :
Capture d’écran 2026-03-25 à 16 52 43
  1. You can now try to update / delete conditions and steps

Related issues

Checklist

  • I consider the submitted work as finished
  • I tested the code for its functionality
  • I wrote test cases for the relevant uses case
  • I added/update the relevant documentation (either on github or on notion)
  • Where necessary I refactored code to improve the overall quality
  • For bug fix -> I implemented a test that covers the bug

Further comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...

@github-actions github-actions bot added the filigran team use to identify PR from the Filigran team label Mar 25, 2026
@camrrx camrrx changed the title [backend] feature(chaining): Step CRUD [backend] feature(chaining): Step CRUD (#4824) Mar 25, 2026
@camrrx camrrx changed the title [backend] feature(chaining): Step CRUD (#4824) [backend] feature(chaining): step CRUD (#4824) Mar 25, 2026
@camrrx camrrx changed the title [backend] feature(chaining): step CRUD (#4824) [backend] feat(chaining): step CRUD (#4824) Mar 25, 2026
@camrrx camrrx marked this pull request as ready for review March 25, 2026 16:14
@heditar heditar self-requested a review March 26, 2026 08:26
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 87.11864% with 38 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.40%. Comparing base (8fc9a21) to head (90db769).

Files with missing lines Patch % Lines
.../io/openaev/service/chaining/ConditionService.java 84.39% 12 Missing and 10 partials ⚠️
...main/java/io/openaev/api/chaining/ChainingApi.java 0.00% 9 Missing ⚠️
.../java/io/openaev/api/chaining/dto/EventMapper.java 86.95% 0 Missing and 6 partials ⚠️
...n/java/io/openaev/api/chaining/dto/StepMapper.java 88.88% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@                  Coverage Diff                  @@
##             release/current    #5243      +/-   ##
=====================================================
+ Coverage              60.25%   60.40%   +0.14%     
- Complexity              5248     5304      +56     
=====================================================
  Files                   1053     1059       +6     
  Lines                  32148    32365     +217     
  Branches                2411     2428      +17     
=====================================================
+ Hits                   19371    19550     +179     
- Misses                 11696    11718      +22     
- Partials                1081     1097      +16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements initial CRUD APIs for the new chaining engine’s step templates and condition trees (events), including the underlying model refactor to support a condition↔step join table and updated DTOs/tests/front-end types.

Changes:

  • Add /api/chaining/steps, /api/chaining/conditions, and aggregated /api/chaining endpoints with new DTOs/mappers.
  • Refactor ConditionStep association via new ConditionStep join entity + Flyway migration to evolve conditions schema.
  • Update chaining services and tests to use StepInput and key_type semantics.

Reviewed changes

Copilot reviewed 30 out of 31 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
openaev-model/src/main/java/io/openaev/database/repository/ConditionRepository.java Adds join-table based query for conditions linked to a step and root-condition query by workflow.
openaev-model/src/main/java/io/openaev/database/model/Step.java Adds join-table relation to ConditionStep and helper accessor for linked conditions.
openaev-model/src/main/java/io/openaev/database/model/ConditionStep.java Introduces join entity for condition↔step links (with is_root).
openaev-model/src/main/java/io/openaev/database/model/Condition.java Refactors condition fields (workflow/name/desc/key_type), adds join-table links + backward-compatible accessors.
openaev-front/src/utils/api-types.d.ts Updates generated API types for steps/events/conditions payloads & outputs.
openaev-api/src/test/java/io/openaev/utils/fixtures/ConditionFixture.java Updates fixture to use keyType instead of legacy key.
openaev-api/src/test/java/io/openaev/service/chaining/StepServiceTest.java Migrates tests to StepInput and adds CRUD-focused unit tests.
openaev-api/src/test/java/io/openaev/service/chaining/StepServiceIntegrationTest.java Migrates integration tests to StepInput and keyType.
openaev-api/src/test/java/io/openaev/service/chaining/ConditionServiceTest.java Adds tests for linking/unlinking conditions↔steps and condition tree create/update helpers.
openaev-api/src/test/java/io/openaev/database/model/ConditionRepositoryTest.java Updates assertions to use getKeyType().
openaev-api/src/test/java/io/openaev/api/chaining/StepApiTest.java Adds controller unit tests for Step API.
openaev-api/src/test/java/io/openaev/api/chaining/InjectExecutionStepTest.java Updates helper conversion method and mapper-condition key usage (keyType).
openaev-api/src/test/java/io/openaev/api/chaining/ConditionApiTest.java Adds controller unit tests for Condition API.
openaev-api/src/main/java/io/openaev/service/chaining/StepService.java Adds step-template CRUD methods and updates condition template building to use new mapper/link model.
openaev-api/src/main/java/io/openaev/service/chaining/ConditionService.java Adds condition-tree CRUD + linking/unlinking logic and refactors condition evaluation helpers.
openaev-api/src/main/java/io/openaev/migration/V4_79__Update_conditions_for_condition_tree.java Migrates schema to support condition trees + join table and new condition columns.
openaev-api/src/main/java/io/openaev/api/chaining/dto/StepsCreateInput.java Removes old step creation DTO in favor of StepInput.
openaev-api/src/main/java/io/openaev/api/chaining/dto/StepOutput.java Adds output DTO for step template CRUD.
openaev-api/src/main/java/io/openaev/api/chaining/dto/StepMapper.java Adds mapper from Step entity to StepOutput.
openaev-api/src/main/java/io/openaev/api/chaining/dto/StepInput.java Adds input DTO for step template create/update, including condition linking.
openaev-api/src/main/java/io/openaev/api/chaining/dto/EventOutput.java Adds output DTO representing an “event” (root condition tree).
openaev-api/src/main/java/io/openaev/api/chaining/dto/EventMapper.java Adds mapper between condition trees and event DTOs, plus input→entity mapping helpers.
openaev-api/src/main/java/io/openaev/api/chaining/dto/EventInput.java Adds input DTO for event/condition-tree create/update.
openaev-api/src/main/java/io/openaev/api/chaining/dto/ConditionOutput.java Adds nested condition DTO for event output.
openaev-api/src/main/java/io/openaev/api/chaining/dto/ConditionCreateInput.java Renames input field keykey_type and reshuffles temp-parent fields.
openaev-api/src/main/java/io/openaev/api/chaining/dto/ChainingOutput.java Adds aggregated output DTO for conditions + steps.
openaev-api/src/main/java/io/openaev/api/chaining/StepApi.java Introduces REST controller for step template CRUD.
openaev-api/src/main/java/io/openaev/api/chaining/InjectExecutionStep.java Updates ActionStep implementation to accept StepInput and new key field.
openaev-api/src/main/java/io/openaev/api/chaining/ConditionApi.java Introduces REST controller for condition tree CRUD (“events”).
openaev-api/src/main/java/io/openaev/api/chaining/ChainingApi.java Adds aggregated read endpoint returning all steps + condition trees.
openaev-api/src/main/java/io/openaev/api/chaining/ActionStep.java Updates ActionStep interface to use StepInput.

Comment on lines +169 to 171
public void deleteConditionTree(String conditionRootId) {
conditionRepository.deleteById(conditionRootId);
}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleteConditionTree() calls conditionRepository.deleteById(). If the ID doesn't exist, Spring Data typically throws EmptyResultDataAccessException, which isn't handled by RestBehavior and will likely surface as a 500 instead of the documented 404. Consider checking existence first or translating the exception to EntityNotFoundException.

Copilot uses AI. Check for mistakes.
Comment on lines +427 to +431
List<Step> steps = stepRepository.findAllById(stepIds);
if (steps.size() != stepIds.size()) {
List<String> found = steps.stream().map(Step::getId).toList();
List<String> missing = stepIds.stream().filter(id -> !found.contains(id)).toList();
throw new EntityNotFoundException("Steps not found: " + missing);
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

linkStepsToRoot() compares steps.size() with stepIds.size() to detect missing steps. If stepIds contains duplicates, this will incorrectly report missing steps even when all IDs exist. De-duplicate stepIds before querying/validating (e.g., via LinkedHashSet) and compute missing IDs against that de-duplicated list.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +23
@Query(
"""
SELECT c
FROM Condition c
JOIN c.conditionSteps cs
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This repository method is now implemented via a custom @Query joining conditionSteps, but the name findAllByStep_Id still reads like a derived query on a (now removed) "step" property. Renaming it (e.g., findAllLinkedToStepId) would reduce confusion and avoid accidental future misuse.

Copilot uses AI. Check for mistakes.
import io.hypersistence.utils.hibernate.type.json.JsonType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.*;
import jakarta.persistence.CascadeType;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step.java imports jakarta.persistence.* and also explicitly imports jakarta.persistence.CascadeType, which is redundant. Consider removing the explicit CascadeType import to keep imports clean and avoid confusion about what's actually used.

Suggested change
import jakarta.persistence.CascadeType;

Copilot uses AI. Check for mistakes.
if (ConditionType.MAPPER.equals(condition.getType())) {

Map<String, Object> input = new HashMap<>();
input.put("key", condition.getKey());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key to keep

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept the key, I just renamed it to keyType

private String value;
@Column(name = "condition_key_type")
@Schema(description = "Key type")
private String keyType;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an Enum related to each type of output available

@JsonProperty("key")
private String key;
@JsonProperty("key_type")
private String keyType;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an Enum related to each type of output available

* condition.
*/
@JsonProperty("step_from")
String stepFrom;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this stepFrom needed here? Isn’t the one in the Condition sufficient?

@ApiResponses({
@ApiResponse(responseCode = "200", description = "Chaining data retrieved successfully")
})
@AccessControl(actionPerformed = Action.READ, resourceType = ResourceType.SIMULATION_OR_SCENARIO)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it is, it is not going to work with RBAC, but I will create a task to implement whats is needed for the RBAC on these APIs

log.error(
String.format(
"Unexpected error while creating a new Steps Workflow: %s", e.getMessage()));
return null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we returning null here ?

private String id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "condition_id", nullable = false)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need cascade here?

@camrrx camrrx force-pushed the issue/4824-step-crud branch from 90db769 to 3c90921 Compare March 30, 2026 07:18
@camrrx camrrx force-pushed the issue/4824-step-crud branch from 0ceec25 to 1d14acc Compare March 30, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

filigran team use to identify PR from the Filigran team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants