Skip to content

[NAE 2424] UserRefs negative view permissions aren't resolved#442

Open
SamuelPalaj wants to merge 6 commits into
release/6.5.0from
NAE-2424
Open

[NAE 2424] UserRefs negative view permissions aren't resolved#442
SamuelPalaj wants to merge 6 commits into
release/6.5.0from
NAE-2424

Conversation

@SamuelPalaj
Copy link
Copy Markdown
Contributor

@SamuelPalaj SamuelPalaj commented May 25, 2026

Description

Refactor of task view permission query resolution for both elastic and mongo search

Fixes NAE-2424

How Has Been This Tested?

Test included in test file TaskPermissionsTest

Name Tested on
OS windows 11
Runtime java 11
Dependency Manager Maven 3.9.9
Framework version Spring Boot 2.7.18
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 @...
  • 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

  • Bug Fixes

    • Improved handling of view permissions and negative permission constraints for task visibility.
    • Enhanced consistency between search backends for permission-based filtering.
  • Tests

    • Added comprehensive test coverage for permission-based task visibility across multiple implementations.

Review Change Stack

SamuelPalaj and others added 5 commits May 13, 2026 08:42
- negativeViewUsers resolution fix in Case and Task
- added test TaskPermissionsTest with test nets view_permission_combinations.xml and view_permission_combinations_no_default.xml
- fix typo in role id
- refactored task view permission query resolution for both elastic search in ElasticViewPermissionService and for mongo in TaskSearchService
- added mongo search test to TaskPermissionsTest
# Conflicts:
#	src/main/java/com/netgrif/application/engine/elastic/service/ElasticViewPermissionService.java
#	src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java
#	src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java
@SamuelPalaj SamuelPalaj self-assigned this May 25, 2026
@SamuelPalaj SamuelPalaj added bugfix A change that fixes a bug Medium labels May 25, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

Walkthrough

This PR refactors the view permission system to treat negative view permissions as first-class entities across the domain model, permission resolution, and search backends. Case and Task now populate negativeViewUsers, the Importer simplifies default role injection logic, and both Elasticsearch and Mongo search queries are rewritten to use more direct boolean matching rather than set algebra or conditional emptiness checks.

Changes

View Permission System Refactoring

Layer / File(s) Summary
Domain model: negative view users support
src/main/java/com/netgrif/application/engine/workflow/domain/Case.java, src/main/java/com/netgrif/application/engine/workflow/domain/Task.java
Case and Task resolveViewUsers() methods now clear and populate negativeViewUsers by partitioning users based on whether their view permission is true, false, or absent; users without a view key are ignored.
Importer: simplified default role/permission logic
src/main/java/com/netgrif/application/engine/importer/service/Importer.java
Default role/permission injection is simplified: per-transition default roles are skipped only when explicit role/user refs exist (not based on triggers), and net-level defaults are blocked when any permissions or user refs maps are non-empty.
Elasticsearch view permission query refactoring
src/main/java/com/netgrif/application/engine/elastic/service/ElasticTaskService.java, src/main/java/com/netgrif/application/engine/elastic/service/ElasticViewPermissionService.java
ElasticViewPermissionService replaces set-algebra composition with direct boolean logic using should clauses and minimumShouldMatch. ElasticTaskService removes role-constraint preprocessing. Helper queries for positive/negative roles and users are restructured to use inclusion-style boolean matching instead of exclusionary patterns.
Mongo/QueryDSL: simplified view permission queries
src/main/java/com/netgrif/application/engine/workflow/service/TaskSearchService.java
TaskSearchService.buildQuery constructs a single constraints BooleanBuilder with view role constraints (including negative exclusions) and view user constraints, then excludes negative view users. viewRoleQuery and viewUsersQuery simplified to direct contains checks without emptiness conditions.
Mongo: user reference resolution
src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java, src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java
TaskService and WorkflowService user reference resolution are simplified: gates permission handling on non-empty resolved userIds, and no longer separately manages negativeViewUsers clearing or conditional population based on permission values.
Test framework: permission test class and XML fixtures
src/test/groovy/com/netgrif/application/engine/workflow/TaskPermissionsTest.groovy, src/test/resources/petriNets/view_permission_combinations.xml, src/test/resources/petriNets/view_permission_combinations_no_default.xml
TaskPermissionsTest verifies view permission visibility across Elastic and Mongo backends by importing two Petri nets, setting up users with roles, and comparing backend query results against expected transition IDs loaded from CSV. Two XML Petri net fixtures define all 27 role/default/user permission combinations and a subset for testing without default role enabled.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ElasticTaskService
  participant ElasticViewPermissionService
  Client->>ElasticTaskService: buildSingleQuery(request, user)
  ElasticTaskService->>ElasticTaskService: construct BoolQueryBuilder (no role constraint preprocessing)
  ElasticTaskService->>ElasticViewPermissionService: buildViewPermissionQuery
  ElasticViewPermissionService->>ElasticViewPermissionService: buildPositiveViewRoleQuery (should clause)
  ElasticViewPermissionService->>ElasticViewPermissionService: buildPositiveViewUser (should clause)
  ElasticViewPermissionService->>ElasticViewPermissionService: buildNegativeViewUser (mustNot clause)
  ElasticViewPermissionService-->>ElasticTaskService: combined permission query
  ElasticTaskService-->>Client: final BoolQueryBuilder
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • netgrif/application-engine#409: Modifies TaskSearchService.buildQuery and user-matching predicate construction—may interact with this PR's view permission filtering refactoring in the same method.
  • netgrif/application-engine#335: Modifies Elasticsearch view-permission query construction in ElasticViewPermissionService helper queries—directly overlaps with this PR's boolean logic refactoring.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.05% 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
Title check ✅ Passed The title '[NAE 2424] UserRefs negative view permissions aren't resolved' directly and clearly identifies the main issue being fixed: the resolution of negative view permissions in UserRefs, which is confirmed across multiple file changes (WorkflowService, TaskService, Case, Task, and both search implementations).
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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/elastic/service/ElasticViewPermissionService.java`:
- Around line 18-24: The current buildViewPermissionQuery uses a
BoolQueryBuilder roleOrPositiveUserQuery that requires either roleViewQuery or
buildPositiveViewUser to match, which excludes documents that lack both
viewRoles and viewUsers; change roleOrPositiveUserQuery to also allow documents
where both permission fields are missing by adding an additional should clause
that matches "viewRoles not exists AND viewUsers not exists" (use exists queries
for viewRoles/viewUsers and combine them with mustNot as a should option) so
minimumShouldMatch(1) still applies, and leave the existing
mustNot(buildNegativeViewUser(user)) in place; update
ElasticViewPermissionService.buildViewPermissionQuery (and any helper usage of
roleViewQuery, buildPositiveViewUser, buildNegativeViewUser) to implement this
or alternatively document and implement a migration/backfill that populates
explicit positive defaults for existing documents.

In `@src/main/java/com/netgrif/application/engine/importer/service/Importer.java`:
- Around line 1160-1161: The current guard calls
importTransition.getRoleRef().isEmpty(), getUsersRef().isEmpty(), and
getUserRef().isEmpty() directly and can NPE when any of those refs is null;
change the condition to null-safe checks (e.g., check each ref for null before
calling isEmpty or use a utility like CollectionUtils.isEmpty/Objects.nonNull)
so the early-return only triggers when a non-null collection/string is present
and non-empty; update the condition around getRoleRef(), getUsersRef(), and
getUserRef() in Importer.java to perform null checks first.

In
`@src/test/groovy/com/netgrif/application/engine/workflow/TaskPermissionsTest.groovy`:
- Around line 66-70: The static maps testUsers and correctResults are reused
across tests; modify the init() setup method to reset static state at the
beginning by clearing testUsers and correctResults (call their clear/reset) and
also reset testCase and testCaseNoDefault to null so each test starts with a
clean slate; locate these symbols (testUsers, correctResults, testCase,
testCaseNoDefault, init) and add the clears/null assignments at the top of
init().
- Around line 141-153: The test currently uses header.indexOf(...) (e.g.,
transitionIdIndex and permissionIndex) without checking for -1, which can
silently pick wrong columns; update TaskPermissionsTest.groovy to validate
indices immediately after computing them (for transitionIdIndex and each
permissionIndex derived from header.indexOf(csvColumnName)) and throw a clear
failure (IllegalStateException or assertion) if any index is -1, including the
missing header name in the error message so the test fails fast when required
CSV headers are missing.
🪄 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: 43c90be6-3661-4bd4-9423-0c20d7493b81

📥 Commits

Reviewing files that changed from the base of the PR and between 7dabfe9 and cb6f7b8.

⛔ Files ignored due to path filters (2)
  • src/test/resources/csv/permissions - correct default disabled.csv is excluded by !**/*.csv
  • src/test/resources/csv/permissions - correct.csv is excluded by !**/*.csv
📒 Files selected for processing (11)
  • src/main/java/com/netgrif/application/engine/elastic/service/ElasticTaskService.java
  • src/main/java/com/netgrif/application/engine/elastic/service/ElasticViewPermissionService.java
  • src/main/java/com/netgrif/application/engine/importer/service/Importer.java
  • src/main/java/com/netgrif/application/engine/workflow/domain/Case.java
  • src/main/java/com/netgrif/application/engine/workflow/domain/Task.java
  • src/main/java/com/netgrif/application/engine/workflow/service/TaskSearchService.java
  • src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java
  • src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java
  • src/test/groovy/com/netgrif/application/engine/workflow/TaskPermissionsTest.groovy
  • src/test/resources/petriNets/view_permission_combinations.xml
  • src/test/resources/petriNets/view_permission_combinations_no_default.xml
💤 Files with no reviewable changes (1)
  • src/main/java/com/netgrif/application/engine/elastic/service/ElasticTaskService.java

Comment on lines +18 to +24
BoolQueryBuilder roleOrPositiveUserQuery = boolQuery().should(roleViewQuery)
.should(buildPositiveViewUser(user))
.minimumShouldMatch(1);

query.filter(permissionQuery);
// (((Rp!=0 & Rn = 0) or Up!=0) & Un=0) == 1
query.filter(roleOrPositiveUserQuery)
.mustNot(buildNegativeViewUser(user));
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 | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/main/java/com/netgrif/application/engine/elastic/service/ElasticViewPermissionService.java"

# Basic sanity: show file with line numbers (but avoid huge output)
echo "== File: $FILE =="
wc -l "$FILE"

# Show the relevant line ranges mentioned in the review comment
echo
echo "== Lines 1-120 =="
sed -n '1,120p' "$FILE" | nl -ba | sed -n '1,120p'

# Show the specific ranges more precisely
echo
echo "== Lines 1-80 (detailed) =="
sed -n '1,80p' "$FILE" | nl -ba

echo
echo "== Lines 80-200 (possible helpers) =="
sed -n '80,200p' "$FILE" | nl -ba

echo
echo "== Remaining lines (if any) =="
sed -n '200,500p' "$FILE" | nl -ba

# Find definitions of helper methods used in the snippet
echo
echo "== Search for builder methods =="
rg -n "buildPositiveViewUser|buildNegativeViewUser|buildViewPermissionQuery|roleViewQuery|viewRoles|viewUsers|not exists|missing" "$FILE" || true

# Show call sites to see whether any migration/backfill logic exists nearby
echo
echo "== Call sites for buildViewPermissionQuery usage =="
rg -n "buildViewPermissionQuery" src/main/java/com/netgrif/application/engine/elastic/service | head -n 50

Repository: netgrif/application-engine

Length of output: 356


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/main/java/com/netgrif/application/engine/elastic/service/ElasticViewPermissionService.java"

echo "== File: $FILE =="
wc -l "$FILE"

echo
echo "== Lines 1-120 =="
awk 'NR>=1 && NR<=120 {printf "%4d\t%s\n", NR, $0}' "$FILE"

echo
echo "== Grep helper/query components =="
rg -n "buildPositiveViewUser|buildNegativeViewUser|buildViewPermissionQuery|roleViewQuery|viewRoles|viewUsers|mustNot|minimumShouldMatch|not exists|missing" "$FILE" || true

echo
echo "== Find usages of buildViewPermissionQuery =="
rg -n "buildViewPermissionQuery" src/main/java/com/netgrif/application/engine/elastic/service

echo
echo "== Locate positive/negative helper method implementations =="
rg -n "buildPositiveViewUser|buildNegativeViewUser" "$FILE"

Repository: netgrif/application-engine

Length of output: 5084


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for any legacy "no permission fields" / not-exists logic references across Java sources
rg -n --hidden --glob '!**/target/**' \
  "viewPermNotExists|view perm(ission)? not exists|permission not exists|not exists|missing.*view|viewRoles.*missing|viewUsers.*missing" \
  src/main/java || true

# Search for query parts touching those fields
rg -n --hidden --glob '!**/target/**' \
  "viewRoles|viewUsers|negativeViewRoles|negativeViewUsers" \
  src/main/java/com/netgrif/application/engine/elastic/service || true

# Specifically check other permission-related services for compatibility paths
rg -n --hidden --glob '!**/target/**' \
  "ElasticViewPermissionService|buildViewPermissionQuery|buildPositiveViewRoleQuery|buildPositiveViewUser" \
  src/main/java || true

Repository: netgrif/application-engine

Length of output: 3064


🏁 Script executed:

#!/bin/bash
set -euo pipefail

TASK_FILE="src/main/java/com/netgrif/application/engine/elastic/service/ElasticTaskService.java"
CASE_FILE="src/main/java/com/netgrif/application/engine/elastic/service/ElasticCaseService.java"

echo "== ElasticTaskService: show around buildViewPermissionQuery usage (line ~183) =="
awk 'NR>=150 && NR<=230 {printf "%4d\t%s\n", NR, $0}' "$TASK_FILE" | sed -n '1,120p'

echo
echo "== ElasticCaseService: show around buildViewPermissionQuery usage (line ~205) =="
awk 'NR>=170 && NR<=260 {printf "%4d\t%s\n", NR, $0}' "$CASE_FILE" | sed -n '1,120p'

echo
echo "== Check for other view permission logic in those services =="
rg -n "buildViewPermissionQuery|viewRoles|viewUsers|negativeViewRoles|negativeViewUsers|mustNot\\(buildNegativeView|minimumShouldMatch" "$TASK_FILE" "$CASE_FILE" || true

Repository: netgrif/application-engine

Length of output: 7725


Elastic view permission query now excludes documents without explicit viewRoles/viewUsers matches

In ElasticViewPermissionService.buildViewPermissionQuery (lines 18-24, helpers 31-59), roleOrPositiveUserQuery uses minimumShouldMatch(1) across roleViewQuery (positive viewRoles) and buildPositiveViewUser (positive viewUsers), with no “field missing => allowed” branch. As a result, documents that omit viewRoles and viewUsers will not match, impacting both task and case searches since both ElasticTaskService and ElasticCaseService call this shared helper.

Restore the intended legacy “no permission fields” behavior or document and implement a migration/reindex/backfill that populates explicit positive defaults for existing documents.

🤖 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/elastic/service/ElasticViewPermissionService.java`
around lines 18 - 24, The current buildViewPermissionQuery uses a
BoolQueryBuilder roleOrPositiveUserQuery that requires either roleViewQuery or
buildPositiveViewUser to match, which excludes documents that lack both
viewRoles and viewUsers; change roleOrPositiveUserQuery to also allow documents
where both permission fields are missing by adding an additional should clause
that matches "viewRoles not exists AND viewUsers not exists" (use exists queries
for viewRoles/viewUsers and combine them with mustNot as a should option) so
minimumShouldMatch(1) still applies, and leave the existing
mustNot(buildNegativeViewUser(user)) in place; update
ElasticViewPermissionService.buildViewPermissionQuery (and any helper usage of
roleViewQuery, buildPositiveViewUser, buildNegativeViewUser) to implement this
or alternatively document and implement a migration/backfill that populates
explicit positive defaults for existing documents.

Comment thread src/main/java/com/netgrif/application/engine/importer/service/Importer.java Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix A change that fixes a bug Medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants