Skip to content

Issues/798#1807

Open
Yaksha-sn wants to merge 3 commits into
kafbat:mainfrom
Yaksha-sn:issues/798
Open

Issues/798#1807
Yaksha-sn wants to merge 3 commits into
kafbat:mainfrom
Yaksha-sn:issues/798

Conversation

@Yaksha-sn

@Yaksha-sn Yaksha-sn commented Apr 21, 2026

Copy link
Copy Markdown

Fixes #798

Problem

When RBAC is enabled, a user who authenticates successfully via OAuth2 or LDAP
but matches no configured roles can still enter the UI, seeing an empty interface
with no clusters visible.

Solution

  • Added checkUserHasRoles() helper in OAuthSecurityConfig called after role
    extraction in both customOidcUserService and customOauth2UserService
  • Added same check inside RbacUserDetailsMapper.mapUserFromContext() in LdapSecurityConfig
  • Throws AccessDeniedException if RBAC is enabled, user has no matching roles,
    and no defaultRole is configured
  • Default role (issue RBAC: Implement instance-wide default role #344) is respected — users are allowed through if a
    defaultRole is configured

Tests

  • OAuthSecurityConfigRoleCheckTest — 7 unit tests covering OAuth path
  • LdapSecurityConfigRoleCheckTest — 5 unit tests covering LDAP path

Summary by CodeRabbit

  • New Features

    • Enhanced access control for LDAP authentication with role-based access enforcement
    • Enhanced access control for OAuth/OIDC authentication with role-based access enforcement
    • When role-based access control is enabled, users must belong to a configured role or have a default role assigned to gain access
  • Tests

    • Added comprehensive test coverage for role-based access control validation across authentication methods

…t#798)

- Added checkUserHasRoles() in OAuthSecurityConfig to deny login
  when RBAC is enabled and user has no matching roles
- Added same check in LdapSecurityConfig.RbacUserDetailsMapper
- Default role (issue kafbat#344) is respected - users are allowed through
  if a defaultRole is configured even with no explicit role match
- Added unit tests for both OAuth and LDAP paths
@Yaksha-sn Yaksha-sn requested a review from a team as a code owner April 21, 2026 11:29
@kapybro kapybro Bot added status/triage Issues pending maintainers triage status/triage/manual Manual triage in progress status/triage/completed Automatic triage completed and removed status/triage Issues pending maintainers triage labels Apr 21, 2026
@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

These changes implement role-based access enforcement for LDAP and OAuth2/OIDC authentication flows. When RBAC is enabled, users without matching roles and no configured default role are denied access via AccessDeniedException. Two new comprehensive test classes validate the role-checking behavior across various RBAC configurations.

Changes

Cohort / File(s) Summary
LDAP Authentication Role Enforcement
api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java
Added role-validation logic to RbacUserDetailsMapper.mapUserFromContext() that checks if mapped users belong to configured roles when RBAC is enabled. Throws AccessDeniedException if no role matches and no default role exists. Made RbacUserDetailsMapper package-private and added constructor accepting AccessControlService for role checking.
OAuth2/OIDC Authentication Role Enforcement
api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java
Introduced checkUserHasRoles() method invoked during both OIDC and OAuth2 user-service flows to validate extracted groups against configured roles. Throws AccessDeniedException when RBAC is enabled, no user groups match any role, and no default role is configured. Updated method calls and imports accordingly.
LDAP Role-Check Tests
api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java
New test class verifying RBAC role-enforcement in LDAP flows: validates access denial when no roles match and no default role exists, access allowance when RBAC is disabled or roles match, and access allowance when default role is present.
OAuth2/OIDC Role-Check Tests
api/src/test/java/io/kafbat/ui/config/auth/OAuthSecurityConfigRoleCheckTest.java
New test class verifying RBAC role-enforcement in OAuth2/OIDC flows: covers scenarios with RBAC enabled/disabled, group matching, default roles, and empty role configurations.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LdapProvider as LDAP Provider
    participant AuthConfig as LdapSecurityConfig
    participant RbacMapper as RbacUserDetailsMapper
    participant ACS as AccessControlService
    participant App as Application

    User->>LdapProvider: Authenticate (username, password)
    LdapProvider->>AuthConfig: Create UserDetails from LDAP context
    AuthConfig->>RbacMapper: mapUserFromContext(context, user)
    
    RbacMapper->>ACS: isRbacEnabled()?
    alt RBAC Enabled
        RbacMapper->>ACS: getRoles()
        RbacMapper->>RbacMapper: Check user authorities against configured roles
        alt User has matching role
            RbacMapper->>RbacMapper: Create RbacLdapUser (success)
            RbacMapper->>AuthConfig: Return RbacLdapUser
        else No matching role
            RbacMapper->>ACS: getDefaultRole()
            alt Default role exists
                RbacMapper->>RbacMapper: Create RbacLdapUser (success)
                RbacMapper->>AuthConfig: Return RbacLdapUser
            else No default role
                RbacMapper->>User: throw AccessDeniedException
                User->>App: ✗ Access Denied
            end
        end
    else RBAC Disabled
        RbacMapper->>RbacMapper: Create RbacLdapUser (success)
        RbacMapper->>AuthConfig: Return RbacLdapUser
    end
    
    AuthConfig->>App: ✓ Authentication complete
    App->>User: Login successful
Loading
sequenceDiagram
    participant User
    participant OAuthProvider as OAuth/OIDC Provider
    participant AuthConfig as OAuthSecurityConfig
    participant RoleValidator as checkUserHasRoles
    participant ACS as AccessControlService
    participant App as Application

    User->>OAuthProvider: Initiate OAuth/OIDC login
    OAuthProvider->>AuthConfig: User service callback
    AuthConfig->>AuthConfig: Extract provider authority (groups)
    
    AuthConfig->>RoleValidator: checkUserHasRoles(extracted groups)
    RoleValidator->>ACS: isRbacEnabled()?
    alt RBAC Enabled
        RoleValidator->>ACS: getRoles()
        RoleValidator->>RoleValidator: Match user groups against configured roles
        alt User group matches role
            RoleValidator->>AuthConfig: ✓ Return (allow)
        else No matching group
            RoleValidator->>ACS: getDefaultRole()
            alt Default role exists
                RoleValidator->>AuthConfig: ✓ Return (allow)
            else No default role
                RoleValidator->>User: throw AccessDeniedException
                User->>App: ✗ Access Denied
            end
        end
    else RBAC Disabled
        RoleValidator->>AuthConfig: ✓ Return (allow)
    end
    
    AuthConfig->>AuthConfig: Create RbacOAuth2User/RbacOidcUser
    AuthConfig->>App: ✓ Authentication complete
    App->>User: Login successful
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A hop, a skip, through auth's domain,
Where LDAP and OAuth paths entwine,
No roles? No access—we guard the lane!
Default roles dance where needed fine,
Access control hops, tests align! 🔐

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Issues/798' is vague and does not clearly describe the main change; it only references an issue number without explaining what the pull request actually does. Use a descriptive title like 'Deny access for RBAC users without matching roles' to clearly convey the primary change.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The pull request fully implements the requirements from issue #798: it denies access for authenticated users without matching RBAC roles by throwing AccessDeniedException in both LDAP and OAuth flows, preserves default role behavior, and includes comprehensive unit tests.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #798: role-validation logic in LdapSecurityConfig and OAuthSecurityConfig with corresponding tests, with no unrelated refactoring or feature additions.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions 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.

Hi Yaksha-sn! 👋

Welcome, and thank you for opening your first PR in the repo!

Please wait for triaging by our maintainers.

Please take a look at our contributing guide.

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java (1)

148-186: ⚠️ Potential issue | 🟠 Major

Replace AccessDeniedException with OAuth2AuthenticationException for proper reactive OAuth2 failure handling.

Spring Security's ReactiveOAuth2UserService contract explicitly requires OAuth2AuthenticationException for user-loading errors, not AccessDeniedException. Throwing AccessDeniedException from your custom user service (lines 225–226) will be handled by ServerAccessDeniedHandler (403 Forbidden response), bypassing the OAuth2 login failure handler. This skips the configured /login?error flow and likely renders a generic 403 error page instead. Wrap the denial in OAuth2AuthenticationException with an appropriate OAuth2Error to integrate cleanly with Spring Security's reactive OAuth2 failure handling.

Additionally, add the username to the error message (as in LdapSecurityConfig) for better forensics when operators investigate failed login attempts.

Suggested fix
-      throw new AccessDeniedException(
-          "Access denied: authenticated user has no roles assigned.");
+      OAuth2Error oauth2Error = new OAuth2Error(
+          "insufficient_scope",
+          "Access denied: authenticated user has no roles assigned.",
+          null);
+      throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.getDescription());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java` around
lines 148 - 186, In OAuthSecurityConfig, customOidcUserService and
customOauth2UserService currently surface an AccessDeniedException via
checkUserHasRoles which causes a 403 instead of triggering the OAuth2 failure
flow; change the logic so when a user lacks roles you throw an
OAuth2AuthenticationException constructed with a meaningful OAuth2Error (e.g.
error code "access_denied") and include the username in the exception message
(similar to LdapSecurityConfig) so the reactive OAuth2 login failure handler can
process it; update the code paths that call checkUserHasRoles (and/or modify
checkUserHasRoles) to produce OAuth2AuthenticationException with OAuth2Error
rather than AccessDeniedException when invoked from
customOidcUserService/customOauth2UserService.
🧹 Nitpick comments (1)
api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java (1)

183-205: Consider consolidating the duplicated RBAC role-check into AccessControlService.

The !hasRole && defaultRole == null predicate is now implemented in two places — here and in OAuthSecurityConfig.checkUserHasRoles (lines 218-228) — with slightly different error messages. This is a natural fit for AccessControlService (it already owns getRoles(), getDefaultRole(), and a filterRole(user) predicate per the context snippet). A single method like assertUserHasRoleOrDefault(Collection<String> groups, String username) would:

  • keep the OAuth and LDAP branches behaviorally identical (including logging, exception type, and message format),
  • let AccessControlService own the RBAC semantics end-to-end (easier to change policy later, e.g. adding admin-override roles), and
  • remove the need to widen RbacUserDetailsMapper visibility / OAuthSecurityConfig.checkUserHasRoles package visibility purely for testability — you can test the centralized method directly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java` around
lines 183 - 205, Extract the duplicated RBAC predicate into AccessControlService
by adding a method like assertUserHasRoleOrDefault(Collection<String> groups,
String username) (or similar name) that checks getRoles()/getDefaultRole() and
throws the canonical AccessDeniedException with the unified message; then
replace the role-check logic in RbacUserDetailsMapper.mapUserFromContext and in
OAuthSecurityConfig.checkUserHasRoles to call that new AccessControlService
method (use existing symbols acs, RbacUserDetailsMapper, and
OAuthSecurityConfig.checkUserHasRoles) so both branches share identical
behavior, logging and exception text.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java`:
- Around line 218-228: Update checkUserHasRoles to accept the authenticated
username (e.g., add a String username parameter), make the method static, and
before throwing the AccessDeniedException log a warning with the username and
the extracted groups using the class logger; also include the username in the
thrown message (e.g., "Access denied: user 'X' has no roles assigned. Groups:
[...]"). Keep the RBAC check logic using AccessControlService acs and groups
as-is (method name checkUserHasRoles, parameters groups and acs), and update all
call sites to pass the OAuth/Oidc/OAuth2 user’s username so tests can invoke the
static helper cleanly.

In
`@api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java`:
- Around line 36-53: The test currently duplicates the RBAC logic in
checkAccess() instead of invoking the production code; update the tests to call
RbacUserDetailsMapper.mapUserFromContext(...) (or a spy of
RbacUserDetailsMapper) so the real role-check path is exercised; replace usages
of checkAccess(...) with a call to
mapper.mapUserFromContext(mockDirContextOperations, "testuser") while
mocking/stubbing the DirContextOperations or spying the mapper to return a
controllable UserDetails from super.mapUserFromContext(), and assert that the
mapper throws the real AccessDeniedException (and message) or returns the
expected mapped user when roles/defaultRole conditions are met.

---

Outside diff comments:
In `@api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java`:
- Around line 148-186: In OAuthSecurityConfig, customOidcUserService and
customOauth2UserService currently surface an AccessDeniedException via
checkUserHasRoles which causes a 403 instead of triggering the OAuth2 failure
flow; change the logic so when a user lacks roles you throw an
OAuth2AuthenticationException constructed with a meaningful OAuth2Error (e.g.
error code "access_denied") and include the username in the exception message
(similar to LdapSecurityConfig) so the reactive OAuth2 login failure handler can
process it; update the code paths that call checkUserHasRoles (and/or modify
checkUserHasRoles) to produce OAuth2AuthenticationException with OAuth2Error
rather than AccessDeniedException when invoked from
customOidcUserService/customOauth2UserService.

---

Nitpick comments:
In `@api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java`:
- Around line 183-205: Extract the duplicated RBAC predicate into
AccessControlService by adding a method like
assertUserHasRoleOrDefault(Collection<String> groups, String username) (or
similar name) that checks getRoles()/getDefaultRole() and throws the canonical
AccessDeniedException with the unified message; then replace the role-check
logic in RbacUserDetailsMapper.mapUserFromContext and in
OAuthSecurityConfig.checkUserHasRoles to call that new AccessControlService
method (use existing symbols acs, RbacUserDetailsMapper, and
OAuthSecurityConfig.checkUserHasRoles) so both branches share identical
behavior, logging and exception text.
🪄 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: CHILL

Plan: Pro

Run ID: f9a17fdb-6b5d-4176-9196-821c62e145ee

📥 Commits

Reviewing files that changed from the base of the PR and between afc9c91 and 518def3.

📒 Files selected for processing (4)
  • api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java
  • api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java
  • api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java
  • api/src/test/java/io/kafbat/ui/config/auth/OAuthSecurityConfigRoleCheckTest.java

Comment on lines +218 to +228
void checkUserHasRoles(Collection<String> groups, AccessControlService acs) {
if (!acs.isRbacEnabled()) {
return;
}
boolean hasRole = acs.getRoles().stream()
.anyMatch(role -> groups.contains(role.getName()));
if (!hasRole && acs.getDefaultRole() == null) {
throw new AccessDeniedException(
"Access denied: authenticated user has no roles assigned.");
}
}

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

Add a log line and include username in the denial message for parity with LDAP.

Two small polish items on the new helper:

  1. No log is emitted before throwing. Operators debugging “my user cannot log in” will see only a generic AccessDeniedException stack trace. A log.warn(...) identifying the user and extracted groups would be valuable for RBAC troubleshooting (the exact symptom described in issue #798).
  2. LdapSecurityConfig.RbacUserDetailsMapper throws with the username embedded ("... user '" + username + "' ..."), but this branch does not — the OAuth user (OidcUser / OAuth2User) is in scope at the call sites and could be threaded through for consistency.

Also: the method has no instance-state dependency and could be static, which would make the test invocation cleaner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java` around
lines 218 - 228, Update checkUserHasRoles to accept the authenticated username
(e.g., add a String username parameter), make the method static, and before
throwing the AccessDeniedException log a warning with the username and the
extracted groups using the class logger; also include the username in the thrown
message (e.g., "Access denied: user 'X' has no roles assigned. Groups: [...]").
Keep the RBAC check logic using AccessControlService acs and groups as-is
(method name checkUserHasRoles, parameters groups and acs), and update all call
sites to pass the OAuth/Oidc/OAuth2 user’s username so tests can invoke the
static helper cleanly.

Comment on lines +36 to +53
/**
* Directly tests the role-check logic by constructing an RbacLdapUser
* with the given authorities and checking if access is granted or denied.
* This avoids calling super.mapUserFromContext() which requires a real LDAP
* context.
*/
private void checkAccess(Collection<GrantedAuthority> authorities) {
UserDetails userDetails = new User("testuser", "", authorities);
RbacLdapUser rbacUser = new RbacLdapUser(userDetails);

if (acs.isRbacEnabled()) {
boolean hasRole = acs.getRoles().stream()
.anyMatch(role -> rbacUser.groups().contains(role.getName()));
if (!hasRole && acs.getDefaultRole() == null) {
throw new AccessDeniedException("Access denied");
}
}
}

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the mapper class is reachable from the test package (same package → accessible).
rg -nP '\b(static\s+)?class\s+RbacUserDetailsMapper\b' api/src/main/java

Repository: kafbat/kafka-ui

Length of output: 198


🏁 Script executed:

#!/bin/bash
# Extract the mapUserFromContext method from RbacUserDetailsMapper (around lines 195-202)
sed -n '180,210p' api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java

Repository: kafbat/kafka-ui

Length of output: 993


🏁 Script executed:

#!/bin/bash
# Extract the checkAccess method from the test file (lines 36-53)
sed -n '36,53p' api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java

Repository: kafbat/kafka-ui

Length of output: 795


🏁 Script executed:

#!/bin/bash
# Check the overall structure of the test class to understand how checkAccess is used
wc -l api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java
head -n 60 api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java

Repository: kafbat/kafka-ui

Length of output: 2343


🏁 Script executed:

#!/bin/bash
# Get the complete test file to see all test methods and their assertions
cat api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java

Repository: kafbat/kafka-ui

Length of output: 3821


Test duplicates the mapper's role-check logic instead of exercising the real code — regressions in RbacUserDetailsMapper will not be caught.

The checkAccess() helper reimplements the exact branch from RbacUserDetailsMapper.mapUserFromContext() (lines 195–202):

if (acs.isRbacEnabled()) {
  boolean hasRole = acs.getRoles().stream()
      .anyMatch(role -> rbacUser.groups().contains(role.getName()));
  if (!hasRole && acs.getDefaultRole() == null) {
    throw new AccessDeniedException("Access denied");
  }
}

The assertions in all five test methods therefore verify only that the helper matches the mocks, not that the production mapper does. This creates a coverage gap:

  • If the mapper's exception message is changed (actual: "Access denied: authenticated user '" + username + "' has no roles assigned."), tests pass.
  • If super.mapUserFromContext() is accidentally omitted, tests pass.
  • If the role-matching predicate is refactored, divergence is only caught if the test's reimplementation is also changed in sync.

Since RBAC role enforcement is the core purpose of this PR (issue #798), exercise the real RbacUserDetailsMapper.mapUserFromContext() instead. Mock the required DirContextOperations parameter or spy on the mapper to stub the super call.

Suggested refactor
   private void checkAccess(Collection<GrantedAuthority> authorities) {
-    UserDetails userDetails = new User("testuser", "", authorities);
-    RbacLdapUser rbacUser = new RbacLdapUser(userDetails);
-
-    if (acs.isRbacEnabled()) {
-      boolean hasRole = acs.getRoles().stream()
-          .anyMatch(role -> rbacUser.groups().contains(role.getName()));
-      if (!hasRole && acs.getDefaultRole() == null) {
-        throw new AccessDeniedException("Access denied");
-      }
-    }
+    DirContextOperations ctx = mock(DirContextOperations.class);
+    LdapSecurityConfig.RbacUserDetailsMapper mapper =
+        Mockito.spy(new LdapSecurityConfig.RbacUserDetailsMapper(acs));
+    Mockito.doReturn(new User("testuser", "", authorities))
+        .when((LdapUserDetailsMapper) mapper)
+        .mapUserFromContext(eq(ctx), eq("testuser"), anyCollection());
+    mapper.mapUserFromContext(ctx, "testuser", authorities);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/src/test/java/io/kafbat/ui/config/auth/LdapSecurityConfigRoleCheckTest.java`
around lines 36 - 53, The test currently duplicates the RBAC logic in
checkAccess() instead of invoking the production code; update the tests to call
RbacUserDetailsMapper.mapUserFromContext(...) (or a spy of
RbacUserDetailsMapper) so the real role-check path is exercised; replace usages
of checkAccess(...) with a call to
mapper.mapUserFromContext(mockDirContextOperations, "testuser") while
mocking/stubbing the DirContextOperations or spying the mapper to return a
controllable UserDetails from super.mapUserFromContext(), and assert that the
mapper throws the real AccessDeniedException (and message) or returns the
expected mapped user when roles/defaultRole conditions are met.

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

Labels

status/triage/completed Automatic triage completed status/triage/manual Manual triage in progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auth: Deny access for a user without any roles

1 participant