Skip to content

[Backend] Introduce GraphQL resources for project-level exclusions

Overview

While we intend to have project-level exclusions managed via the UI, we still want to provide the ability for users to control their exclusions via GraphQL resources. This can be especially helpful in situations where customers manage the exclusions either via our terraform provider or through some other automated workflow.

Implementation Plan

Below is a list of tasks to achieve the desired outcome of this issue.

  • Introduce a new GraphQL type, eg. ProjectSecurityExclusionType and add it to ProjectType.
  • Introduce a new GraphQL resolver, eg. ProjectSecurityExclusionResolver.
  • Introduce a new GraphQL enum, e.g. ExclusionTypeEnum.
  • Introduce a new GraphQL enum, e.g. ExclusionScannerEnum.
  • Introduce a new GraphQL query to retrieve all project-level exclusions.
  • Consider introducing a new GraphQL query to retrieve one project-level exclusion.
  • Introduce a new GraphQL fragment, e.g. ProjectSecurityExclusionFragment.
  • Introduce GraphQL mutations to:
    • Add a new exclusion to a project, e.g. ProjectSecurityExclusionCreateMutation.
    • Update an existing exclusion of a project, e.g. ProjectSecurityExclusionUpdateMutation.
    • Delete an existing exclusion of a project, e.g. ProjectSecurityExclusionDeleteMutation.
  • Add appropriate documentation for all GraphQL resources.

Example Interface

Below is an example of the GraphQL API interface we seek to provide so frontend can build the UI to manage exclusions.

1. Enums and Fragment

enum ExclusionTypeEnum {
  PATH
  PATTERN
  RAW_VALUE
  RULE
}

enum ExclusionScannerEnum {
  SECRET_PUSH_PROTECTION
}

fragment ProjectSecurityExclusionFragment on ProjectSecurityExclusion {
  id: ProjectSecurityExclusionID
  scanner: ExclusionScannerEnum
  type: ExclusionTypeEnum
  value: String
  description: String
  active: Boolean
  createdAt: TimeType
  updatedAt: TimeType
}

2. Query: Project.securityExclusions

query ProjectSecurityExclusions($fullPath: ID!, $first: Int) {
  project(id: $fullPath) {
    id
    securityExclusions(first: $first) {
      nodes {
        ...ProjectSecurityExclusionFragment
      }
    }
  }
}

Considerations

  • We need to support standard pagination params: before: String, after: String, first: Int, and last: Int.
  • Consider implementing another query Project.securityExclusion which can be used to retrieve a single exclusion.
query ProjectSecurityExclusion($fullPath: ID!, $first: Int) {
  project(id: $fullPath) {
    id
    securityExclusion(id: ProjectSecurityExclusionID!) {
      ...ProjectSecurityExclusionFragment
    }
  }
}

3. Mutations

3.1 Mutation ProjectSecurityExclusionCreate

mutation projectSecurityExclusionCreate($input: ProjectSecurityExclusionCreateInput!) {
  projectSecurityExclusionCreate(input: $input) {
    securityExclusion {
      ...ProjectSecurityExclusionFragment
    }
    errors
  }
}

input ProjectSecurityExclusionCreateInput {
  projectPath: ID!
  scanner: ExclusionScannerEnum!
  type: ExclusionTypeEnum!
  value: String!
  description: String
  active: Boolean!
}
3.2 Mutation ProjectSecurityExclusionUpdate
mutation projectSecurityExclusionUpdate($input: ProjectSecurityExclusionUpdateInput!) {
  projectSecurityExclusionUpdate(input: $input) {
    securityExclusion {
      ...ProjectSecurityExclusionFragment
    }
    errors
  }
}

input ProjectSecurityExclusionUpdateInput {
  id: ProjectSecurityExclusionID!
  scanner: ExclusionScannerEnum
  type: ExclusionTypeEnum
  active: Boolean
  description: String
  value: String
}
3.3 Mutation ProjectSecurityExclusionDelete
mutation projectSecurityExclusionDelete($input: ProjectSecurityExclusionDeleteInput!) {
  projectSecurityExclusionDelete(input: $input) {
    errors
  }
}

input ProjectSecurityExclusionDeleteInput {
  id: ProjectSecurityExclusionID!
}
Edited by Ahmed Hemdan