Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: create application request and role guard introduction #338

Merged
merged 10 commits into from
Oct 10, 2024

Conversation

kshitij-k-osmosys
Copy link
Contributor

@kshitij-k-osmosys kshitij-k-osmosys commented Oct 3, 2024

API PR Checklist

Pre-requisites

  • I have gone through the Contributing guidelines for Submitting a Pull Request (PR) and ensured that this is not a duplicate PR.
  • I have performed unit testing for the new feature added or updated to ensure the new features added are working as expected.
  • I have added/updated test cases to the test suite as applicable.
  • I have performed preliminary testing using the test suite to ensure that any existing features are not impacted and any new features are working as expected as a whole.
  • I have added/updated the required api docs as applicable.
  • I have added/updated the .env.example file with the required values as applicable.

PR Details

PR details have been updated as per the given format (see below)

  • PR title adheres to the format specified in guidelines (e.g., feat: add admin login endpoint)
  • Description has been added
  • Related changes have been added (optional)
  • Screenshots have been added (optional)
  • Query request and response examples have been added (as applicable, in case added or updated)
  • Documentation changes have been listed (as applicable)
  • Test suite/unit testing output is added (as applicable)
  • Pending actions have been added (optional)
  • Any other additional notes have been added (optional)

Additional Information

  • Appropriate label(s) have been added (ready for review should be added if the PR is ready to be reviewed)
  • Assignee(s) and reviewer(s) have been added (optional)

Note: Reviewer should ensure that the checklist and description have been populated and followed correctly, and the PR should be merged only after resolving all conversations and verifying that CI checks pass.


Description:

Update Create Application to get user id from auth token & Add Roles guard for API

Related changes:

  • Update Create Application to not use auth token and use request context instead to fetch userid
  • Refactor create application service function to use context instead of request header
  • Create Role guards for Provider and Application Resolvers
  • Refactor code to use Role guards
  • Update postman collection
  • Update documentation

Screenshots:
image
Response for non admin user

Query request and response:

New cURL for create application

curl --location 'localhost:3000/graphql' \
--header 'Authorization: Bearer auth-token' \
--header 'Content-Type: application/json' \
--data '{"query":"mutation CreateApplication {\r\n    application(createApplicationInput: {\r\n        name: \"<newApplicationName>\",\r\n    }) {\r\n        applicationId\r\n        name\r\n        userId\r\n        createdOn\r\n        updatedOn\r\n        status\r\n    }\r\n}","variables":{}}'

Response

{
    "errors": [
        {
            "message": "Forbidden resource",
            "locations": [
                {
                    "line": 2,
                    "column": 5
                }
            ],
            "path": [
                "application"
            ],
            "extensions": {
                "code": "FORBIDDEN",
                "stacktrace": [
                    "ForbiddenException: Forbidden resource",
                    "    at canActivateFn (/home/work/osmosys-repos/osmo-x/apps/api/node_modules/@nestjs/core/helpers/external-context-creator.js:157:23)",
                    "    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)",
                    "    at async target (/home/work/osmosys-repos/osmo-x/apps/api/node_modules/@nestjs/core/helpers/external-context-creator.js:73:31)",
                    "    at async Object.application (/home/work/osmosys-repos/osmo-x/apps/api/node_modules/@nestjs/core/helpers/external-proxy.js:9:24)"
                ],
                "originalError": {
                    "message": "Forbidden resource",
                    "error": "Forbidden",
                    "statusCode": 403
                }
            }
        }
    ],
    "data": null
}

Documentation changes:

  • Update create application request sample in api-documentation.md to not use userID

Test suite/unit testing output:
NA

Pending actions:
NA

Additional notes:
NA

Summary by CodeRabbit

  • New Features

    • Introduced new notification types: Twilio Voice Call, AWS SES, and SNS SMS.
    • Added webhook registration tests for success and error scenarios.
  • Bug Fixes

    • Enhanced error handling in tests for various scenarios, including invalid API keys and missing fields.
  • Improvements

    • Simplified GraphQL mutation for creating applications by removing the userId field.
    • Updated GraphQL mutations to include new properties and improved response structures.
    • Streamlined authorization process by modifying access control for application-related methods.

@kshitij-k-osmosys kshitij-k-osmosys self-assigned this Oct 3, 2024
Copy link

coderabbitai bot commented Oct 3, 2024

Walkthrough

The pull request introduces modifications to the OsmoX API Postman collections, focusing on the removal of the userId field from the CreateApplication mutation. Additionally, it updates the CreateProvider mutation to include providerId in the response. The changes also enhance the Postman collections by adding new notification types, improving error handling, and refining tests for various scenarios. The overall structure of the collections remains intact, with updates to the _postman_id.

Changes

File Path Change Summary
apps/api/OsmoX-API.postman_collection.json Removed userId from CreateApplication mutation input; added providerId to CreateProvider response; updated _postman_id.
apps/api/OsmoX.postman_collection.json Added new notification types with success and error tests; updated GraphQL queries for CreateApplication and CreateProvider; added webhook registration tests; updated _postman_id.
apps/api/src/modules/applications/applications.resolver.ts Added @Roles(UserRoles.ADMIN) for access control; updated @UseGuards to include RolesGuard; simplified method signatures by removing unnecessary parameters.
apps/api/src/modules/applications/applications.service.ts Removed admin role checks; updated createApplication and getAllApplications methods to simplify user validation; replaced checkAdminUser with getUserEntryFromContext.

Possibly related PRs

  • feat: add support for aws ses #305: This PR modifies the OsmoX.postman_collection.json to include updates to GraphQL mutations for creating applications and providers, which aligns with the changes in the main PR that also updates these mutations by removing the userId field and adding providerId in the response.
  • docs: add postman api and environment collection, update setup #329: This PR updates the OsmoX-API.postman_collection.json to include new API endpoints and modifications to existing ones, including the Create new Application mutation, which is directly related to the changes made in the main PR.
  • docs: add usage guide for twilio voice call #336: This PR updates the OsmoX-API.postman_collection.json to enhance the API request structures, including modifications to the GraphQL queries for fetching notifications and applications, which relates to the overall structure and functionality changes in the main PR.

Suggested labels

documentation

Suggested reviewers

  • xixas

🐇 In the land of code where changes bloom,
A rabbit hops in, dispelling the gloom.
With roles and guards, we secure the way,
Removing userId, a brighter day!
Notifications abound, tests now refined,
OsmoX API, a treasure we find! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@kshitij-k-osmosys kshitij-k-osmosys marked this pull request as ready for review October 3, 2024 11:12
Copy link

@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

🧹 Outside diff range and nitpick comments (22)
apps/api/src/common/decorators/roles.decorator.ts (3)

4-5: LGTM: Type definition ensures type safety.

The UserRoleValues type definition correctly restricts the allowed values to those defined in UserRoles, ensuring type safety in the decorator usage.

Consider updating the comment to be more specific:

// Type definition for allowed role values (only values from UserRoles)

7-8: LGTM with suggestions: Roles decorator implementation is correct.

The Roles decorator is correctly implemented using SetMetadata to set roles metadata. The use of rest parameters and UserRoleValues[] type ensures flexible and type-safe role assignment.

Consider the following improvements:

  1. Add an explicit return type to the function.
  2. Remove the ESLint disable comment if the return type is added.
  3. Add a brief JSDoc comment explaining the decorator's usage.

Here's a suggested implementation:

/**
 * Decorator that assigns roles to a route handler.
 * @param roles - The roles to be assigned to the route handler.
 */
export const Roles = (...roles: UserRoleValues[]): MethodDecorator => SetMetadata('roles', roles);

1-8: Summary: Roles decorator implementation aligns with PR objectives.

This new file introduces a Roles decorator that provides a foundation for role-based access control in the application. This aligns well with the PR objectives of addressing issues related to the creation of application requests, as it allows for fine-grained control over who can perform certain actions.

The implementation is correct and type-safe, with only minor suggestions for improvement. This decorator will be a valuable addition to the project's authentication and authorization system.

As you integrate this decorator into the application request creation process:

  1. Ensure that the roles are properly checked in a guard or interceptor.
  2. Update the API documentation to reflect the role requirements for each endpoint.
  3. Consider implementing unit tests for endpoints using this decorator to verify role-based access control.
apps/api/src/modules/providers/providers.resolver.ts (2)

14-15: Effective implementation of role-based access control

The addition of @Roles(UserRoles.ADMIN) and @UseGuards(GqlAuthGuard, RolesGuard) decorators effectively implements role-based access control for the entire ProvidersResolver class. This change restricts access to admin users only, enhancing security.

Consider swapping the order of guards in the @UseGuards decorator to @UseGuards(RolesGuard, GqlAuthGuard). This ensures that authentication is performed before checking roles, which is a more typical and slightly more efficient approach.


1-33: Overall improvement in security and code simplification

The changes in this file significantly enhance the security of the ProvidersResolver by implementing role-based access control. The resolver is now restricted to admin users only, which aligns well with the PR objectives of fixing issues related to the creation of application requests.

The simplification of the createProvider and findAll methods by removing the @Context() parameter and authorizationHeader extraction improves code readability and maintainability. This change is consistent with the new role-based access control implemented at the class level.

Consider documenting these security changes in the project's API documentation to ensure that frontend developers and other team members are aware of the new access restrictions for provider-related operations.

apps/api/src/modules/applications/applications.resolver.ts (1)

14-15: LGTM: Role-based access control implemented correctly.

The addition of @Roles(UserRoles.ADMIN) and the update to @UseGuards(GqlAuthGuard, RolesGuard) correctly implement role-based access control for the ApplicationsResolver class. This ensures that only admin users can access the resolver's methods, which aligns with the PR objectives.

