Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@elibosley
Copy link
Member

@elibosley elibosley commented Sep 26, 2025

…on tests for AuthZGuard

  • Improved error handling in the auth module to ensure user context is present and valid.
  • Added checks for user roles and identifiers, throwing appropriate exceptions for missing or invalid data.
  • Introduced a new integration test suite for AuthZGuard, validating role-based access control for various actions in the application.
  • Tests cover scenarios for viewer and admin roles, ensuring correct permissions are enforced.

Summary by CodeRabbit

  • New Features

    • Added a subject-resolution utility to consistently derive an authorization subject from the authenticated user.
  • Bug Fixes

    • Hardened authorization: rejects missing/invalid users or roles and ensures a valid subject is produced for permission checks.
  • Tests

    • Added unit and integration tests validating subject resolution and authorization behaviors across admin/viewer/API-key scenarios.

…on tests for AuthZGuard

- Improved error handling in the auth module to ensure user context is present and valid.
- Added checks for user roles and identifiers, throwing appropriate exceptions for missing or invalid data.
- Introduced a new integration test suite for AuthZGuard, validating role-based access control for various actions in the application.
- Tests cover scenarios for viewer and admin roles, ensuring correct permissions are enforced.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Delegates subject extraction in the auth module to a new utility resolveSubjectFromUser; adds that utility plus unit tests; and introduces an integration test suite for AuthZGuard using an in-memory Casbin enforcer to validate role- and policy-based authorization scenarios.

Changes

Cohort / File(s) Summary
Auth module update
api/src/unraid-api/auth/auth.module.ts
Replaces inline subject/roles extraction with a call to resolveSubjectFromUser(request?.user); removes manual array checks and role-joining; preserves UnauthorizedException on resolution failure.
Resolve-subject utility
api/src/unraid-api/auth/casbin/resolve-subject.util.ts
Adds resolveSubjectFromUser(user) which validates input, prefers trimmed user.id, falls back to a single non-empty role, and throws UnauthorizedException on invalid/missing subject.
Resolve-subject unit tests
api/src/unraid-api/auth/casbin/resolve-subject.util.spec.ts
New unit tests covering successful ID or single-role resolution and multiple error cases (missing user, non-array roles, empty/multiple roles, blank entries).
AuthZGuard Casbin integration tests
api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts
New integration tests that create an in-memory Casbin enforcer, register grouping policies and dynamic policies, scaffold GraphQL execution contexts, and verify allow/deny scenarios for VIEWER/ADMIN roles and API-key permissions across Docker/VM/ME actions.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant GQL as GraphQL Resolver
  participant Guard as AuthZGuard
  participant Ctx as ExecutionContext
  participant Resolver as resolveSubjectFromUser
  participant Enforcer as Casbin Enforcer

  Client->>GQL: call resolver/mutation
  GQL->>Guard: canActivate(Ctx)
  Guard->>Ctx: get request.user
  Guard->>Resolver: resolveSubjectFromUser(request.user)
  alt resolution fails
    Resolver-->>Guard: throws UnauthorizedException
    Guard-->>GQL: deny (401/Forbidden)
    GQL-->>Client: error
  else resolution succeeds
    Resolver-->>Guard: subject
    Guard->>Enforcer: enforce(subject, action, resource)
    alt allowed
      Enforcer-->>Guard: true
      Guard-->>GQL: allow
      GQL-->>Client: success
    else denied
      Enforcer-->>Guard: false
      Guard-->>GQL: deny (Forbidden)
      GQL-->>Client: error
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers, resolve in paw,
IDs trimmed neat, or a lone role's law—
Casbin watches gates and hums,
Guards deciding who may come.
Hop, hop—permissions snug as a glove! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly summarizes the pull request by specifying the enhancement of user context validation in the auth module and the addition of integration tests, which aligns directly with the described changes.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c6c5d5 and 86de6ff.

📒 Files selected for processing (4)
  • api/src/unraid-api/auth/auth.module.ts (2 hunks)
  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts (1 hunks)
  • api/src/unraid-api/auth/casbin/resolve-subject.util.spec.ts (1 hunks)
  • api/src/unraid-api/auth/casbin/resolve-subject.util.ts (1 hunks)

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

@claude
Copy link

claude bot commented Sep 26, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

@codecov
Copy link

codecov bot commented Sep 26, 2025

Codecov Report

❌ Patch coverage is 96.55172% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 53.34%. Comparing base (7bdeca8) to head (86de6ff).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
api/src/unraid-api/auth/auth.module.ts 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1726      +/-   ##
==========================================
+ Coverage   53.29%   53.34%   +0.05%     
==========================================
  Files         859      860       +1     
  Lines       48247    48271      +24     
  Branches     4912     4926      +14     
==========================================
+ Hits        25715    25752      +37     
+ Misses      22463    22450      -13     
  Partials       69       69              

☔ 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
Contributor

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

🧹 Nitpick comments (4)
api/src/unraid-api/auth/auth.module.ts (1)

40-40: Hoist Logger and log stack traces properly.

Avoid per-call Logger creation and pass stack/trace to Logger.error for clarity.

Apply this diff to reuse a shared logger and improve error logging:

-                const logger = new Logger('AuthZModule');
+                const logger = AUTHZ_LOGGER;
@@
-                } catch (error) {
-                    logger.error('Failed to extract user context', error);
+                } catch (error) {
+                    logger.error(
+                        'Failed to extract user context',
+                        error instanceof Error ? error.stack : String(error)
+                    );
                     throw new UnauthorizedException('Failed to authenticate user');
                 }

Add this at module scope (top of file) to define the shared logger:

const AUTHZ_LOGGER = new Logger('AuthModule');

Also applies to: 66-69

api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts (3)

19-20: Use unknown[] instead of any[].

Tighten the handler signature to avoid any.

As per coding guidelines

-type Handler = (...args: any[]) => unknown;
+type Handler = (...args: unknown[]) => unknown;

69-79: Mirror module’s user presence check and safer subject fallback in tests.

Keep test mapper aligned with production to catch mismatches early.

Apply this diff:

-            userFromContext: (ctx: ExecutionContext) => {
-                const request = getRequest(ctx) as TestRequest | undefined;
-                const user: TestUser = request?.user ?? {};
-                const roles = user.roles ?? [];
-
-                if (!Array.isArray(roles)) {
-                    throw new UnauthorizedException('User roles must be an array');
-                }
-
-                return typeof user.id === 'string' && user.id.length > 0 ? user.id : roles.join(',');
-            },
+            userFromContext: (ctx: ExecutionContext) => {
+                const request = getRequest(ctx) as TestRequest | undefined;
+                const user = request?.user;
+                if (!user) {
+                    throw new UnauthorizedException('Request user context missing');
+                }
+                const roles = user.roles ?? [];
+                if (!Array.isArray(roles)) {
+                    throw new UnauthorizedException('User roles must be an array');
+                }
+                const userId = typeof user.id === 'string' ? user.id.trim() : '';
+                const subject = userId || (roles.length === 1 ? String(roles[0]) : '');
+                if (!subject) {
+                    throw new UnauthorizedException('User identifier (id) or single role is required');
+                }
+                return subject;
+            },

54-81: Add negative-path tests for missing user/invalid roles.

Strengthens guarantees around Unauthorized flows and aligns with test guidelines.

As per coding guidelines

it('rejects when user context is missing', async () => {
  // Create a context with no user
  const context = (() => {
    const graphqlContextHost = new ExecutionContextHost(
      [undefined, undefined, { req: {} as TestRequest }, undefined],
      DockerResolver,
      DockerResolver.prototype.containers
    );
    graphqlContextHost.setType('graphql');
    return graphqlContextHost as unknown as ExecutionContext;
  })();

  await expect(guard.canActivate(context)).rejects.toThrow();
});

it('rejects when roles is not an array', async () => {
  // roles: as any to simulate a malformed token/user object
  const badRoles = null as unknown as Role[];
  const context = createExecutionContext(
    DockerResolver.prototype.containers,
    DockerResolver,
    badRoles,
    'api-key-viewer'
  );
  await expect(guard.canActivate(context)).rejects.toThrow();
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bdeca8 and 0c6c5d5.

📒 Files selected for processing (2)
  • api/src/unraid-api/auth/auth.module.ts (1 hunks)
  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
api/src/unraid-api/**

📄 CodeRabbit inference engine (.cursor/rules/api-rules.mdc)

Prefer adding new files to the Nest repo at api/src/unraid-api/ instead of legacy code

Files:

  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts
  • api/src/unraid-api/auth/auth.module.ts
api/**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/api-rules.mdc)

api/**/*.{test,spec}.{js,jsx,ts,tsx}: Use Vitest for tests in the api; do not use Jest
Prefer not to mock simple dependencies in tests
For error testing, use .rejects.toThrow() without arguments; avoid asserting exact error messages unless the message format is the subject under test

Files:

  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript import specifiers with .js extensions for ESM compatibility
Never use the any type; prefer precise typing
Avoid type casting; model proper types from the start

Files:

  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts
  • api/src/unraid-api/auth/auth.module.ts
api/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

api/**/*.{test,spec}.{ts,tsx}: API test suite is Vitest; do not use Jest
Prefer not to mock simple dependencies in API tests

Files:

  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts
{api,web}/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

{api,web}/**/*.{test,spec}.{ts,tsx}: For error tests, use .rejects.toThrow() without arguments; avoid asserting exact error messages unless that format is the subject
Focus tests on behavior, not implementation details
Avoid brittle tests tied to exact error or log wording
Use mocks as nouns, not verbs
Always await async operations before making assertions
Place all mock declarations at the top level; use factory functions for module mocks; clear mocks between tests

Files:

  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts
api/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

cache-manager v7 TTL values must be in milliseconds (e.g., 600000 for 10 minutes)

Files:

  • api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts
  • api/src/unraid-api/auth/auth.module.ts
🧬 Code graph analysis (1)
api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts (2)
api/src/unraid-api/auth/casbin/model.ts (1)
  • CASBIN_MODEL (1-18)
api/src/unraid-api/auth/casbin/policy.ts (1)
  • BASE_POLICY (9-26)
🔇 Additional comments (4)
api/src/unraid-api/auth/auth.module.ts (1)

46-49: Good: strict user/roles validation before subject derivation.

The explicit user presence check and enforcing roles to be an array harden the context extraction path.

Also applies to: 52-55

api/src/unraid-api/auth/casbin/authz.guard.integration.spec.ts (3)

65-79: Verify AuthZGuard constructor signature against nest-authz 2.17.0.

Direct instantiation with (reflector, enforcer, options) may vary by version; ensure it compiles and behaves as expected.

Run the test suite locally/CI and confirm the guard is constructed successfully with these params.


82-124: LGTM: clear, behavior-focused authorization checks for viewer/admin.

The scenarios align with policy/grouping and assert on canActivate without brittle message coupling.


126-137: LGTM: custom subject policy path is exercised.

Good coverage for direct p.sub subject permissions independent of role grouping.

…xtraction

- Introduced a new utility function, `resolveSubjectFromUser`, to streamline user context extraction in the auth module.
- Replaced direct user role and ID checks with the new utility for improved readability and maintainability.
- Added unit tests for `resolveSubjectFromUser` to ensure robust validation of user roles and identifiers.
- Updated integration tests for AuthZGuard to utilize the new utility, enhancing error handling and user context validation.
@github-actions
Copy link
Contributor

This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL:

https://preview.dl.unraid.net/unraid-api/tag/PR1726/dynamix.unraid.net.plg

@elibosley elibosley merged commit cd5eff1 into main Sep 26, 2025
12 of 14 checks passed
@elibosley elibosley deleted the fix/roles-on-auth-module branch September 26, 2025 16:50
elibosley pushed a commit that referenced this pull request Sep 26, 2025
🤖 I have created a release *beep* *boop*
---


## [4.25.0](v4.24.1...v4.25.0)
(2025-09-26)


### Features

* add Tailwind scoping plugin and integrate into Vite config
([#1722](#1722))
([b7afaf4](b7afaf4))
* notification filter controls pill buttons
([#1718](#1718))
([661865f](661865f))


### Bug Fixes

* enable auth guard for nested fields - thanks
[@ingel81](https://github.com/ingel81)
([7bdeca8](7bdeca8))
* enhance user context validation in auth module
([#1726](#1726))
([cd5eff1](cd5eff1))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants