prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Support /projects/:id/job_token_scope/allowlist
  I would like to access the job token allow list through the Gitlab API. 
  
  Docs: 
  - [Get a project’s CI/CD job token inbound allowlist](https://docs.gitlab.com/ee/api/project_job_token_scopes.html#get-a-projects-cicd-job-token-inbound-allowlist)
  - [Allow access to your project with a job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#allow-access-to-your-project-with-a-job-token)
  
  API endpoint: 
  ```
  GET/POST/DELETE /projects/:id/job_token_scope/allowlist
  ```
  
  I currently have the following manager to access the job token scope allow list:
  
  ```
  class ProjectJobTokenScopeAllowlistManager(
      gitlab.mixins.ListMixin,
      gitlab.mixins.CreateMixin,
      gitlab.mixins.DeleteMixin,
      gitlab.base.RESTManager,
  ):
      _path = "/projects/{project_id}/job_token_scope/allowlist"
      _obj_cls = gitlab.v4.objects.Project
      _from_parent_attrs = {"project_id": "id"}
      _create_attrs = gitlab.types.RequiredOptional(required=("target_project_id",))
  ```
  
  </issue>
  <code>
  [start of gitlab/v4/objects/job_token_scope.py]
  1 from typing import Any, cast
  2 
  3 from gitlab.base import RESTManager, RESTObject
  4 from gitlab.mixins import (
  5     GetWithoutIdMixin,
  6     RefreshMixin,
  7     SaveMixin,
  8     UpdateMethod,
  9     UpdateMixin,
  10 )
  11 
  12 __all__ = [
  13     "ProjectJobTokenScope",
  14     "ProjectJobTokenScopeManager",
  15 ]
  16 
  17 
  18 class ProjectJobTokenScope(RefreshMixin, SaveMixin, RESTObject):
  19     _id_attr = None
  20 
  21 
  22 class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
  23     _path = "/projects/{project_id}/job_token_scope"
  24     _obj_cls = ProjectJobTokenScope
  25     _from_parent_attrs = {"project_id": "id"}
  26     _update_method = UpdateMethod.PATCH
  27 
  28     def get(self, **kwargs: Any) -> ProjectJobTokenScope:
  29         return cast(ProjectJobTokenScope, super().get(**kwargs))
  30
  [end of gitlab/v4/objects/job_token_scope.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/gitlab/v4/objects/job_token_scope.py b/gitlab/v4/objects/job_token_scope.py
  --- a/gitlab/v4/objects/job_token_scope.py
  +++ b/gitlab/v4/objects/job_token_scope.py
  @@ -2,12 +2,17 @@
   
   from gitlab.base import RESTManager, RESTObject
   from gitlab.mixins import (
  +    CreateMixin,
  +    DeleteMixin,
       GetWithoutIdMixin,
  +    ListMixin,
  +    ObjectDeleteMixin,
       RefreshMixin,
       SaveMixin,
       UpdateMethod,
       UpdateMixin,
   )
  +from gitlab.types import RequiredOptional
   
   __all__ = [
       "ProjectJobTokenScope",
  @@ -18,6 +23,9 @@
   class ProjectJobTokenScope(RefreshMixin, SaveMixin, RESTObject):
       _id_attr = None
   
  +    allowlist: "AllowlistProjectManager"
  +    groups_allowlist: "AllowlistGroupManager"
  +
   
   class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
       _path = "/projects/{project_id}/job_token_scope"
  @@ -27,3 +35,43 @@
   
       def get(self, **kwargs: Any) -> ProjectJobTokenScope:
           return cast(ProjectJobTokenScope, super().get(**kwargs))
  +
  +
  +class AllowlistProject(ObjectDeleteMixin, RESTObject):
  +    _id_attr = "target_project_id"  # note: only true for create endpoint
  +
  +    def get_id(self) -> int:
  +        """Returns the id of the resource. This override deals with
  +        the fact that either an `id` or a `target_project_id` attribute
  +        is returned by the server depending on the endpoint called."""
  +        target_project_id = cast(int, super().get_id())
  +        if target_project_id is not None:
  +            return target_project_id
  +        return cast(int, self.id)
  +
  +
  +class AllowlistProjectManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
  +    _path = "/projects/{project_id}/job_token_scope/allowlist"
  +    _obj_cls = AllowlistProject
  +    _from_parent_attrs = {"project_id": "project_id"}
  +    _create_attrs = RequiredOptional(required=("target_project_id",))
  +
  +
  +class AllowlistGroup(ObjectDeleteMixin, RESTObject):
  +    _id_attr = "target_group_id"  # note: only true for create endpoint
  +
  +    def get_id(self) -> int:
  +        """Returns the id of the resource. This override deals with
  +        the fact that either an `id` or a `target_group_id` attribute
  +        is returned by the server depending on the endpoint called."""
  +        target_group_id = cast(int, super().get_id())
  +        if target_group_id is not None:
  +            return target_group_id
  +        return cast(int, self.id)
  +
  +
  +class AllowlistGroupManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
  +    _path = "/projects/{project_id}/job_token_scope/groups_allowlist"
  +    _obj_cls = AllowlistGroup
  +    _from_parent_attrs = {"project_id": "project_id"}
  +    _create_attrs = RequiredOptional(required=("target_group_id",))
  
verification_info: {"golden_diff": "diff --git a/gitlab/v4/objects/job_token_scope.py b/gitlab/v4/objects/job_token_scope.py\n--- a/gitlab/v4/objects/job_token_scope.py\n+++ b/gitlab/v4/objects/job_token_scope.py\n@@ -2,12 +2,17 @@\n \n from gitlab.base import RESTManager, RESTObject\n from gitlab.mixins import (\n+    CreateMixin,\n+    DeleteMixin,\n     GetWithoutIdMixin,\n+    ListMixin,\n+    ObjectDeleteMixin,\n     RefreshMixin,\n     SaveMixin,\n     UpdateMethod,\n     UpdateMixin,\n )\n+from gitlab.types import RequiredOptional\n \n __all__ = [\n     \"ProjectJobTokenScope\",\n@@ -18,6 +23,9 @@\n class ProjectJobTokenScope(RefreshMixin, SaveMixin, RESTObject):\n     _id_attr = None\n \n+    allowlist: \"AllowlistProjectManager\"\n+    groups_allowlist: \"AllowlistGroupManager\"\n+\n \n class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):\n     _path = \"/projects/{project_id}/job_token_scope\"\n@@ -27,3 +35,43 @@\n \n     def get(self, **kwargs: Any) -> ProjectJobTokenScope:\n         return cast(ProjectJobTokenScope, super().get(**kwargs))\n+\n+\n+class AllowlistProject(ObjectDeleteMixin, RESTObject):\n+    _id_attr = \"target_project_id\"  # note: only true for create endpoint\n+\n+    def get_id(self) -> int:\n+        \"\"\"Returns the id of the resource. This override deals with\n+        the fact that either an `id` or a `target_project_id` attribute\n+        is returned by the server depending on the endpoint called.\"\"\"\n+        target_project_id = cast(int, super().get_id())\n+        if target_project_id is not None:\n+            return target_project_id\n+        return cast(int, self.id)\n+\n+\n+class AllowlistProjectManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):\n+    _path = \"/projects/{project_id}/job_token_scope/allowlist\"\n+    _obj_cls = AllowlistProject\n+    _from_parent_attrs = {\"project_id\": \"project_id\"}\n+    _create_attrs = RequiredOptional(required=(\"target_project_id\",))\n+\n+\n+class AllowlistGroup(ObjectDeleteMixin, RESTObject):\n+    _id_attr = \"target_group_id\"  # note: only true for create endpoint\n+\n+    def get_id(self) -> int:\n+        \"\"\"Returns the id of the resource. This override deals with\n+        the fact that either an `id` or a `target_group_id` attribute\n+        is returned by the server depending on the endpoint called.\"\"\"\n+        target_group_id = cast(int, super().get_id())\n+        if target_group_id is not None:\n+            return target_group_id\n+        return cast(int, self.id)\n+\n+\n+class AllowlistGroupManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):\n+    _path = \"/projects/{project_id}/job_token_scope/groups_allowlist\"\n+    _obj_cls = AllowlistGroup\n+    _from_parent_attrs = {\"project_id\": \"project_id\"}\n+    _create_attrs = RequiredOptional(required=(\"target_group_id\",))\n", "issue": "Support /projects/:id/job_token_scope/allowlist\nI would like to access the job token allow list through the Gitlab API. \r\n\r\nDocs: \r\n- [Get a project\u2019s CI/CD job token inbound allowlist](https://docs.gitlab.com/ee/api/project_job_token_scopes.html#get-a-projects-cicd-job-token-inbound-allowlist)\r\n- [Allow access to your project with a job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#allow-access-to-your-project-with-a-job-token)\r\n\r\nAPI endpoint: \r\n```\r\nGET/POST/DELETE /projects/:id/job_token_scope/allowlist\r\n```\r\n\r\nI currently have the following manager to access the job token scope allow list:\r\n\r\n```\r\nclass ProjectJobTokenScopeAllowlistManager(\r\n    gitlab.mixins.ListMixin,\r\n    gitlab.mixins.CreateMixin,\r\n    gitlab.mixins.DeleteMixin,\r\n    gitlab.base.RESTManager,\r\n):\r\n    _path = \"/projects/{project_id}/job_token_scope/allowlist\"\r\n    _obj_cls = gitlab.v4.objects.Project\r\n    _from_parent_attrs = {\"project_id\": \"id\"}\r\n    _create_attrs = gitlab.types.RequiredOptional(required=(\"target_project_id\",))\r\n```\n", "before_files": [{"content": "from typing import Any, cast\n\nfrom gitlab.base import RESTManager, RESTObject\nfrom gitlab.mixins import (\n    GetWithoutIdMixin,\n    RefreshMixin,\n    SaveMixin,\n    UpdateMethod,\n    UpdateMixin,\n)\n\n__all__ = [\n    \"ProjectJobTokenScope\",\n    \"ProjectJobTokenScopeManager\",\n]\n\n\nclass ProjectJobTokenScope(RefreshMixin, SaveMixin, RESTObject):\n    _id_attr = None\n\n\nclass ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):\n    _path = \"/projects/{project_id}/job_token_scope\"\n    _obj_cls = ProjectJobTokenScope\n    _from_parent_attrs = {\"project_id\": \"id\"}\n    _update_method = UpdateMethod.PATCH\n\n    def get(self, **kwargs: Any) -> ProjectJobTokenScope:\n        return cast(ProjectJobTokenScope, super().get(**kwargs))\n", "path": "gitlab/v4/objects/job_token_scope.py"}]}