Consider adding a comment explaining the purpose of these guards for better code documentation:

// Ensure only authenticated admin users can access these resolver methods
@Roles(UserRoles.ADMIN)
@UseGuards(GqlAuthGuard, RolesGuard)
apps/api/docs/api-documentation.md (2)

350-351: Approve update to authentication method for fetching applications

The change from server-api-key to Bearer authorization-token is a positive update. It reflects a more standard and secure authentication method using bearer tokens. The explicit mention of the Admin role clarifies the access control for this endpoint.

To ensure consistency throughout the documentation:

  1. Review and update any other mentions of server-api-key to use bearer tokens.
  2. Clarify the Admin role requirement for other admin-only endpoints.

Would you like me to search for other occurrences of server-api-key in the documentation?


Line range hint 1-624: Summary of API documentation changes

The changes in this file enhance the security and clarity of the API documentation:

  1. Removal of userId from the CreateApplication mutation improves security by preventing arbitrary user assignment.
  2. Update to authentication method for fetching applications, using bearer tokens instead of API keys, aligns with modern security practices.

These changes positively impact the API's security posture and provide clearer guidance for API consumers. Ensure these changes are consistently applied across the entire API and its documentation.

Consider implementing the following to further improve API security and usability:

  1. Use OAuth 2.0 or OpenID Connect for more robust authentication and authorization.
  2. Implement rate limiting to protect against abuse.
  3. Add versioning to the API endpoints to facilitate future updates without breaking existing integrations.
apps/api/OsmoX-API.postman_collection.json (1)

784-784: LGTM! Consider updating documentation for this API change.

The removal of the userId field from the createApplicationInput is a good simplification of the API. This change likely means that the server will determine the user ID from the authentication context, which is a more secure and maintainable approach.

To ensure a smooth transition for API consumers:

  1. Update the API documentation to reflect this change.
  2. If not already implemented, ensure that the server correctly extracts the user ID from the authentication context.
  3. Consider adding a deprecation notice in the previous version of the API to inform users of the upcoming change.
apps/api/OsmoX.postman_collection.json (5)

Line range hint 3433-3554: Comprehensive authentication test cases

The authentication-related requests in the collection are well-designed and cover important scenarios, including successful login, invalid credentials, missing password, and bad requests. The use of GraphQL mutations for authentication is consistent with modern API practices.

Positive aspects:

  1. Coverage of both success and error cases
  2. Validation of response structure and error messages
  3. Use of GraphQL mutations for authentication

Suggestion for improvement:
Consider adding a test case for token expiration or refresh to ensure the API handles authentication timeouts correctly.


Line range hint 1-3278: Comprehensive notification test suite

The notification-related requests in the collection are extensive and well-structured, covering various notification types such as SMTP, Mailgun, WhatsApp, SMS, and more. Each notification type includes tests for success cases, error scenarios, and invalid API key handling.

Strengths:

  1. Thorough coverage of multiple notification types
  2. Inclusion of success and error cases for each type
  3. Testing of important scenarios like missing fields and invalid channel types
  4. Use of different provider IDs to ensure proper routing

Suggestion for improvement:
Consider adding test cases for rate limiting and bulk notifications to ensure the API can handle high-volume scenarios efficiently.


Line range hint 3279-4058: Well-designed application and provider management tests

The collection includes comprehensive tests for fetching and creating applications and providers. The use of GraphQL queries and mutations for these operations allows for flexible data fetching and creation.

Positive aspects:

  1. Coverage of success and error cases
  2. Testing of access control scenarios (e.g., non-admin users)
  3. Use of GraphQL for flexible data operations
  4. Inclusion of bad request scenarios

Suggestion for improvement:
Consider adding test cases for updating and deleting applications and providers to ensure full CRUD functionality is covered.


Line range hint 4059-4365: Effective webhook and server key management tests

The collection includes well-designed tests for webhook registration and server key generation. The use of GraphQL mutations for these operations is consistent with the rest of the collection.

Strengths:

  1. Coverage of success and error cases
  2. Testing of important scenarios like duplicate webhooks and unknown providers
  3. Consistent use of GraphQL mutations

Suggestion for improvement:
Consider adding test cases for webhook updates and deletions, as well as key rotation or revocation scenarios, to ensure comprehensive coverage of these features.


Line range hint 1-4365: Excellent and comprehensive API test collection

This Postman collection for the OsmoX API is exceptionally well-structured and comprehensive. It covers a wide range of functionality, including authentication, various notification types, application and provider management, webhook registration, and server key generation.

Key strengths:

  1. Thorough coverage of API functionality
  2. Consistent use of GraphQL for flexible data operations
  3. Inclusion of both success and error scenarios for each feature
  4. Well-organized folder structure for easy navigation
  5. Use of environment variables for sensitive data

Suggestions for further improvement:

  1. Add test cases for rate limiting and bulk operations to ensure API performance under load
  2. Include tests for updating and deleting resources where applicable (e.g., applications, providers, webhooks)
  3. Add scenarios for token refresh and expiration in authentication tests
  4. Consider adding tests for key rotation or revocation in server key management
  5. Implement data-driven tests using Postman's data file feature to test with multiple input sets

Overall, this collection provides a solid foundation for testing the OsmoX API and will greatly aid in maintaining API quality and reliability.

apps/api/src/common/guards/role.guard.ts (3)

40-41: Define an interface for the decoded JWT token

For type safety and clarity, define an interface representing the expected structure of the decoded token.

Add the interface:

interface DecodedToken {
  role: UserRoles;
  // Add other properties as needed
}

Update the token verification:

- const decodedToken = this.jwtService.verify(token, { secret });
+ const decodedToken = this.jwtService.verify<DecodedToken>(token, { secret });
const userRoleId = decodedToken.role;

35-36: Handle missing JWT secret configuration gracefully

While getOrThrow will throw an error if JWT_SECRET is not set, providing a clear error message can aid in debugging configuration issues.

Consider wrapping this in a try-catch block with a custom error message:

- const secret = this.configService.getOrThrow('JWT_SECRET');
+ let secret: string;
+ try {
+   secret = this.configService.getOrThrow('JWT_SECRET');
+ } catch (error) {
+   throw new InternalServerErrorException('JWT secret is not configured');
+ }

1-7: Organize imports according to project conventions

Review the import statement order to match the project's coding standards, such as grouping external and internal imports separately.

Example of organized imports:

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { GqlExecutionContext } from '@nestjs/graphql';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';

import { UserRoles } from 'src/common/constants/database';
apps/api/src/modules/providers/providers.service.ts (2)

Line range hint 30-43: Security Concern: Removal of Authorization Checks in createProvider Method

The createProvider method no longer includes an authorization check to verify if the user has the necessary permissions to create a provider. Removing the authorizationHeader parameter and the associated admin check may allow unauthorized users to perform this action, potentially leading to security vulnerabilities.

Consider reintroducing the authorization logic to ensure that only authorized users can create providers. If the authorization checks have been moved to a different layer (e.g., controller or middleware), please verify that they are effectively preventing unauthorized access.


Line range hint 65-73: Security Concern: Removal of Authorization Checks in getAllProviders Method

By removing the authorizationHeader parameter and the associated admin check from the getAllProviders method, the code may allow unauthorized users to retrieve all providers. This could expose sensitive data and pose security risks.

Ensure that appropriate access control mechanisms are in place to restrict access to this method. If authorization is handled elsewhere in the application (such as in a middleware or a higher-level controller), please confirm that it adequately protects this endpoint.

apps/api/src/modules/applications/applications.service.ts (3)

Line range hint 50-77: Fix Incorrect Extraction of Authorization Header

In getUserEntryFromToken, you're using authHeader.toString() to get the bearer token, which is incorrect since authHeader is a Request object. This can cause issues in token extraction and lead to unauthorized access errors.

Update the method to extract the Authorization header correctly from the request:

- async getUserEntryFromToken(authHeader: Request): Promise<User> {
+ async getUserEntryFromToken(request: Request): Promise<User> {
     try {
-      const bearerToken = authHeader.toString();
+      const bearerToken = request.headers['authorization'] || request.headers['Authorization'];
       if (!bearerToken || !bearerToken.startsWith('Bearer ')) {
         throw new UnauthorizedException('Missing or malformed authorization header');
       }
🧰 Tools
🪛 Biome

[error] 77-77: The catch clause that only rethrows the original error is redundant.

These unnecessary catch clauses can be confusing. It is recommended to remove them.

(lint/complexity/noUselessCatch)


Line range hint 50-77: Remove Redundant Catch Block

The catch block in getUserEntryFromToken rethrows the original error without additional handling, making it unnecessary. This adds extra complexity without benefit.

Simplify the code by removing the redundant try...catch block:

async getUserEntryFromToken(request: Request): Promise<User> {
-   try {
      const bearerToken = request.headers['authorization'] || request.headers['Authorization'];
      if (!bearerToken || !bearerToken.startsWith('Bearer ')) {
        throw new UnauthorizedException('Missing or malformed authorization header');
      }
      // ... rest of your code ...
      return userEntry;
-   } catch (error) {
-     throw error;
-   }
}
🧰 Tools
🪛 Biome

[error] 77-77: The catch clause that only rethrows the original error is redundant.

These unnecessary catch clauses can be confusing. It is recommended to remove them.

(lint/complexity/noUselessCatch)


Security Concern Confirmed: Unrestricted Access to All Applications

The getAllApplications method in apps/api/src/modules/applications/applications.service.ts does not perform an admin role check, allowing any authenticated user to retrieve all application records. This could expose sensitive data to unauthorized users.

  • File: apps/api/src/modules/applications/applications.service.ts
  • Method: getAllApplications
🔗 Analysis chain

Line range hint 81-86: Security Concern: Unrestricted Access to All Applications

The getAllApplications method no longer checks for admin privileges, allowing any authenticated user to retrieve all application records. This could expose sensitive data to unauthorized users.

Please verify if removing the admin role check is intentional and aligns with the project's security requirements. If not, consider reintroducing role-based access control.

To help verify role checks in the codebase, run the following script:


[/run_scripts]


[/run_scripts]

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for admin role checks in ApplicationsService.

rg --type typescript 'ApplicationsService' -A 50 | rg 'UserRoles.ADMIN' -A 5

Length of output: 109


Script:

#!/bin/bash
# Description: Search for admin role checks in ApplicationsService within TypeScript files.

# Search for ApplicationsService.ts or ApplicationsService.tsx files and then look for UserRoles.ADMIN within them
rg 'ApplicationsService' --glob '*.ts*' -A 50 | rg 'UserRoles\.ADMIN' -A 5

Length of output: 658


Script:

#!/bin/bash
# Description: Verify presence of admin role checks in ApplicationsService.ts.

rg 'UserRoles\.ADMIN' apps/api/src/modules/applications/applications.service.ts -A 5

Length of output: 86

🧰 Tools
🪛 Biome

[error] 77-77: The catch clause that only rethrows the original error is redundant.

These unnecessary catch clauses can be confusing. It is recommended to remove them.

(lint/complexity/noUselessCatch)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 683266a and 40afcc3.

📒 Files selected for processing (10)
  • apps/api/OsmoX-API.postman_collection.json (1 hunks)
  • apps/api/OsmoX.postman_collection.json (7 hunks)
  • apps/api/docs/api-documentation.md (1 hunks)
  • apps/api/src/common/decorators/roles.decorator.ts (1 hunks)
  • apps/api/src/common/guards/role.guard.ts (1 hunks)
  • apps/api/src/modules/applications/applications.resolver.ts (2 hunks)
  • apps/api/src/modules/applications/applications.service.ts (3 hunks)
  • apps/api/src/modules/applications/dto/create-application.input.ts (0 hunks)
  • apps/api/src/modules/providers/providers.resolver.ts (1 hunks)
  • apps/api/src/modules/providers/providers.service.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/api/src/modules/applications/dto/create-application.input.ts
🧰 Additional context used
🪛 Biome
apps/api/src/modules/applications/applications.service.ts

[error] 77-77: The catch clause that only rethrows the original error is redundant.

These unnecessary catch clauses can be confusing. It is recommended to remove them.

(lint/complexity/noUselessCatch)

🔇 Additional comments (10)
apps/api/src/common/decorators/roles.decorator.ts (1)

1-2: LGTM: Imports are appropriate for the decorator implementation.

The imports of SetMetadata from '@nestjs/common' and UserRoles from '../constants/database' are correctly chosen for implementing a role-based decorator in NestJS.

apps/api/src/modules/providers/providers.resolver.ts (3)

9-11: Improved security with role-based access control

The addition of Roles, UserRoles, and RolesGuard imports indicates a shift towards role-based access control. This change enhances the security of the application by restricting access to authorized roles.


30-31: Simplified findAll method

The removal of the @Context() parameter and authorizationHeader extraction simplifies the findAll method. This change is consistent with the new role-based access control implemented at the class level.

Please verify that the providerService.getAllProviders method no longer requires the authorizationHeader. Run the following script to check the method signature:

#!/bin/bash
# Description: Verify the signature of the getAllProviders method in the ProvidersService

ast-grep --lang typescript --pattern $'class ProvidersService {
  $$$
  getAllProviders($_) {
    $$$
  }
  $$$
}'

22-23: Simplified createProvider method

The removal of the @Context() parameter and authorizationHeader extraction simplifies the createProvider method. This change is consistent with the new role-based access control implemented at the class level.

Please verify that the providerService.createProvider method no longer requires the authorizationHeader. Run the following script to check the method signature:

✅ Verification successful

Verification of providerService.createProvider Method

The createProvider method in ProvidersService no longer requires the authorizationHeader parameter. This aligns with the updated role-based access control implemented at the class level.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the signature of the createProvider method in the ProvidersService

ast-grep --lang typescript --pattern $'class ProvidersService {
  $$$
  createProvider($_) {
    $$$
  }
  $$$
}'

Length of output: 115


Script:

#!/bin/bash
# Description: Search for the createProvider method in ProvidersService to verify its signature

rg 'class\s+ProvidersService' -A 20 | rg 'createProvider\s*\('

Length of output: 196

apps/api/src/modules/applications/applications.resolver.ts (2)

9-11: LGTM: New imports for role-based access control.

The new imports for Roles, RolesGuard, and UserRoles are correctly added and necessary for implementing role-based access control (RBAC) in the resolver.


37-37: LGTM: Simplified findAll method, but verify ApplicationsService changes.

The simplification of the findAll method by removing the @Context() parameter and authorizationHeader usage is a good improvement. This change aligns with the PR objectives of streamlining the authorization process.

Please ensure that the ApplicationsService.getAllApplications method has been updated to no longer expect the authorizationHeader parameter. Run the following script to verify:

apps/api/docs/api-documentation.md (1)

Line range hint 310-315: Approve removal of userId from CreateApplication mutation

The removal of the userId parameter from the CreateApplication mutation is a positive change. It enhances security by preventing arbitrary user assignment during application creation. This change implies that the API now determines the user internally, likely from the authentication token.

To ensure this change is correctly implemented, please verify the backend logic:

Also applies to: 321-326

✅ Verification successful

Verified: userId parameter has been successfully removed from the CreateApplication mutation. No references found in the backend code.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the backend correctly associates the application with the authenticated user

# Test: Search for the application creation logic
rg --type typescript "createApplication.*userId" apps/api/src

Length of output: 98


Script:

#!/bin/bash
# Description: Verify that the backend correctly associates the application with the authenticated user

# Test: Search for the application creation logic without specifying file type
rg "createApplication.*userId" apps/api/src --type-add 'ts=**/*.ts' --type-add 'tsx=**/*.tsx' --files-with-matches

Length of output: 176


Script:

#!/bin/bash
# Description: Verify that the backend correctly associates the application with the authenticated user

# Test: Search for the application creation logic without specifying file type, using correct type definitions
rg "createApplication.*userId" apps/api/src --type-add 'ts:*.ts' --type-add 'tsx:*.tsx' --files-with-matches

Length of output: 110

apps/api/OsmoX.postman_collection.json (1)

Line range hint 1-4365: Well-structured and comprehensive Postman collection

The OsmoX Postman collection is well-organized and covers a wide range of functionality for the API. It includes various request folders for different types of notifications and API operations, with tests for both success and error scenarios. The collection's structure makes it easy to navigate and test different aspects of the API, including authentication, notifications, applications, providers, webhooks, and server keys.

Good practices observed:

  1. Comprehensive coverage of API functionality
  2. Inclusion of both success and error test cases
  3. Use of environment variables for sensitive data
  4. Well-organized folder structure
apps/api/src/common/guards/role.guard.ts (2)

23-25: Verify default access behavior when no roles are specified

The guard currently allows access when no roles are specified. Confirm that this is the intended behavior, as it might lead to unsecured endpoints if roles are not properly set.


18-21: Confirm the retrieval of required roles

Ensure that the metadata key 'roles' is correctly set using a custom decorator or metadata assignment on route handlers and classes that utilize this guard.

You can use the following script to list all handlers with the 'roles' metadata:

✅ Verification successful

Required roles retrieval confirmed.

The @Roles(UserRoles.ADMIN) decorator is correctly applied to the relevant route handlers in:

  • apps/api/src/modules/providers/providers.resolver.ts
  • apps/api/src/modules/applications/applications.resolver.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all methods with 'roles' metadata in the project.

# Search for the '@Roles' decorator usage
rg --type ts '@Roles\(' -A 2 src/

Length of output: 80


Script:

#!/bin/bash
# Description: Find all methods with 'roles' metadata in the project.

# Search for the '@Roles' decorator usage across the entire repository
rg --type ts '@Roles\(' -A 2

Length of output: 560


Script:

#!/bin/bash
# Description: Extract all roles assigned via the '@Roles' decorator in the project.

# Search for the '@Roles(UserRoles.<ROLE>)' pattern and extract the role names
rg --type ts '@Roles\(UserRoles\.(\w+)\)' -o --only-matching | grep -o 'UserRoles\.\w\+' | awk -F. '{print $2}' | sort | uniq

Length of output: 133

apps/api/src/common/guards/role.guard.ts Show resolved Hide resolved
apps/api/src/common/guards/role.guard.ts Show resolved Hide resolved
apps/api/src/common/guards/role.guard.ts Show resolved Hide resolved
apps/api/src/modules/applications/applications.service.ts Outdated Show resolved Hide resolved
@kshitij-k-osmosys kshitij-k-osmosys changed the title fix: create application request fix: create application request and role guard introduction Oct 3, 2024
Copy link

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

🧹 Outside diff range and nitpick comments (5)
apps/api/OsmoX.postman_collection.json (5)

3279-3283: Comprehensive authentication testing with room for improvement

The authentication-related requests in the collection are well-designed and cover essential scenarios. However, there's a minor inconsistency in the error handling tests:

pm.test("message: Forbidden resource", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property("data");
    pm.expect(jsonData).to.have.property("errors").to.be.an("array");
    pm.expect(jsonData.errors[0]).to.have.property("message", "Forbidden resource");
});

This test is repeated in multiple places with slight variations. To improve maintainability and consistency, consider extracting this common test into a reusable function.


Line range hint 1-4329: Comprehensive notification testing across multiple channels

The collection includes a wide range of notification-related requests, covering various channels such as SMTP, Mailgun, WhatsApp, SMS, and more. Key points:

  1. Well-organized structure with separate folders for each notification type
  2. Consistent use of x-api-key header for authentication
  3. Thorough error scenario coverage (invalid API keys, missing fields, mismatched channel types)
  4. Detailed test scripts validating response structure and specific fields

To further enhance the collection, consider adding a test for rate limiting or throttling, if applicable to the API. This would help ensure the API behaves correctly under high load scenarios.


Line range hint 1-4329: Well-structured application and provider management requests

The collection includes comprehensive requests for managing applications and providers:

  1. Separate folders for listing and creating applications and providers
  2. Both query (GET) and mutation (POST) operations are covered
  3. Error scenarios for non-admin users and bad requests are included
  4. Consistent use of GraphQL queries and mutations

To improve the collection further, consider adding requests for updating and deleting applications and providers if these operations are supported by the API. This would complete the CRUD (Create, Read, Update, Delete) cycle for these entities.


Line range hint 1-4329: Solid coverage of webhook and server key operations

The collection includes well-structured requests for webhook registration and server key generation:

  1. Webhook registration covers success and error scenarios (existing provider, unknown provider)
  2. Server key generation includes success and error cases
  3. Test scripts validate response structures and error messages

To enhance this section, consider adding the following:

  1. A request for listing registered webhooks, if supported by the API
  2. A request for revoking or deleting server keys
  3. A request for refreshing or updating existing webhooks

These additions would provide a more complete set of operations for webhook and key management.


Line range hint 1-4329: Excellent Postman collection with room for minor enhancements

Overall, the OsmoX.postman_collection.json file presents a high-quality, comprehensive Postman collection for testing the OsmoX API. Key strengths include:

  1. Wide coverage of API functionalities (authentication, notifications, applications, providers, webhooks, and server keys)
  2. Consistent use of test scripts for validating responses
  3. Thorough representation of both success and error scenarios
  4. Well-structured organization with separate folders for different functionalities

To further improve this already solid collection, consider:

  1. Implementing reusable test functions for common assertions
  2. Adding rate limiting/throttling tests for the notification endpoints
  3. Including update and delete operations for applications and providers
  4. Expanding webhook and server key management with additional operations (list, revoke, refresh)
  5. Ensuring all environment variables are properly documented

These enhancements would elevate the collection from excellent to outstanding, providing even more comprehensive API testing and documentation capabilities.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 40afcc3 and 3d59bc4.

📒 Files selected for processing (2)
  • apps/api/OsmoX-API.postman_collection.json (3 hunks)
  • apps/api/OsmoX.postman_collection.json (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/OsmoX-API.postman_collection.json
🔇 Additional comments (1)
apps/api/OsmoX.postman_collection.json (1)

Line range hint 1-4329: Well-structured and comprehensive Postman collection

The OsmoX.postman_collection.json file presents a well-organized and thorough Postman collection for testing the OsmoX API. It includes:

  1. Separate folders for different types of notifications and functionalities
  2. Comprehensive test coverage with success and error scenarios
  3. Proper use of environment variables for dynamic values
  4. Consistent structure across different requests

This collection will be valuable for API testing and documentation purposes.

Copy link

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

🧹 Outside diff range and nitpick comments (5)
apps/api/src/modules/applications/applications.resolver.ts (3)

9-11: LGTM! Role-based access control implemented correctly.

The addition of Roles, RolesGuard, and UserRoles imports, along with the @Roles(UserRoles.ADMIN) and @UseGuards(GqlAuthGuard, RolesGuard) decorators, effectively implements role-based access control for the ApplicationsResolver class. This aligns well with the PR objectives.

Consider grouping related imports together for better readability:

import { UseGuards } from '@nestjs/common';
import { Args, Context, Mutation, Resolver, Query } from '@nestjs/graphql';
import { Roles } from 'src/common/decorators/roles.decorator';
import { GqlAuthGuard } from 'src/common/guards/api-key/gql-auth.guard';
import { RolesGuard } from 'src/common/guards/role.guard';
import { UserRoles } from 'src/common/constants/database';
// ... other imports

Also applies to: 14-15


24-25: LGTM! Simplified user ID extraction.

The changes to the createApplication method effectively simplify the user ID extraction process by directly accessing context.req.userId. This aligns with the PR objectives and improves code readability.

Consider adding a null check for context.req.userId to handle potential edge cases:

const requestUserId: number = context.req.userId;
if (!requestUserId) {
  throw new Error('User ID not found in request context');
}
return await this.applicationsService.createApplication(createApplicationInput, requestUserId);

Line range hint 1-34: Overall, excellent implementation of role-based access control and code simplification.

The changes in this file successfully implement role-based access control for the ApplicationsResolver class and simplify the method implementations. Key improvements include:

  1. Addition of @Roles(UserRoles.ADMIN) decorator to restrict access to admin users.
  2. Implementation of RolesGuard alongside GqlAuthGuard for comprehensive authorization.
  3. Simplification of the createApplication method by directly using context.req.userId.
  4. Streamlining of the findAll method by removing unnecessary context parameters.

These changes align well with the PR objectives and contribute to improved security and code maintainability.

Consider documenting the role-based access control implementation in the project's architecture documentation to ensure that other developers understand and follow this pattern in future resolver implementations.

apps/api/src/modules/applications/applications.service.ts (2)

35-40: Improved createApplication implementation

The updated implementation correctly uses getUserEntryFromContext to retrieve user information and creates a new Application object with the authenticated user's ID. This change enhances security and aligns with the PR objectives.

However, consider adding error handling for cases where getUserEntryFromContext might throw an exception:

Consider wrapping the implementation in a try-catch block to handle potential errors:

try {
  const userEntryFromContext = await this.getUserEntryFromContext(requestUserId);

  const newApplicationObject = new Application({
    name: applicationInput.name,
    userId: userEntryFromContext.userId,
  });

  const application = this.applicationsRepository.create(newApplicationObject);
  return this.applicationsRepository.save(application);
} catch (error) {
  // Log the error
  console.error('Error creating application:', error);
  throw new Error('Failed to create application');
}

This addition will provide better error handling and logging for troubleshooting purposes.


46-59: New getUserEntryFromContext method implementation

The new getUserEntryFromContext method effectively replaces the previous checkAdminUser method, aligning with the PR objective of implementing role guards for API access. It correctly retrieves the user entry and throws an UnauthorizedException if the user is not found.

Remove the redundant catch clause as suggested by the static analysis tool:

async getUserEntryFromContext(requestUserId: number): Promise<User> {
  // Find the related user entry using the user ID from the token
  const userEntry = await this.usersService.findByUserId(requestUserId);

  if (!userEntry) {
    throw new UnauthorizedException('User not found');
  }

  return userEntry;
}

This change simplifies the method without altering its functionality.

🧰 Tools
🪛 Biome

[error] 57-57: The catch clause that only rethrows the original error is redundant.

These unnecessary catch clauses can be confusing. It is recommended to remove them.

(lint/complexity/noUselessCatch)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 3d59bc4 and bbed12e.

📒 Files selected for processing (2)
  • apps/api/src/modules/applications/applications.resolver.ts (2 hunks)
  • apps/api/src/modules/applications/applications.service.ts (2 hunks)
🧰 Additional context used
🪛 Biome
apps/api/src/modules/applications/applications.service.ts

[error] 57-57: The catch clause that only rethrows the original error is redundant.

These unnecessary catch clauses can be confusing. It is recommended to remove them.

(lint/complexity/noUselessCatch)

🔇 Additional comments (4)
apps/api/src/modules/applications/applications.resolver.ts (1)

28-33: LGTM! Simplified findAll method.

The removal of the @Context() parameter and the simplification of the getAllApplications service method call improve code clarity and align with the PR objectives.

Please verify that the getAllApplications method in the ApplicationsService has been updated to no longer require a user ID or authorization header. Run the following script to check the method signature:

apps/api/src/modules/applications/applications.service.ts (3)

7-7: Import changes align with code modifications

The addition of Status and User imports, along with the removal of UserRoles and JwtService imports, correctly reflects the changes in the service implementation. These modifications support the transition from role-based access control to direct user validation.

Also applies to: 11-11


33-34: Improved method signature for createApplication

The updated method signature now correctly accepts requestUserId: number instead of authorizationHeader: Request. This change:

  1. Aligns with the PR objective of retrieving the user ID from the authentication token.
  2. Addresses the potential bug raised in a previous review comment about incorrect parameter type.
  3. Follows the suggestion to obtain user data from the request context.

These modifications enhance the security and correctness of the application creation process.


61-61: Simplified getAllApplications method signature

The removal of the authorizationHeader parameter from the getAllApplications method signature aligns with the PR objective of updating the functionality to retrieve user information from the authentication context rather than passing it explicitly.

However, the removal of this parameter also suggests that role-based access control for this method has been removed. Please clarify if this is intentional and if there are any other mechanisms in place to ensure proper access control for retrieving all applications.

To verify the impact of this change, please run the following script:

This script will help identify any remaining role-based checks or other access control mechanisms related to the getAllApplications method.

@xixas xixas merged commit b077b5f into main Oct 10, 2024
6 checks passed
@xixas xixas deleted the fix/create-application branch October 10, 2024 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants