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

feat: Add approval support #158

Merged
merged 8 commits into from
Mar 7, 2024
Merged

feat: Add approval support #158

merged 8 commits into from
Mar 7, 2024

Conversation

rajdip-b
Copy link
Member

@rajdip-b rajdip-b commented Mar 3, 2024

Type

enhancement, bug_fix


Description

  • Added e2e tests for the Approval module, covering creation, update, and deletion of approvals for workspaces, projects, environments, secrets, and variables.
  • Commented out all existing tests in the Event module e2e test file due to changes in event handling.
  • Adjusted Workspace e2e tests to include approvalEnabled flag and commented out event creation tests.
  • Implemented approval creation for secret actions (create, update, delete, rollback) when workspace approval is enabled.
  • Added support for approval creation in variable service actions including create, update, delete, and rollback.
  • Integrated approval workflow into project service actions such as create, update, and delete.

Changes walkthrough

Relevant files
Tests
approval.e2e.spec.ts
Add e2e Tests for Approval Module Covering Various Scenarios

apps/api/src/approval/approval.e2e.spec.ts

  • Added comprehensive e2e tests for the Approval module, covering
    scenarios like creating, updating, and deleting approvals for various
    items such as workspaces, projects, environments, secrets, and
    variables.
  • Tested approval view permissions based on user roles and specific
    authorities like WORKSPACE_ADMIN and MANAGE_APPROVALS.
  • Included tests for approval actions such as approve, reject, and
    checking for duplicate names upon approval.
  • Ensured proper handling of pending creation items and their approvals.

  • +1408/-0
    event.e2e.spec.ts
    Comment Out Event Module e2e Tests                                             

    apps/api/src/event/event.e2e.spec.ts

  • Commented out all existing tests in the Event module e2e test file.
  • +344/-340
    workspace.e2e.spec.ts
    Adjust Workspace e2e Tests and Comment Out Event Creation Tests

    apps/api/src/workspace/workspace.e2e.spec.ts

  • Commented out tests related to event creation upon workspace actions.
  • Minor adjustments to workspace creation tests to include
    approvalEnabled flag.
  • +227/-224
    Enhancement
    secret.service.ts
    Support Approval Workflow in Secret Service Actions           

    apps/api/src/secret/service/secret.service.ts

  • Implemented approval creation for secret actions (create, update,
    delete, rollback) when workspace approval is enabled.
  • Added checks for pending creation status and workspace approval
    settings before proceeding with secret actions.
  • Refactored secret action methods to handle approval creation and
    secret updates separately.
  • +378/-159
    variable.service.ts
    Implement Approval Workflow Support in Variable Service   

    apps/api/src/variable/service/variable.service.ts

  • Added support for approval creation in variable service actions
    including create, update, delete, and rollback.
  • Included checks for workspace approval settings and pending creation
    status.
  • Separated variable action logic into distinct methods for handling
    approvals and direct updates.
  • +383/-155
    project.service.ts
    Integrate Approval Workflow into Project Service Actions 

    apps/api/src/project/service/project.service.ts

  • Integrated approval workflow into project service actions such as
    create, update, and delete.
  • Added logic to check for workspace approval settings and project's
    pending creation status.
  • Refactored project action methods to support approval creation and
    direct project updates.
  • +276/-108

    PR-Agent usage:
    Comment /help on the PR to get a list of all available PR-Agent tools and their descriptions

    @rajdip-b rajdip-b marked this pull request as draft March 3, 2024 18:32
    @codiumai-pr-agent-free codiumai-pr-agent-free bot added type: enhancement New feature or request Tests labels Mar 3, 2024
    Copy link
    Contributor

    PR Description updated to latest commit (ab399e5)

    Copy link
    Contributor

    codiumai-pr-agent-free bot commented Mar 3, 2024

    PR Review

    (Review updated until commit 7f7a29d)

    ⏱️ Estimated effort to review [1-5]

    5, due to the extensive changes across multiple files, including the addition of new functionalities related to approval workflows, updates to existing services to integrate approval checks, and modifications to tests. The complexity and breadth of these changes necessitate a thorough review to ensure correctness, security, and adherence to best practices.

    🧪 Relevant tests

    Yes

    🔍 Possible issues

    Possible Bug: In secret.service.ts, when creating or updating secrets (and similarly for variables, projects, and environments), the approval process is initiated only if the workspace approval is enabled. However, there's no check to ensure that the approval process completes successfully before proceeding. This could potentially lead to inconsistencies if the approval creation fails but the secret creation/update proceeds.

    Security Concern: The reason parameter in workspace.controller.ts for update operations is directly passed to the service layer without any sanitation or validation. This could potentially be exploited to inject malicious data if not properly handled at the service or database layer.

    Performance Concern: The approval checks are performed sequentially in the services (e.g., secret.service.ts, variable.service.ts). In workspaces with a large number of pending approvals, this could introduce latency. Consider optimizing the database queries or caching workspace approval states to improve performance.

    🔒 Security concerns

    SQL Injection: The direct use of query parameters (e.g., the reason parameter in workspace.controller.ts) without explicit validation or sanitation could expose the application to SQL injection vulnerabilities if these parameters are used in constructing SQL queries.

    Code feedback:
    relevant fileapps/api/src/secret/service/secret.service.ts
    suggestion      

    Consider implementing a transaction or a rollback mechanism when creating approvals to ensure atomicity. This way, if the approval creation fails, the secret creation/update does not proceed, maintaining data integrity. [important]

    relevant lineapprovalEnabled

    relevant fileapps/api/src/workspace/controller/workspace.controller.ts
    suggestion      

    Validate or sanitize the reason query parameter in update operations to prevent potential security vulnerabilities, such as SQL injection or cross-site scripting (XSS). [important]

    relevant line@Query('reason') reason: string

    relevant fileapps/api/src/secret/service/secret.service.ts
    suggestion      

    For performance optimization, consider caching the result of workspaceApprovalEnabled checks or using more efficient database queries to reduce the overhead of checking approval status in high-load scenarios. [medium]

    relevant line(await workspaceApprovalEnabled(secret.project.workspaceId, this.prisma))

    relevant fileapps/api/src/secret/service/secret.service.ts
    suggestion      

    To improve code modularity and readability, consider refactoring the approval creation logic into a separate method or service that handles approval-related operations. This can help isolate the approval logic from the business logic of creating or updating secrets. [medium]

    relevant linereturn await createApproval(


    ✨ Review tool usage guide:

    Overview:
    The review tool scans the PR code changes, and generates a PR review. The tool can be triggered automatically every time a new PR is opened, or can be invoked manually by commenting on any PR.
    When commenting, to edit configurations related to the review tool (pr_reviewer section), use the following template:

    /review --pr_reviewer.some_config1=... --pr_reviewer.some_config2=...
    

    With a configuration file, use the following template:

    [pr_reviewer]
    some_config1=...
    some_config2=...
    
    Utilizing extra instructions

    The review tool can be configured with extra instructions, which can be used to guide the model to a feedback tailored to the needs of your project.

    Be specific, clear, and concise in the instructions. With extra instructions, you are the prompter. Specify the relevant sub-tool, and the relevant aspects of the PR that you want to emphasize.

    Examples for extra instructions:

    [pr_reviewer] # /review #
    extra_instructions="""
    In the 'possible issues' section, emphasize the following:
    - Does the code logic cover relevant edge cases?
    - Is the code logic clear and easy to understand?
    - Is the code logic efficient?
    ...
    """
    

    Use triple quotes to write multi-line instructions. Use bullet points to make the instructions more readable.

    How to enable\disable automation
    • When you first install PR-Agent app, the default mode for the review tool is:
    pr_commands = ["/review", ...]
    

    meaning the review tool will run automatically on every PR, with the default configuration.
    Edit this field to enable/disable the tool, or to change the used configurations

    Auto-labels

    The review tool can auto-generate two specific types of labels for a PR:

    • a possible security issue label, that detects possible security issues (enable_review_labels_security flag)
    • a Review effort [1-5]: x label, where x is the estimated effort to review the PR (enable_review_labels_effort flag)
    Extra sub-tools

    The review tool provides a collection of possible feedbacks about a PR.
    It is recommended to review the possible options, and choose the ones relevant for your use case.
    Some of the feature that are disabled by default are quite useful, and should be considered for enabling. For example:
    require_score_review, require_soc2_ticket, and more.

    Auto-approve PRs

    By invoking:

    /review auto_approve
    

    The tool will automatically approve the PR, and add a comment with the approval.

    To ensure safety, the auto-approval feature is disabled by default. To enable auto-approval, you need to actively set in a pre-defined configuration file the following:

    [pr_reviewer]
    enable_auto_approval = true
    

    (this specific flag cannot be set with a command line argument, only in the configuration file, committed to the repository)

    You can also enable auto-approval only if the PR meets certain requirements, such as that the estimated_review_effort is equal or below a certain threshold, by adjusting the flag:

    [pr_reviewer]
    maximal_review_effort = 5
    
    More PR-Agent commands

    To invoke the PR-Agent, add a comment using one of the following commands:

    • /review: Request a review of your Pull Request.
    • /describe: Update the PR title and description based on the contents of the PR.
    • /improve [--extended]: Suggest code improvements. Extended mode provides a higher quality feedback.
    • /ask <QUESTION>: Ask a question about the PR.
    • /update_changelog: Update the changelog based on the PR's contents.
    • /add_docs 💎: Generate docstring for new components introduced in the PR.
    • /generate_labels 💎: Generate labels for the PR based on the PR's contents.
    • /analyze 💎: Automatically analyzes the PR, and presents changes walkthrough for each component.

    See the tools guide for more details.
    To list the possible configuration parameters, add a /config comment.

    See the review usage page for a comprehensive guide on using this tool.

    Copy link
    Contributor

    codiumai-pr-agent-free bot commented Mar 3, 2024

    PR Code Suggestions

    CategorySuggestions                                                                                                                                                       
    Best practice
    Use beforeEach to reset shared state before each test.

    Consider using beforeEach to reset the state before each test to ensure test isolation and
    avoid potential side effects between tests. This can be particularly useful for resetting
    the totalEvents array and any other shared state.

    apps/api/src/event/event.e2e.spec.ts [109]

     describe('Event Controller Tests', () => {
    +  beforeEach(() => {
    +    // Reset shared state here, e.g., totalEvents = [];
    +  });
     
    Use it.skip for skipping tests instead of commenting them out.

    Instead of commenting out entire test cases, consider using it.skip for temporarily
    skipping tests. This approach is cleaner and allows you to specify a reason for skipping
    the test.

    apps/api/src/event/event.e2e.spec.ts [114]

    -// it('should be able to fetch a user event', async () => {
    +it.skip('should be able to fetch a user event', async () => {
    +  // Reason: Pending implementation or issue XYZ-123
     
    Move setup code into the test case or beforeEach for clarity and self-containment.

    To improve test readability and ensure that each test case is self-contained, consider
    moving the setup code (e.g., creating a new workspace, project, or variable) into the test
    case itself or using beforeEach for shared setup logic.

    apps/api/src/event/event.e2e.spec.ts [169-173]

    -const newWorkspace = await workspaceService.createWorkspace(user, {
    -  name: 'My workspace',
    -  ...
    -})
    +beforeEach(async () => {
    +  workspace = await workspaceService.createWorkspace(user, {
    +    name: 'My workspace',
    +    ...
    +  });
    +});
     
    Test error handling logic by mocking service calls to throw errors.

    To ensure that tests are correctly handling errors, consider explicitly testing the error
    handling logic by mocking the service calls to throw errors and then asserting that the
    error is handled as expected.

    apps/api/src/event/event.e2e.spec.ts [397]

    -// it('should throw an error if user is not provided in event creation for user-triggered event', async () => {
    +it('should throw an error if user is not provided in event creation for user-triggered event', async () => {
    +  // Mock the service to throw an error
    +  jest.spyOn(eventService, 'createEvent').mockImplementation(() => {
    +    throw new Error('User not provided');
    +  });
    +  // Add your test logic here
    +});
     
    Use a transaction for related database operations.

    Use a transaction when performing multiple related database operations to ensure data
    integrity.

    apps/api/src/secret/service/secret.service.ts [95-106]

    -const secret = await this.prisma.secret.create({
    +const secret = await this.prisma.$transaction(async (prisma) => {
    +  return await prisma.secret.create({
         data: {
           name: dto.name,
           note: dto.note,
           rotateAt: addHoursToDate(dto.rotateAfter),
           pendingCreation:
             project.pendingCreation ||
             environment.pendingCreation ||
             approvalEnabled,
           versions: {
             create: {
               value: await encrypt(project.publicKey, dto.value),
             }
           }
         }
       })
    +})
     
    Add error handling for database operations.

    Ensure consistent error handling across all methods that perform database operations or
    other actions that might fail.

    apps/api/src/secret/service/secret.service.ts [508-512]

    -const secret = await this.prisma.secret.findUnique({
    -    where: {
    -      id: secretId
    -    }
    -  })
    +let secret;
    +try {
    +  secret = await this.prisma.secret.findUnique({
    +      where: {
    +        id: secretId
    +      }
    +    })
    +} catch (error) {
    +  // Handle error appropriately
    +}
     
    Use a transaction for creating a variable and its approval.

    Use a transaction for creating a variable and its approval to ensure data consistency and
    rollback in case of failure.

    apps/api/src/variable/service/variable.service.ts [88-95]

    -const variable = await this.prisma.variable.create({
    -  data: {
    -    name: dto.name,
    -    note: dto.note,
    -    pendingCreation:
    -      project.pendingCreation ||
    -      environment.pendingCreation ||
    -      approvalEnabled,
    -    versions: {
    -      create: {
    -        value: dto.value,
    +const [variable, approval] = await this.prisma.$transaction([
    +  this.prisma.variable.create({
    +    data: {
    +      name: dto.name,
    +      note: dto.note,
    +      pendingCreation:
    +        project.pendingCreation ||
    +        environment.pendingCreation ||
    +        approvalEnabled,
    +      versions: {
    +        create: {
    +          value: dto.value,
    +        }
    +      }
    +    }
    +  }),
    +  createApproval({...})
    +])
     
    Use a centralized error handling approach.

    Instead of directly throwing exceptions within the updateEnvironment and rollback methods,
    consider using a more centralized error handling approach to ensure consistency and ease
    of maintenance.

    apps/api/src/variable/service/variable.service.ts [239-240]

    -throw new BadRequestException(
    -  `Can not update the environment of the variable to the same environment: ${environmentId}`
    -)
    +this.handleError('BadRequest', `Can not update the environment of the variable to the same environment: ${environmentId}`)
     
    Maintainability
    Abstract event object creation into a helper function for maintainability.

    For better test maintainability, consider abstracting the event object creation into a
    helper function. This will reduce duplication and make the tests easier to read and
    update.

    apps/api/src/event/event.e2e.spec.ts [150-159]

    -const event = {
    +const createExpectedEvent = (overrides = {}) => ({
       id: expect.any(String),
       title: expect.any(String),
       ...
    -}
    +  ...overrides,
    +});
     
    Simplify the conditional logic for setting pendingCreation.

    Refactor the conditionals that check for pendingCreation and approvalEnabled into a
    single, more readable condition.

    apps/api/src/secret/service/secret.service.ts [100-103]

    -pendingCreation:
    -  project.pendingCreation ||
    -  environment.pendingCreation ||
    -  approvalEnabled,
    +pendingCreation: [project.pendingCreation, environment.pendingCreation, approvalEnabled].some(Boolean),
     
    Extract pendingCreation logic into a separate method.

    Extract the logic for checking pendingCreation and approvalEnabled into a separate method
    to improve code readability and maintainability.

    apps/api/src/variable/service/variable.service.ts [92-95]

    -pendingCreation:
    -  project.pendingCreation ||
    -  environment.pendingCreation ||
    -  approvalEnabled,
    +pendingCreation: this.isPendingCreation(project, environment, approvalEnabled),
     
    Break down complex methods into smaller functions.

    For methods like createVariable, updateVariable, and others that have a significant amount
    of logic and conditions, consider breaking them down into smaller, more focused functions.
    This can greatly enhance readability and testability.

    apps/api/src/variable/service/variable.service.ts [39-43]

     async createVariable(
       user: User,
       dto: CreateVariable,
       projectId: Project['id'],
       reason?: string
     ) {
    +  // Break down into smaller functions here
    +}
     
    Refactor large switch-case blocks into separate methods for better maintainability.

    To improve code maintainability and readability, consider refactoring the large
    switch-case blocks in methods like approveApproval into separate methods. This will make
    the code easier to understand and modify in the future.

    apps/api/src/approval/service/approval.service.ts [190-386]

    -switch (approval.action) {
    -  case ApprovalAction.DELETE: {
    -    await this.deleteItem(approval, user)
    -  } else {
    -    switch (approval.itemType) {
    -      case ApprovalItemType.WORKSPACE: {
    -        switch (approval.action) {
    -          case ApprovalAction.UPDATE: {
    -            op.push(
    -              this.workspaceService.update(
    -                approval.itemId,
    -                approval.metadata as UpdateWorkspaceMetadata,
    -                user
    -              )
    -            )
    -            break
    -          }
    -        }
    -        break
    -      }
    -    }
    -  }
    -}
    +await this.handleApprovalAction(approval, user, op)
     
    Move event creation logic to a dedicated service for better modularity.

    For better code organization and separation of concerns, consider moving the createEvent
    function calls into a dedicated service. This would encapsulate the event creation logic
    separately from the approval logic, making the codebase more modular and easier to
    maintain.

    apps/api/src/approval/service/approval.service.ts [68-80]

    -createEvent(
    -  {
    -    triggeredBy: user,
    -    entity: approval,
    -    type: EventType.APPROVAL_UPDATED,
    -    source: EventSource.APPROVAL,
    -    title: `Approval with id ${approvalId} updated`,
    -    metadata: {
    -      approvalId
    -    }
    -  },
    -  this.prisma
    -)
    +this.eventService.createApprovalEvent(user, approval, EventType.APPROVAL_UPDATED, `Approval with id ${approvalId} updated`)
     
    Enhancement
    Add error handling for the createApproval function.

    Consider adding error handling for the createApproval function to manage potential
    failures gracefully.

    apps/api/src/secret/service/secret.service.ts [155-165]

    -const approval = await createApproval(
    -    {
    -      action: ApprovalAction.CREATE,
    -      itemType: ApprovalItemType.SECRET,
    -      itemId: secret.id,
    -      reason,
    -      user,
    -      workspaceId: project.workspaceId
    -    },
    -    this.prisma
    -  )
    +try {
    +  const approval = await createApproval(
    +      {
    +        action: ApprovalAction.CREATE,
    +        itemType: ApprovalItemType.SECRET,
    +        itemId: secret.id,
    +        reason,
    +        user,
    +        workspaceId: project.workspaceId
    +      },
    +      this.prisma
    +    )
    +} catch (error) {
    +  // Handle error appropriately
    +}
     
    Check the result of workspaceApprovalEnabled before proceeding with operations.

    Consider checking the result of workspaceApprovalEnabled before proceeding with variable
    creation or updates. This can help in avoiding unnecessary operations if the workspace
    approval is not enabled.

    apps/api/src/variable/service/variable.service.ts [82-84]

     const approvalEnabled = await workspaceApprovalEnabled(
       project.workspaceId,
       this.prisma
     )
    +if (!approvalEnabled) {
    +  // Handle the case when approval is not enabled
    +}
     
    Wrap database operations in a transaction to ensure data integrity.

    Consider using a transaction for operations that should be executed as a unit to ensure
    data integrity. For example, in approveApproval, where multiple database operations are
    performed based on the approval action, wrapping these operations in a transaction would
    ensure that either all operations succeed or none, maintaining the database's consistent
    state.

    apps/api/src/approval/service/approval.service.ts [170-390]

    -op.push(
    +const transaction = await this.prisma.$transaction([
       this.prisma.approval.update({
         where: {
           id: approvalId
         },
         data: {
           status: ApprovalStatus.APPROVED,
           approvedAt: new Date(),
           approvedBy: {
             connect: {
               id: user.id
             }
           }
         }
    -  })
    -)
    +  }),
    +  ...op
    +])
     
    Use more specific exceptions for clearer error messaging.

    Use a more specific exception instead of BadRequestException for missing environments in
    approveApproval to provide clearer error messages to the client. For example,
    NotFoundException could be more appropriate when an environment does not exist.

    apps/api/src/approval/service/approval.service.ts [293-295]

    -throw new BadRequestException(
    +throw new NotFoundException(
       `Environment with id ${metadata.environmentId} does not exist`
     )
     
    Lock approval rows at the start of operations to prevent race conditions.

    To avoid potential race conditions and ensure that the approval status is always
    accurately checked, consider locking the approval row at the beginning of operations like
    updateApproval, deleteApproval, rejectApproval, and approveApproval. This can be achieved
    using Prisma's transaction API with a select statement that includes a forUpdate hint.

    apps/api/src/approval/service/approval.service.ts [50-52]

    -let approval = await this.checkApprovalAuthority(user, approvalId)
    +let approval = await this.prisma.$transaction(async (prisma) => {
    +  return prisma.approval.findUnique({
    +    where: { id: approvalId },
    +    select: { id: true }, // Select minimal fields required
    +    forUpdate: true
    +  })
    +})
     
    Performance
    Optimize the database query for checking existing secrets.

    Optimize the check for existing secrets to avoid potential performance issues with large
    datasets.

    apps/api/src/secret/service/secret.service.ts [514-520]

     const secretExists = await this.prisma.secret.count({
         where: {
    -      name: secret.name,
    -      environmentId: secret.environmentId,
    -      pendingCreation: false,
    -      projectId: secret.projectId
    +      AND: [
    +        { name: secret.name },
    +        { environmentId: secret.environmentId },
    +        { pendingCreation: false },
    +        { projectId: secret.projectId }
    +      ]
         }
       })
     

    ✨ Improve tool usage guide:

    Overview:
    The improve tool scans the PR code changes, and automatically generates suggestions for improving the PR code. The tool can be triggered automatically every time a new PR is opened, or can be invoked manually by commenting on a PR.
    When commenting, to edit configurations related to the improve tool (pr_code_suggestions section), use the following template:

    /improve --pr_code_suggestions.some_config1=... --pr_code_suggestions.some_config2=...
    

    With a configuration file, use the following template:

    [pr_code_suggestions]
    some_config1=...
    some_config2=...
    
    Enabling\disabling automation

    When you first install the app, the default mode for the improve tool is:

    pr_commands = ["/improve --pr_code_suggestions.summarize=true", ...]
    

    meaning the improve tool will run automatically on every PR, with summarization enabled. Delete this line to disable the tool from running automatically.

    Utilizing extra instructions

    Extra instructions are very important for the improve tool, since they enable to guide the model to suggestions that are more relevant to the specific needs of the project.

    Be specific, clear, and concise in the instructions. With extra instructions, you are the prompter. Specify relevant aspects that you want the model to focus on.

    Examples for extra instructions:

    [pr_code_suggestions] # /improve #
    extra_instructions="""
    Emphasize the following aspects:
    - Does the code logic cover relevant edge cases?
    - Is the code logic clear and easy to understand?
    - Is the code logic efficient?
    ...
    """
    

    Use triple quotes to write multi-line instructions. Use bullet points to make the instructions more readable.

    A note on code suggestions quality
    • While the current AI for code is getting better and better (GPT-4), it's not flawless. Not all the suggestions will be perfect, and a user should not accept all of them automatically.
    • Suggestions are not meant to be simplistic. Instead, they aim to give deep feedback and raise questions, ideas and thoughts to the user, who can then use his judgment, experience, and understanding of the code base.
    • Recommended to use the 'extra_instructions' field to guide the model to suggestions that are more relevant to the specific needs of the project, or use the custom suggestions 💎 tool
    • With large PRs, best quality will be obtained by using 'improve --extended' mode.
    More PR-Agent commands

    To invoke the PR-Agent, add a comment using one of the following commands:

    • /review: Request a review of your Pull Request.
    • /describe: Update the PR title and description based on the contents of the PR.
    • /improve [--extended]: Suggest code improvements. Extended mode provides a higher quality feedback.
    • /ask <QUESTION>: Ask a question about the PR.
    • /update_changelog: Update the changelog based on the PR's contents.
    • /add_docs 💎: Generate docstring for new components introduced in the PR.
    • /generate_labels 💎: Generate labels for the PR based on the PR's contents.
    • /analyze 💎: Automatically analyzes the PR, and presents changes walkthrough for each component.

    See the tools guide for more details.
    To list the possible configuration parameters, add a /config comment.

    See the improve usage page for a more comprehensive guide on using this tool.

    @rajdip-b rajdip-b marked this pull request as ready for review March 7, 2024 06:27
    @rajdip-b rajdip-b changed the base branch from develop to approval-and-event March 7, 2024 06:28
    Copy link
    Contributor

    PR Description updated to latest commit (ff8cb98)

    Copy link
    Contributor

    Persistent review updated to latest commit ff8cb98

    Copy link
    Contributor

    codiumai-pr-agent-free bot commented Mar 7, 2024

    PR Code Suggestions

    CategorySuggestions                                                                                                                                                       
    Maintainability
    Remove or add a TODO for commented-out test cases.

    Consider removing the commented-out test cases if they are no longer needed. If they are
    temporarily disabled, add a TODO comment with a reason and a target date for re-enabling
    or removing them.

    apps/api/src/event/event.e2e.spec.ts [114-395]

    +// TODO: Re-enable or remove this test by [target_date] because [reason]
     // it('should be able to fetch a user event', async () => {
     ...
     // })
     
    Implement or remove commented-out event creation tests.

    The commented-out tests for event creation (e.g., WORKSPACE_CREATED, WORKSPACE_UPDATED)
    suggest that these tests are either temporarily disabled or under development. If these
    tests are important for validating event creation, consider implementing them fully or, if
    they are no longer needed, removing the commented-out code to keep the test suite clean
    and maintainable.

    apps/api/src/workspace/workspace.e2e.spec.ts [192-213]

    -// it('should have created a WORKSPACE_CREATED event', async () => {
    -...
    -// })
    +it('should have created a WORKSPACE_CREATED event', async () => {
    +  ...
    +})
     
    Refactor approval record creation into a separate method.

    To improve code maintainability, consider moving the logic for creating approval records
    into a separate method. This will make the createSecret, updateSecret,
    updateSecretEnvironment, rollbackSecret, and deleteSecret methods more readable and
    maintainable.

    apps/api/src/secret/service/secret.service.ts [156-166]

    -const approval = await createApproval(
    -    {
    -        action: ApprovalAction.CREATE,
    -        itemType: ApprovalItemType.SECRET,
    -        itemId: secret.id,
    -        reason,
    -        user,
    -        workspaceId: project.workspaceId
    -    },
    -    this.prisma
    -)
    +const approval = await this.createApprovalRecord(user, secret.id, ApprovalAction.CREATE, reason);
     
    Use more descriptive variable names for data transfer objects.

    To enhance code readability and maintainability, consider using a more descriptive
    variable name than dto for the data transfer object parameters in methods.

    apps/api/src/secret/service/secret.service.ts [49]

    -dto: CreateSecret,
    +secretData: CreateSecret,
     
    Extract approval check and creation logic into a separate method.

    To improve code maintainability, consider extracting the logic for checking workspace
    approval and creating approvals into a separate method. This will reduce code duplication
    across createVariable, updateVariable, rollbackVariable, and deleteVariable methods.

    apps/api/src/variable/service/variable.service.ts [83-96]

    -const approvalEnabled = await workspaceApprovalEnabled(
    -  project.workspaceId,
    -  this.prisma
    -)
    +private async checkAndCreateApproval(variableId: Variable['id'], action: ApprovalAction, reason: string, user: User, workspaceId: Workspace['id'], metadata?: any) {
    +  const approvalEnabled = await workspaceApprovalEnabled(workspaceId, this.prisma);
    +  if (approvalEnabled) {
    +    return await createApproval({
    +      action,
    +      itemType: ApprovalItemType.VARIABLE,
    +      itemId: variableId,
    +      reason,
    +      user,
    +      workspaceId,
    +      metadata
    +    }, this.prisma);
    +  }
    +}
     
    Refactor error handling for invalid rollback versions into a reusable function.

    Instead of using throw new NotFoundException directly in the rollbackVariable method for
    invalid rollback versions, consider creating a more specific error handling function or
    class that can be reused across different methods for consistency and maintainability.

    apps/api/src/variable/service/variable.service.ts [310-311]

    -throw new NotFoundException(
    -  `Invalid rollback version: ${rollbackVersion} for variable: ${variableId}`
    -)
    +private handleInvalidRollbackVersion(rollbackVersion: number, variableId: Variable['id']) {
    +  throw new NotFoundException(`Invalid rollback version: ${rollbackVersion} for variable: ${variableId}`);
    +}
     
    Best practice
    Add explicit type annotations for workspace variables.

    Consider adding explicit type annotations for workspace1 and workspace2 to improve code
    readability and maintainability. TypeScript can infer types, but explicit types for object
    structures returned from external functions can make the code more robust and easier to
    understand for new contributors.

    apps/api/src/workspace/workspace.e2e.spec.ts [139-189]

    -workspace1 = response.json()
    -workspace2 = response.json()
    +const workspace1: WorkspaceType = response.json()
    +const workspace2: WorkspaceType = response.json()
     
    Use optional chaining for safer property access.

    Use TypeScript's optional chaining (?.) when accessing deeply nested properties to prevent
    runtime errors due to potential undefined values.

    apps/api/src/variable/service/variable.service.ts [306]

    -const maxVersion = variable.versions[variable.versions.length - 1].version
    +const maxVersion = variable.versions?.[variable.versions.length - 1]?.version
     
    Enhancement
    Add assertions to verify the effect of user role updates.

    For the API endpoint tests that involve user roles and permissions, such as updating
    workspace roles or removing users from a workspace, consider adding assertions to verify
    that the operation has the expected effect. For example, after updating a user's role,
    fetch the user's role again and assert that it has been updated correctly. This ensures
    that the tests fully validate the functionality they are intended to cover.

    apps/api/src/workspace/workspace.e2e.spec.ts [733-734]

     it('should be able to update the role of a member', async () => {
       await createMembership(adminRole.id, user2.id, workspace1.id, prisma)
    +  // Fetch the updated role and assert it has been changed as expected
     })
     
    Add assertions for error handling in non-existing member update test.

    The test case it('should not be able to update the role of a non existing member', async
    () => { ... }) should include assertions to check the response status code and message to
    ensure it correctly handles the error scenario. This will make the test more robust by
    explicitly verifying that the API behaves as expected when trying to update a non-existent
    member.

    apps/api/src/workspace/workspace.e2e.spec.ts [858-859]

     it('should not be able to update the role of a non existing member', async () => {
       const response = await app.inject({
    -})
    +  })
    +  expect(response.statusCode).toBe(404) // Assuming 404 is the expected status code
    +  expect(response.body).toContain('Member not found') // Assuming this is part of the expected response
     
    Implement transactional operations for methods involving multiple database changes.

    To ensure the integrity of the secret creation process, consider implementing
    transactional operations where multiple database changes are involved, especially in
    methods like createSecret, updateSecret, deleteSecret, etc.

    apps/api/src/secret/service/secret.service.ts [96-107]

    -const secret = await this.prisma.secret.create({
    -    data: {
    -        name: dto.name,
    -        note: dto.note,
    -        rotateAt: addHoursToDate(dto.rotateAfter),
    -        pendingCreation:
    -            project.pendingCreation ||
    -            environment.pendingCreation ||
    -            approvalEnabled,
    -        versions: {
    -            create: {
    -                value: await encrypt(project.publicKey, dto.value),
    +await this.prisma.$transaction(async (prisma) => {
    +    const secret = await prisma.secret.create({
    +        data: {
    +            name: dto.name,
    +            note: dto.note,
    +            rotateAt: addHoursToDate(dto.rotateAfter),
    +            pendingCreation:
    +                project.pendingCreation ||
    +                environment.pendingCreation ||
    +                approvalEnabled,
    +            versions: {
    +                create: {
    +                    value: await encrypt(project.publicKey, dto.value),
    +                }
                 }
             }
    -    }
    -})
    +    });
    +    // Additional operations within the transaction
    +});
     
    Validate the 'reason' parameter to ensure it is not empty.

    To ensure data integrity and prevent potential issues, validate the reason parameter in
    methods like createVariable, updateVariable, rollbackVariable, and deleteVariable to
    ensure it is not empty when approvals are required.

    apps/api/src/variable/service/variable.service.ts [164]

    -reason,
    +reason: reason.trim().length > 0 ? reason : 'No reason provided',
     
    Security
    Include tests for access control to ensure security.

    When testing endpoints that require authentication or specific user roles, it's important
    to include tests that verify access control. For example, ensure that users without the
    appropriate permissions cannot perform actions that are restricted to admin roles. This
    can help catch security issues where endpoints are unintentionally exposed to unauthorized
    users.

    apps/api/src/workspace/workspace.e2e.spec.ts [1025]

    -const response = await app.inject({
    -  method: 'POST',
    -  url: '/workspace'
    +// Example test case for unauthorized access
    +it('should not allow unauthorized users to access restricted endpoints', async () => {
    +  const response = await app.inject({
    +    method: 'POST',
    +    url: '/workspace',
    +    headers: { 'Authorization': 'Bearer invalid-token' }
    +  })
    +  expect(response.statusCode).toBe(403) // Assuming 403 Forbidden is the expected response
     })
     
    Validate the 'reason' parameter to ensure it's provided when necessary.

    For better security and error handling, consider validating the reason parameter in
    methods that require it, ensuring it's not empty when necessary.

    apps/api/src/secret/service/secret.service.ts [51]

    -reason?: string
    +if (!reason) {
    +    throw new BadRequestException('Reason is required for this operation.');
    +}
     
    Possible issue
    Add a null check for the secret object after fetching it.

    Consider checking if secret is null after fetching it with prisma.secret.findUnique to
    avoid potential null reference errors.

    apps/api/src/secret/service/secret.service.ts [510-513]

     const secret = await this.prisma.secret.findUnique({
         where: {
             id: secretId
         }
     })
    +if (!secret) {
    +    throw new NotFoundException(`Secret not found with ID ${secretId}`);
    +}
     
    Add a check for variable existence before accessing its properties.

    Consider checking for the existence of variable before attempting to access its properties
    in the makeVariableApproved method. This will prevent potential runtime errors if the
    variable does not exist.

    apps/api/src/variable/service/variable.service.ts [456-465]

    +if (!variable) {
    +  throw new NotFoundException(`Variable with ID ${variableId} not found`);
    +}
     const variableExists = await this.prisma.variable.count({
       where: {
         name: variable.name,
         pendingCreation: false,
         environmentId: variable.environmentId,
         projectId: variable.projectId
       }
     })
     

    ✨ Improve tool usage guide:

    Overview:
    The improve tool scans the PR code changes, and automatically generates suggestions for improving the PR code. The tool can be triggered automatically every time a new PR is opened, or can be invoked manually by commenting on a PR.
    When commenting, to edit configurations related to the improve tool (pr_code_suggestions section), use the following template:

    /improve --pr_code_suggestions.some_config1=... --pr_code_suggestions.some_config2=...
    

    With a configuration file, use the following template:

    [pr_code_suggestions]
    some_config1=...
    some_config2=...
    
    Enabling\disabling automation

    When you first install the app, the default mode for the improve tool is:

    pr_commands = ["/improve --pr_code_suggestions.summarize=true", ...]
    

    meaning the improve tool will run automatically on every PR, with summarization enabled. Delete this line to disable the tool from running automatically.

    Utilizing extra instructions

    Extra instructions are very important for the improve tool, since they enable to guide the model to suggestions that are more relevant to the specific needs of the project.

    Be specific, clear, and concise in the instructions. With extra instructions, you are the prompter. Specify relevant aspects that you want the model to focus on.

    Examples for extra instructions:

    [pr_code_suggestions] # /improve #
    extra_instructions="""
    Emphasize the following aspects:
    - Does the code logic cover relevant edge cases?
    - Is the code logic clear and easy to understand?
    - Is the code logic efficient?
    ...
    """
    

    Use triple quotes to write multi-line instructions. Use bullet points to make the instructions more readable.

    A note on code suggestions quality
    • While the current AI for code is getting better and better (GPT-4), it's not flawless. Not all the suggestions will be perfect, and a user should not accept all of them automatically.
    • Suggestions are not meant to be simplistic. Instead, they aim to give deep feedback and raise questions, ideas and thoughts to the user, who can then use his judgment, experience, and understanding of the code base.
    • Recommended to use the 'extra_instructions' field to guide the model to suggestions that are more relevant to the specific needs of the project, or use the custom suggestions 💎 tool
    • With large PRs, best quality will be obtained by using 'improve --extended' mode.
    More PR-Agent commands

    To invoke the PR-Agent, add a comment using one of the following commands:

    • /review: Request a review of your Pull Request.
    • /describe: Update the PR title and description based on the contents of the PR.
    • /improve [--extended]: Suggest code improvements. Extended mode provides a higher quality feedback.
    • /ask <QUESTION>: Ask a question about the PR.
    • /update_changelog: Update the changelog based on the PR's contents.
    • /add_docs 💎: Generate docstring for new components introduced in the PR.
    • /generate_labels 💎: Generate labels for the PR based on the PR's contents.
    • /analyze 💎: Automatically analyzes the PR, and presents changes walkthrough for each component.

    See the tools guide for more details.
    To list the possible configuration parameters, add a /config comment.

    See the improve usage page for a more comprehensive guide on using this tool.

    Copy link

    codecov bot commented Mar 7, 2024

    Codecov Report

    Attention: Patch coverage is 97.00787% with 19 lines in your changes are missing coverage. Please review.

    ❗ No coverage uploaded for pull request base (approval-and-event@6134bb2). Click here to learn what that means.

    Files Patch % Lines
    ...rc/config/oauth-strategy/google/google.strategy.ts 50.00% 4 Missing ⚠️
    ...s/api/src/common/get-environment-with-authority.ts 57.14% 3 Missing ⚠️
    apps/api/src/common/get-project-with-authority.ts 57.14% 3 Missing ⚠️
    apps/api/src/common/get-secret-with-authority.ts 57.14% 3 Missing ⚠️
    apps/api/src/common/get-variable-with-authority.ts 57.14% 3 Missing ⚠️
    apps/api/src/secret/service/secret.service.ts 97.53% 2 Missing ⚠️
    ...c/config/factory/google/google-strategy.factory.ts 93.75% 1 Missing ⚠️
    Additional details and impacted files
    @@                  Coverage Diff                  @@
    ##             approval-and-event     #158   +/-   ##
    =====================================================
      Coverage                      ?   93.09%           
    =====================================================
      Files                         ?       89           
      Lines                         ?     2055           
      Branches                      ?      418           
    =====================================================
      Hits                          ?     1913           
      Misses                        ?      142           
      Partials                      ?        0           
    Flag Coverage Δ
    api-e2e-tests 93.09% <97.00%> (?)

    Flags with carried forward coverage won't be shown. Click here to find out more.

    ☔ View full report in Codecov by Sentry.
    📢 Have feedback on the report? Share it here.

    Copy link

    sonarcloud bot commented Mar 7, 2024

    Quality Gate Failed Quality Gate failed

    Failed conditions
    39 New Code Smells (required ≤ 5)

    See analysis details on SonarCloud

    Catch issues before they fail your Quality Gate with our IDE extension SonarLint

    @rajdip-b
    Copy link
    Member Author

    rajdip-b commented Mar 7, 2024

    /review

    Copy link
    Contributor

    Persistent review updated to latest commit 7f7a29d

    @rajdip-b rajdip-b merged commit 4abf251 into approval-and-event Mar 7, 2024
    5 of 7 checks passed
    @rajdip-b rajdip-b deleted the feat/approval branch March 7, 2024 09:30
    rajdip-b added a commit that referenced this pull request Mar 9, 2024
    @rajdip-b rajdip-b mentioned this pull request Apr 10, 2024
    6 tasks
    rajdip-b pushed a commit that referenced this pull request May 12, 2024
    ## [1.3.0](v1.2.0...v1.3.0) (2024-05-12)
    
    ### 🚀 Features
    
    * Add approval support ([#158](#158)) ([e09ae60](e09ae60))
    * **api:** Add configuration live update support ([#181](#181)) ([f7d6684](f7d6684))
    * **api:** Add feature to export data of a workspace ([#152](#152)) ([46833aa](46833aa))
    * **api:** Add Integration support ([#203](#203)) ([f1ae87e](f1ae87e))
    * **api:** Add note to [secure] and variable ([#151](#151)) ([2e62351](2e62351))
    * **api:** Add OAuth redirection and polished authentication ([#212](#212)) ([d2968bc](d2968bc))
    * **api:** Add support for storing and managing variables ([#149](#149)) ([963a8ae](963a8ae))
    * **api:** Added GitLab OAuth ([#188](#188)) ([4d3bbe4](4d3bbe4))
    * **api:** Added validation for reason field ([#190](#190)) ([90b8ff2](90b8ff2))
    * **api:** Create default workspace on user's creation ([#182](#182)) ([3dc0c4c](3dc0c4c))
    * **api:** Reading `port` Dynamically ([#170](#170)) ([fd46e3e](fd46e3e))
    * **auth:** Add Google OAuth ([#156](#156)) ([cf387ea](cf387ea))
    * **web:** Added waitlist ([#168](#168)) ([1084c77](1084c77))
    * **web:** Landing revamp ([#165](#165)) ([0bc723b](0bc723b))
    
    ### 🐛 Bug Fixes
    
    * **web:** alignment issue in “Collaboration made easy” section ([#178](#178)) ([df5ca75](df5ca75))
    * **workspace:** delete duplicate tailwind config ([99d922a](99d922a))
    
    ### 📚 Documentation
    
    * add contributor list ([f37569a](f37569a))
    * Add integration docs ([#204](#204)) ([406ddb7](406ddb7))
    * Added integration docs to gitbook summary ([ab37530](ab37530))
    * **api:** Add swagger docs of API key controller ([#167](#167)) ([2910476](2910476))
    * **api:** Add swagger docs of User Controller ([#166](#166)) ([fd59522](fd59522))
    * fix typo in environment-variables.md ([#163](#163)) ([48294c9](48294c9))
    * Remove supabase from docs ([#169](#169)) ([eddbce8](eddbce8))
    * **setup:** replace NX with Turbo in setup instructions ([#175](#175)) ([af8a460](af8a460))
    * Update README.md ([b59f16b](b59f16b))
    * Update running-the-api.md ([177dbbf](177dbbf))
    * Update running-the-api.md ([#193](#193)) ([3d5bcac](3d5bcac))
    
    ### 🔧 Miscellaneous Chores
    
    * Added lockfile ([60a3b9b](60a3b9b))
    * Added lockfile ([6bb512c](6bb512c))
    * **api:** Added type inference and runtime validation to `process.env` ([#200](#200)) ([249e07d](249e07d))
    * **api:** Fixed prisma script env errors ([#209](#209)) ([8762354](8762354))
    * **API:** Refactor authority check functions in API ([#189](#189)) ([e9d710d](e9d710d))
    * **api:** Refactor user e2e tests ([b38d45a](b38d45a))
    * **ci:** Disabled api stage release ([97877c4](97877c4))
    * **ci:** Update stage deployment config ([868a6a1](868a6a1))
    * **codecov:** update api-e2e project coverage ([1e90d7e](1e90d7e))
    * **dockerfile:** Fixed web dockerfile ([6134bb2](6134bb2))
    * **docker:** Optimized web Dockerfile to reduct image size ([#173](#173)) ([444286a](444286a))
    * **release:** Downgraded package version ([c173fee](c173fee))
    * **release:** Fix failing release ([#213](#213)) ([40f64f3](40f64f3))
    * **release:** Install pnpm ([1081bea](1081bea))
    * **release:** Updated release commit ([b8958e7](b8958e7))
    * **release:** Updated release commit ([e270eb8](e270eb8))
    * Update deprecated husky Install command ([#202](#202)) ([e61102c](e61102c))
    * Upgrade @million/lint from 0.0.66 to 0.0.73 ([#172](#172)) ([dd43ed9](dd43ed9))
    * **web:** Updated fly memory config ([4debc66](4debc66))
    
    ### 🔨 Code Refactoring
    
    * **api:** Made events central to workspace ([#159](#159)) ([9bc00ae](9bc00ae))
    * **api:** Migrated to cookie based authentication ([#206](#206)) ([ad6911f](ad6911f))
    * **monorepo:** Migrate from nx to turbo ([#153](#153)) ([88b4b00](88b4b00))
    @rajdip-b
    Copy link
    Member Author

    🎉 This PR is included in version 1.3.0 🎉

    The release is available on GitHub release

    Your semantic-release bot 📦🚀

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    type: enhancement New feature or request
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    3 participants