Skip to content

[NAE-2450] Filter field PFQL support#454

Open
Retoocs wants to merge 6 commits into
release/6.5.0from
NAE-2450
Open

[NAE-2450] Filter field PFQL support#454
Retoocs wants to merge 6 commits into
release/6.5.0from
NAE-2450

Conversation

@Retoocs

@Retoocs Retoocs commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Description

  • removed prefix autocomplete when calling PFQL searches from ActionDelegate
  • updated QueryLang grammar to allow empty queries (cases, tasks, ...)
  • introduced PFQL search endpoints for Case and Task resource

Implements NAE-2450

Dependencies

No new dependencies were introduced

Third party dependencies

No new dependencies were introduced

Blocking Pull requests

There are no dependencies on other PR

How Has Been This Tested?

Manually and by unit tests

Test Configuration

Name Tested on
OS Ubuntu 24.04.1 LTS
Runtime Java 11
Dependency Manager Maven 3.6.3
Framework version Spring Boot 2.7.8
Run parameters
Other configuration

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes have been checked, personally or remotely, with @mazarijuraj
  • I have commented my code, particularly in hard-to-understand areas
  • I have resolved all conflicts with the target branch of the PR
  • I have updated and synced my code with the target branch
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes:
    • Lint test
    • Unit tests
    • Integration tests
  • I have checked my contribution with code analysis tools:
  • I have made corresponding changes to the documentation:
    • Developer documentation
    • User Guides
    • Migration Guides

Summary by CodeRabbit

  • New Features

    • Added PFQL search endpoints for tasks and cases with enhanced query parsing.
    • PFQL queries now support optional conditions (e.g., tasks: without filter criteria).
  • Bug Fixes

    • Improved error handling with proper HTTP status codes (400 Bad Request, 500 Internal Server Error).
    • Fixed authentication-aware search behavior for filtered queries.
  • Refactor

    • Consolidated exception handling across storage and search services.
    • Updated filter configurations to use PFQL query syntax instead of Elasticsearch strings.

Retoocs added 4 commits June 15, 2026 17:45
- create general throwable package
- make PFQL conditions optional
- update QueryLangEvaluator to generate empty database queries to find all documents
- implement new PFQL search endpoints
- update tests
- remove prefix autocomplete in ActionDelegate for PFQL methods
- implement PFQL endpoints dedicated for Elasticsearch
- update tests
- fix PFQL task search endpoint to interact only with Mongo database
- update tests to test permissions
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR extends PFQL grammar to make filter conditions optional, removes SearchUtils prefix normalization and all QUERY_SINGLE/MULTIPLE_PREFIX constants from search services, relocates BadRequestException to utils.throwable, adds a new InternalServerErrorException, introduces POST /search_pfql endpoints in task and workflow controllers, updates menu filter templates and XML configurations to use PFQL-based defaults, and adds comprehensive test coverage.

Changes

PFQL Optional Conditions, Prefix Removal, and New Search Endpoints

Layer / File(s) Summary
PFQL grammar optional conditions and evaluator handling
src/main/java/com/netgrif/application/engine/pfql/domain/antlr4/QueryLang.g4, src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java, src/main/java/com/netgrif/application/engine/pfql/service/QueryLangExplainEvaluator.java
QueryLang.g4 introduces four *ConditionsAndPaging subrules making conditions optional. QueryLangEvaluator adds handleNoneConditions() with default empty Mongo and wildcard Elastic query assignment. QueryLangExplainEvaluator conditionally populates the children list per exit method.
Removal of SearchUtils prefix normalization and QUERY_PREFIX constants
src/main/java/com/netgrif/application/engine/pfql/service/utils/SearchUtils.java, src/main/java/com/netgrif/application/engine/pfql/service/caseresource/CaseSearchService.java, .../processresource/ProcessSearchService.java, .../taskresource/TaskSearchService.java, .../userresource/UserSearchService.java, src/main/groovy/.../action/ActionDelegate.groovy
All ensureStartsWith* public methods and the queryPrefixes setup are removed from SearchUtils. Each search service drops its QUERY_SINGLE_PREFIX and QUERY_MULTIPLE_PREFIX constants. ActionDelegate removes the SearchUtils import and passes raw query strings directly to each search service.
BadRequestException relocation and new InternalServerErrorException
src/main/java/com/netgrif/application/engine/utils/throwable/BadRequestException.java, .../InternalServerErrorException.java, src/main/java/com/netgrif/application/engine/files/interfaces/IStorageService.java, .../local/LocalStorageService.java, .../minio/MinIoStorageService.java
BadRequestException moves to engine.utils.throwable and gains @ResponseStatus(HttpStatus.BAD_REQUEST). A new InternalServerErrorException is created with @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR). Storage service imports are updated to the new package.
New PFQL task search endpoint in task controllers
src/main/java/com/netgrif/application/engine/workflow/web/requestbodies/TaskSearchRequest.java, src/main/java/com/netgrif/application/engine/workflow/service/LegacyTaskSearchService.java, src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java, .../TaskController.java, .../PublicTaskController.java
TaskSearchRequest gains a query field. LegacyTaskSearchService.buildSingleQuery becomes public. AbstractTaskController is refactored with Lombok, adds LegacyTaskSearchService, reworks searchElastic and count to use elasticTaskService, and adds searchPfql with per-request PFQL predicate building and exception mapping. TaskController exposes POST /search_pfql. PublicTaskController is wired with the new service parameter.
New PFQL case search endpoint in WorkflowController
src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java
WorkflowController is refactored with @Slf4j and @RequiredArgsConstructor. A new POST /api/workflow/case/search_pfql endpoint evaluates PFQL queries via QueryLangEvaluator, calls elasticCaseService.search, and maps exceptions to BadRequestException or InternalServerErrorException.
Menu filter template updates for PFQL defaults
src/main/java/com/netgrif/application/engine/menu/domain/templates/Template.java, .../SingleTaskViewTemplate.java, src/main/resources/petriNets/engine-processes/menu/*.xml
Template.defaultTaskFilterBody() sets query to "tasks", defaultCaseFilterBody() sets query to "cases", and a new defaultSingleTaskFilterBody() sets query to "task". SingleTaskViewTemplate switches to defaultSingleTaskFilterBody(). XML configurations change filter init values from "*" to their respective PFQL selectors and update localized descriptions.
Test coverage for optional conditions, prefix removal, and authenticated queries
src/test/java/com/netgrif/application/engine/pfql/QueryLangTest.java, src/test/groovy/.../QueryLangActionTest.groovy, src/test/java/.../CaseSearchServiceTest.java, src/test/java/.../TaskSearchServiceTest.java, src/test/resources/petriNets/query_lang_test.xml
QueryLangTest adds "no comparison" base assertions, paging-without-filter, and sorting-without-filter cases, plus malformed/empty PFQL failure cases. QueryLangActionTest updates list-search assertions to plural selectors. CaseSearchServiceTest and TaskSearchServiceTest add authenticated login/logout flows asserting empty/null/false results. query_lang_test.xml gains a system role and transition roleRef.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • netgrif/application-engine#450: This PR directly extends the PFQL search infrastructure introduced in PR #450, removing the SearchUtils.ensureStartsWith* normalization and QUERY_PREFIX constants that were part of that implementation, and expanding the grammar and evaluator built there.

Suggested labels

improvement, new feature, breaking change, Large, Medium

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main change: implementing PFQL (Persistent Filter Query Language) support for filter fields, which is the core objective of this PR across multiple files and components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Retoocs Retoocs self-assigned this Jun 16, 2026
- simplify build of completePredicate
@Retoocs Retoocs marked this pull request as ready for review June 17, 2026 06:34

public Map<String, String> tags;

public String query;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Check ElasticTaskSearchRequest. There is also attribute query

@coderabbitai coderabbitai Bot added breaking change Fix or feature that would cause existing functionality doesn't work as expected improvement A change that improves on an existing feature Large Medium new feature A change that introduces new functionality labels Jun 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java`:
- Around line 160-162: The issue is that unconstrained queries on singular
resources (like task, case, user, process) are currently allowed and fall back
to full-scan results. Modify the null condition checks in the QueryLangEvaluator
class at the four locations (lines 160, 178, 196, and 214) to restrict the
handleNoneConditions() fallback to plural/multiple resources only. Before
calling handleNoneConditions() when ctx.processConditionsAndPaging() is null,
add a check to ensure that the query is for a multiple resource (multiple ==
true); if it is a singular resource (multiple == false), reject the query with
appropriate error handling instead of allowing it to proceed without conditions.

In
`@src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java`:
- Around line 192-204: The operation parameter of type MergeFilterOperation is
not being used when combining multiple search predicates in the searchPfql
method. Currently, the code hardcodes ExpressionUtils::and in the reduce
operation regardless of the operation parameter value. To fix this, replace the
hardcoded .reduce(ExpressionUtils::and) call with conditional logic that checks
the operation parameter and applies either AND or OR operation accordingly when
reducing the stream of predicates to create the completePredicate.

In
`@src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java`:
- Around line 137-141: The exception handling in the catch blocks for
IllegalArgumentException and generic Exception is discarding the original
exception information by not preserving it as the cause when throwing
BadRequestException and InternalServerErrorException. Modify both throw
statements to pass the caught exception e as the cause parameter to the
respective exception constructors (e.g., BadRequestException and
InternalServerErrorException), ensuring that stack-trace causality is preserved
for better production diagnostics and debugging.

In
`@src/test/java/com/netgrif/application/engine/pfql/CaseSearchServiceTest.java`:
- Around line 179-185: The login() and logout() methods in CaseSearchServiceTest
rely on explicit test invocation, meaning if a test fails after calling login(),
the logout() won't execute and authentication state will leak into subsequent
tests. Add an `@AfterEach` annotated cleanup method that unconditionally calls
SecurityContextHolder.getContext().clearContext() to ensure the SecurityContext
is reset after every test execution regardless of pass or fail status. This
replaces the current approach of manually calling logout() in individual tests.

In
`@src/test/java/com/netgrif/application/engine/pfql/TaskSearchServiceTest.java`:
- Around line 147-153: The login and logout methods in TaskSearchServiceTest
rely on manual logout calls to clear authentication, which creates a risk of
authentication state leaking to subsequent tests if an assertion fails before
logout is invoked. Add a new method annotated with `@AfterEach` that calls
SecurityContextHolder.clearContext() to ensure the SecurityContext is always
cleaned up after each test execution, regardless of whether the test passes or
fails, eliminating the dependency on the manual logout method being called.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 47744b06-9d39-4de2-8733-b13b1fbadb7a

📥 Commits

Reviewing files that changed from the base of the PR and between 53c7fde and 747f2fa.

📒 Files selected for processing (30)
  • src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy
  • src/main/java/com/netgrif/application/engine/files/interfaces/IStorageService.java
  • src/main/java/com/netgrif/application/engine/files/local/LocalStorageService.java
  • src/main/java/com/netgrif/application/engine/files/minio/MinIoStorageService.java
  • src/main/java/com/netgrif/application/engine/menu/domain/templates/SingleTaskViewTemplate.java
  • src/main/java/com/netgrif/application/engine/menu/domain/templates/Template.java
  • src/main/java/com/netgrif/application/engine/pfql/domain/antlr4/QueryLang.g4
  • src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java
  • src/main/java/com/netgrif/application/engine/pfql/service/QueryLangExplainEvaluator.java
  • src/main/java/com/netgrif/application/engine/pfql/service/caseresource/CaseSearchService.java
  • src/main/java/com/netgrif/application/engine/pfql/service/processresource/ProcessSearchService.java
  • src/main/java/com/netgrif/application/engine/pfql/service/taskresource/TaskSearchService.java
  • src/main/java/com/netgrif/application/engine/pfql/service/userresource/UserSearchService.java
  • src/main/java/com/netgrif/application/engine/pfql/service/utils/SearchUtils.java
  • src/main/java/com/netgrif/application/engine/utils/throwable/BadRequestException.java
  • src/main/java/com/netgrif/application/engine/utils/throwable/InternalServerErrorException.java
  • src/main/java/com/netgrif/application/engine/workflow/service/LegacyTaskSearchService.java
  • src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java
  • src/main/java/com/netgrif/application/engine/workflow/web/PublicTaskController.java
  • src/main/java/com/netgrif/application/engine/workflow/web/TaskController.java
  • src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java
  • src/main/java/com/netgrif/application/engine/workflow/web/requestbodies/TaskSearchRequest.java
  • src/main/resources/petriNets/engine-processes/menu/case_view_configuration.xml
  • src/main/resources/petriNets/engine-processes/menu/single_task_view_configuration.xml
  • src/main/resources/petriNets/engine-processes/menu/task_view_configuration.xml
  • src/test/groovy/com/netgrif/application/engine/pfql/QueryLangActionTest.groovy
  • src/test/java/com/netgrif/application/engine/pfql/CaseSearchServiceTest.java
  • src/test/java/com/netgrif/application/engine/pfql/QueryLangTest.java
  • src/test/java/com/netgrif/application/engine/pfql/TaskSearchServiceTest.java
  • src/test/resources/petriNets/query_lang_test.xml
💤 Files with no reviewable changes (6)
  • src/main/java/com/netgrif/application/engine/pfql/service/userresource/UserSearchService.java
  • src/main/java/com/netgrif/application/engine/pfql/service/processresource/ProcessSearchService.java
  • src/main/java/com/netgrif/application/engine/pfql/service/caseresource/CaseSearchService.java
  • src/test/groovy/com/netgrif/application/engine/pfql/QueryLangActionTest.groovy
  • src/main/java/com/netgrif/application/engine/pfql/service/utils/SearchUtils.java
  • src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy

Comment on lines +160 to +162
if (ctx.processConditionsAndPaging() == null || ctx.processConditionsAndPaging().processConditions() == null) {
handleNoneConditions();
} else {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent unconstrained single-resource queries from falling back to full-scan predicates.

Lines 160, 178, 196, and 214 currently route missing conditions to handleNoneConditions() for both plural and singular resources. That makes queries like task, case, user, process legal and unconstrained, so downstream single-result searches can return an arbitrary first match. Restrict this fallback to multiple == true and reject missing conditions for singular queries.

Suggested fix
@@
-        if (ctx.processConditionsAndPaging() == null || ctx.processConditionsAndPaging().processConditions() == null) {
-            handleNoneConditions();
+        if (ctx.processConditionsAndPaging() == null || ctx.processConditionsAndPaging().processConditions() == null) {
+            if (!multiple) {
+                throw new IllegalArgumentException("Single process query must contain conditions");
+            }
+            handleNoneConditions();
@@
-        if (ctx.caseConditionsAndPaging() == null || ctx.caseConditionsAndPaging().caseConditions() == null) {
-            handleNoneConditions();
+        if (ctx.caseConditionsAndPaging() == null || ctx.caseConditionsAndPaging().caseConditions() == null) {
+            if (!multiple) {
+                throw new IllegalArgumentException("Single case query must contain conditions");
+            }
+            handleNoneConditions();
@@
-        if (ctx.taskConditionsAndPaging() == null || ctx.taskConditionsAndPaging().taskConditions() == null) {
-            handleNoneConditions();
+        if (ctx.taskConditionsAndPaging() == null || ctx.taskConditionsAndPaging().taskConditions() == null) {
+            if (!multiple) {
+                throw new IllegalArgumentException("Single task query must contain conditions");
+            }
+            handleNoneConditions();
@@
-        if (ctx.userConditionsAndPaging() == null || ctx.userConditionsAndPaging().userConditions() == null) {
-            handleNoneConditions();
+        if (ctx.userConditionsAndPaging() == null || ctx.userConditionsAndPaging().userConditions() == null) {
+            if (!multiple) {
+                throw new IllegalArgumentException("Single user query must contain conditions");
+            }
+            handleNoneConditions();

Also applies to: 178-180, 196-198, 214-216

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/netgrif/application/engine/pfql/service/QueryLangEvaluator.java`
around lines 160 - 162, The issue is that unconstrained queries on singular
resources (like task, case, user, process) are currently allowed and fall back
to full-scan results. Modify the null condition checks in the QueryLangEvaluator
class at the four locations (lines 160, 178, 196, and 214) to restrict the
handleNoneConditions() fallback to plural/multiple resources only. Before
calling handleNoneConditions() when ctx.processConditionsAndPaging() is null,
add a check to ensure that the query is for a multiple resource (multiple ==
true); if it is a singular resource (multiple == false), reject the query with
appropriate error handling instead of allowing it to proceed without conditions.

Comment on lines +192 to +204
public PagedModel<LocalisedTaskResource> searchPfql(Authentication auth, Pageable pageable, SingleTaskSearchRequestAsList searchBody, MergeFilterOperation operation, PagedResourcesAssembler<Task> assembler, Locale locale) {
try {
Predicate completePredicate = searchBody.getList().stream()
.map((request) -> {
if (request.query == null || request.query.isEmpty()) {
return searchService.buildSingleQuery(request, (LoggedUser) auth.getPrincipal(), locale);
} else {
QueryLangEvaluator evaluator = SearchUtils.evaluateQuery(request.query);
return evaluator.getFullMongoQuery();
}
})
.reduce(ExpressionUtils::and).orElse(null);
Page<Task> tasks = taskService.search(completePredicate, pageable);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

operation is ignored when combining predicates (Line 203).

searchPfql always reduces with ExpressionUtils::and, so requests with operation=OR are evaluated as AND.

Proposed fix
-                    .reduce(ExpressionUtils::and).orElse(null);
+                    .reduce(operation == MergeFilterOperation.AND ? ExpressionUtils::and : ExpressionUtils::or)
+                    .orElse(null);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public PagedModel<LocalisedTaskResource> searchPfql(Authentication auth, Pageable pageable, SingleTaskSearchRequestAsList searchBody, MergeFilterOperation operation, PagedResourcesAssembler<Task> assembler, Locale locale) {
try {
Predicate completePredicate = searchBody.getList().stream()
.map((request) -> {
if (request.query == null || request.query.isEmpty()) {
return searchService.buildSingleQuery(request, (LoggedUser) auth.getPrincipal(), locale);
} else {
QueryLangEvaluator evaluator = SearchUtils.evaluateQuery(request.query);
return evaluator.getFullMongoQuery();
}
})
.reduce(ExpressionUtils::and).orElse(null);
Page<Task> tasks = taskService.search(completePredicate, pageable);
public PagedModel<LocalisedTaskResource> searchPfql(Authentication auth, Pageable pageable, SingleTaskSearchRequestAsList searchBody, MergeFilterOperation operation, PagedResourcesAssembler<Task> assembler, Locale locale) {
try {
Predicate completePredicate = searchBody.getList().stream()
.map((request) -> {
if (request.query == null || request.query.isEmpty()) {
return searchService.buildSingleQuery(request, (LoggedUser) auth.getPrincipal(), locale);
} else {
QueryLangEvaluator evaluator = SearchUtils.evaluateQuery(request.query);
return evaluator.getFullMongoQuery();
}
})
.reduce(operation == MergeFilterOperation.AND ? ExpressionUtils::and : ExpressionUtils::or)
.orElse(null);
Page<Task> tasks = taskService.search(completePredicate, pageable);
🧰 Tools
🪛 ast-grep (0.43.0)

[warning] 203-203: Avoid LDAP injections
Context: taskService.search(completePredicate, pageable)
Note: [CWE-90] Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection'). Security best practice.

(ldap-injection-java)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java`
around lines 192 - 204, The operation parameter of type MergeFilterOperation is
not being used when combining multiple search predicates in the searchPfql
method. Currently, the code hardcodes ExpressionUtils::and in the reduce
operation regardless of the operation parameter value. To fix this, replace the
hardcoded .reduce(ExpressionUtils::and) call with conditional logic that checks
the operation parameter and applies either AND or OR operation accordingly when
reducing the stream of predicates to create the completePredicate.

Comment on lines +137 to +141
} catch (IllegalArgumentException e) {
throw new BadRequestException("Bad request: " + e.getMessage());
} catch (Exception e) {
log.error("Something went wrong while searching cases by PFQL", e);
throw new InternalServerErrorException("Something went wrong");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve exception causes when mapping PFQL errors to HTTP exceptions.

Line 138 and Line 141 discard the original Throwable, which drops stack-trace causality and weakens production diagnostics.

Suggested patch
diff --git a/src/main/java/com/netgrif/application/engine/utils/throwable/InternalServerErrorException.java b/src/main/java/com/netgrif/application/engine/utils/throwable/InternalServerErrorException.java
@@
 public class InternalServerErrorException extends RuntimeException {
     public InternalServerErrorException(String message) {
         super(message);
     }
+
+    public InternalServerErrorException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
diff --git a/src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java b/src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java
@@
         } catch (IllegalArgumentException e) {
-            throw new BadRequestException("Bad request: " + e.getMessage());
+            throw new BadRequestException("Bad request: " + e.getMessage(), e);
         } catch (Exception e) {
             log.error("Something went wrong while searching cases by PFQL", e);
-            throw new InternalServerErrorException("Something went wrong");
+            throw new InternalServerErrorException("Something went wrong", e);
         }
🧰 Tools
🪛 PMD (7.25.0)

[Medium] 138-138: PreserveStackTrace (Best Practices): Thrown exception does not preserve the stack trace of exception 'e' on all code paths

(PreserveStackTrace (Best Practices))


[Medium] 141-141: PreserveStackTrace (Best Practices): Thrown exception does not preserve the stack trace of exception 'e' on all code paths

(PreserveStackTrace (Best Practices))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java`
around lines 137 - 141, The exception handling in the catch blocks for
IllegalArgumentException and generic Exception is discarding the original
exception information by not preserving it as the cause when throwing
BadRequestException and InternalServerErrorException. Modify both throw
statements to pass the caught exception e as the cause parameter to the
respective exception constructors (e.g., BadRequestException and
InternalServerErrorException), ensuring that stack-trace causality is preserved
for better production diagnostics and debugging.

Source: Linters/SAST tools

Comment on lines +179 to +185
private void login(LoggedUser loggedUser) {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(loggedUser, null));
}

private void logout() {
SecurityContextHolder.getContext().setAuthentication(null);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Harden SecurityContext cleanup to prevent cross-test leakage

Line 179–Line 185 cleanup is not failure-safe: if a test fails after login(...), logout() won’t run and auth state can leak into later tests. Add an @AfterEach cleanup and use clearContext().

Proposed fix
@@
-import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
@@
     `@BeforeEach`
     protected void beforeEach() {
         testHelper.truncateDbs();
         Optional<PetriNet> createdNetOpt = importHelper.createNet("/query_lang_test.xml");
         assertTrue(createdNetOpt.isPresent());
         testCase = importHelper.createCase("test", createdNetOpt.get());
     }
+
+    `@AfterEach`
+    protected void afterEach() {
+        SecurityContextHolder.clearContext();
+    }
@@
     private void logout() {
-        SecurityContextHolder.getContext().setAuthentication(null);
+        SecurityContextHolder.clearContext();
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/netgrif/application/engine/pfql/CaseSearchServiceTest.java`
around lines 179 - 185, The login() and logout() methods in
CaseSearchServiceTest rely on explicit test invocation, meaning if a test fails
after calling login(), the logout() won't execute and authentication state will
leak into subsequent tests. Add an `@AfterEach` annotated cleanup method that
unconditionally calls SecurityContextHolder.getContext().clearContext() to
ensure the SecurityContext is reset after every test execution regardless of
pass or fail status. This replaces the current approach of manually calling
logout() in individual tests.

Comment on lines +147 to +153
private void login(LoggedUser loggedUser) {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(loggedUser, null));
}

private void logout() {
SecurityContextHolder.getContext().setAuthentication(null);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add failure-safe SecurityContext teardown

Line 147–Line 153 relies on manual logout in test flow. If an assertion fails before logout(), authentication can leak to subsequent tests. Add @AfterEach with SecurityContextHolder.clearContext().

Proposed fix
@@
-import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
@@
     `@BeforeEach`
     protected void beforeEach() {
         testHelper.truncateDbs();
         Optional<PetriNet> createdNetOpt = importHelper.createNet("/query_lang_test.xml");
         assertTrue(createdNetOpt.isPresent());
         Case testCase = importHelper.createCase("test", createdNetOpt.get());
         testTaskId = testCase.getTasks().stream()
                 .filter(taskPair -> taskPair.getTransition().equals("t1"))
                 .map(TaskPair::getTask)
                 .findFirst().get();
     }
+
+    `@AfterEach`
+    protected void afterEach() {
+        SecurityContextHolder.clearContext();
+    }
@@
     private void logout() {
-        SecurityContextHolder.getContext().setAuthentication(null);
+        SecurityContextHolder.clearContext();
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/netgrif/application/engine/pfql/TaskSearchServiceTest.java`
around lines 147 - 153, The login and logout methods in TaskSearchServiceTest
rely on manual logout calls to clear authentication, which creates a risk of
authentication state leaking to subsequent tests if an assertion fails before
logout is invoked. Add a new method annotated with `@AfterEach` that calls
SecurityContextHolder.clearContext() to ensure the SecurityContext is always
cleaned up after each test execution, regardless of whether the test passes or
fails, eliminating the dependency on the manual logout method being called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Fix or feature that would cause existing functionality doesn't work as expected improvement A change that improves on an existing feature Large Medium new feature A change that introduces new functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant