Skip to content

Allow adding groups to CI_JOB_TOKEN allowlist graphQL mutation

Original issue: #435903 (closed)

POC MR: !143106 (closed)

What does this MR do and why?

The current configuration for CI_JOB_TOKEN permissions relies on the project allow list, where permitted projects can be specified. The primary objective of the original issue is to expand this functionality by enabling permissions for CI_JOB_TOKEN on specific projects through group associations.

API/GraphQL

  1. Introduce a mutation Mutations::Ci::JobTokenScope::AddGroupOrProject (similar to Mutations::Ci::JobTokenScope::AddGroupOrProject)
  2. Introduce a mutation Mutations::Ci::JobTokenScope::RemoveGroup (similar to Mutations::Ci::JobTokenScope::RemoveProject)
  3. Extend Types::Ci::JobTokenScopeType with GroupsAllowlist field which returns list of groups in the allowlist.

To facilitate a smoother review process, the implementation has been divided into four iterations:

  1. Database design of group list table and model - job_token/group_scope_link - !142749 (merged)
  2. Add into app/models/ci/job_token/group_scope_link.rb and app/models/ci/job_token/allowlist.rb groups validation together with inbound lists, Feature flag group_scope_link_allowlist - !142441 (merged)
  3. GraphQL implementation 👈 you are here
  4. REST API implementation

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

How to set up and validate locally

  1. Navigate to the grapqhl explorer

    http://localhost:3000/-/graphql-explorer. # can be different based on gdk config
  2. Copy and paste and run the following queries to the grqphql explorer to test

Fetching the lists of groups

# Fetching the lists of groups
query fetchGroupAllowlists {
  project(fullPath: "flight/flightjsFlight") {
    id
    ciJobTokenScope {
      groupsAllowlist {
        edges {
          node {
            id
          }
        }
      }
    }
  }
}

Response:

{
  "data": {
    "project": {
      "id": "gid://gitlab/Project/38",
      "ciJobTokenScope": {
        "groupsAllowlist": {
          "edges": [
            {
              "node": {
                "id": "gid://gitlab/Group/87"
              }
            },
            {
              "node": {
                "id": "gid://gitlab/Group/25"
              }
            }
          ]
        }
      }
    }
  }
}

Add a project to allow list

mutation addGroupOrProject {
  ciJobTokenScopeAddGroupOrProject(
    input: {
      projectPath: "flight/flightjsFlight",
      targetPath: "mygroup/myproj1"
    }
  ) {
    errors,
    clientMutationId,
    ciJobTokenScope {
      groupsAllowlist {
        edges {
          node {
            id
          }
        }
      }
      inboundAllowlist {
        edges {
          node {
            id
          }
        }
      }
    }
  }
}

Response:

{
  "data": {
    "ciJobTokenScopeAddGroupOrProject": {
      "errors": [],
      "clientMutationId": null,
      "ciJobTokenScope": {
        "groupsAllowlist": {
          "edges": [
            {
              "node": {
                "id": "gid://gitlab/Group/123"
              }
            },
            {
              "node": {
                "id": "gid://gitlab/Group/116"
              }
            }
          ]
        },
        "inboundAllowlist": {
          "edges": [
            {
              "node": {
                "id": "gid://gitlab/Project/49"
              }
            },
            {
              "node": {
                "id": "gid://gitlab/Project/39"
              }
            }
          ]
        }
      }
    }
  }
}

Add a group to allow list

mutation addGroupOrProject {
  ciJobTokenScopeAddGroupOrProject(
    input: {
      projectPath: "flight/flightjsFlight",
      targetPath: "dmitry_subgroup1"
    }
  ) {
    errors,
    clientMutationId,
    ciJobTokenScope {
      groupsAllowlist {
        edges {
          node {
            id
          }
        }
      }
      inboundAllowlist {
        edges {
          node {
            id
          }
        }
      }
    }
  }
}

Response:

{
  "data": {
    "ciJobTokenScopeAddGroupOrProject": {
      "errors": [],
      "clientMutationId": null,
      "ciJobTokenScope": {
        "groupsAllowlist": {
          "edges": [
            {
              "node": {
                "id": "gid://gitlab/Group/123"
              }
            },
            {
              "node": {
                "id": "gid://gitlab/Group/121"
              }
            },
            {
              "node": {
                "id": "gid://gitlab/Group/116"
              }
            }
          ]
        },
        "inboundAllowlist": {
          "edges": [
            {
              "node": {
                "id": "gid://gitlab/Project/49"
              }
            },
            {
              "node": {
                "id": "gid://gitlab/Project/39"
              }
            }
          ]
        }
      }
    }
  }
}

Remove a group from allow list

mutation removeGroup {
  ciJobTokenScopeRemoveGroup(
    input: {
      projectPath: "flight/flightjsFlight",
      targetGroupPath: "newgroup"
    }
  ) {
    errors,
    clientMutationId,
    ciJobTokenScope {
      groupsAllowlist {
        edges {
          node {
            id
          }
        }
      }
    }
  }
}

Response:

{
  "data": {
    "ciJobTokenScopeRemoveGroup": {
      "errors": [],
      "clientMutationId": null,
      "ciJobTokenScope": {
        "groupsAllowlist": {
          "edges": [
            {
              "node": {
                "id": "gid://gitlab/Group/27"
              }
            }
          ]
        }
      }
    }
  }
}
Edited by Dmytro Biryukov

Merge request reports