← 返回首页
feat(job_token_scope): support Groups in job token allowlist API (#2… · python-gitlab/python-gitlab@2d1b749 · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus

Commit 2d1b749

Browse files
andauthored
feat(job_token_scope): support Groups in job token allowlist API (#2816)
* feat(job_token_scope): support job token access allowlist API Signed-off-by: Tim Knight <tim.knight1@engineering.digital.dwp.gov.uk> l.dwp.gov.uk> Co-authored-by: Nejc Habjan <nejc.habjan@siemens.com>
1 parent c5d0404 commit 2d1b749

4 files changed

Lines changed: 353 additions & 0 deletions

File tree

‎docs/gl_objects/job_token_scope.rst‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,53 @@ Refresh the current state of job token scope::
4949
scope.refresh()
5050
print(scope.inbound_enabled)
5151
# False
52+
53+
Get a project's CI/CD job token inbound allowlist::
54+
55+
allowlist = scope.allowlist.list()
56+
57+
Add a project to the project's inbound allowlist::
58+
59+
allowed_project = scope.allowlist.create({"target_project_id": 42})
60+
61+
Remove a project from the project's inbound allowlist::
62+
63+
allowed_project.delete()
64+
# or directly using a project ID
65+
scope.allowlist.delete(42)
66+
67+
.. warning::
68+
69+
Similar to above, the ID attributes you receive from the create and list
70+
APIs are not consistent (in create() the id is returned as ``source_project_id`` whereas list() returns as ``id``). To safely retrieve the ID of the allowlisted project
71+
regardless of how the object was created, always use its ``.get_id()`` method.
72+
73+
Using ``.get_id()``::
74+
75+
resp = allowlist.create({"target_project_id": 2})
76+
allowlist_id = resp.get_id()
77+
78+
allowlists = project.allowlist.list()
79+
for allowlist in allowlists:
80+
allowlist_id == allowlist.get_id()
81+
82+
Get a project's CI/CD job token inbound groups allowlist::
83+
84+
allowlist = scope.groups_allowlist.list()
85+
86+
Add a project to the project's inbound groups allowlist::
87+
88+
allowed_project = scope.groups_allowlist.create({"target_project_id": 42})
89+
90+
Remove a project from the project's inbound agroups llowlist::
91+
92+
allowed_project.delete()
93+
# or directly using a Group ID
94+
scope.groups_allowlist.delete(42)
95+
96+
.. warning::
97+
98+
Similar to above, the ID attributes you receive from the create and list
99+
APIs are not consistent. To safely retrieve the ID of the allowlisted group
100+
regardless of how the object was created, always use its ``.get_id()`` method.
101+

‎gitlab/v4/objects/job_token_scope.py‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
from gitlab.base import RESTManager, RESTObject
44
from gitlab.mixins import (
5+
CreateMixin,
6+
DeleteMixin,
57
GetWithoutIdMixin,
8+
ListMixin,
9+
ObjectDeleteMixin,
610
RefreshMixin,
711
SaveMixin,
812
UpdateMethod,
913
UpdateMixin,
1014
)
15+
from gitlab.types import RequiredOptional
1116

1217
__all__ = [
1318
"ProjectJobTokenScope",
@@ -18,6 +23,9 @@
1823
class ProjectJobTokenScope(RefreshMixin, SaveMixin, RESTObject):
1924
_id_attr = None
2025

26+
allowlist: "AllowlistProjectManager"
27+
groups_allowlist: "AllowlistGroupManager"
28+
2129

2230
class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
2331
_path = "/projects/{project_id}/job_token_scope"
@@ -27,3 +35,43 @@ class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
2735

2836
def get(self, **kwargs: Any) -> ProjectJobTokenScope:
2937
return cast(ProjectJobTokenScope, super().get(**kwargs))
38+
39+
40+
class AllowlistProject(ObjectDeleteMixin, RESTObject):
41+
_id_attr = "target_project_id" # note: only true for create endpoint
42+
43+
def get_id(self) -> int:
44+
"""Returns the id of the resource. This override deals with
45+
the fact that either an `id` or a `target_project_id` attribute
46+
is returned by the server depending on the endpoint called."""
47+
target_project_id = cast(int, super().get_id())
48+
if target_project_id is not None:
49+
return target_project_id
50+
return cast(int, self.id)
51+
52+
53+
class AllowlistProjectManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
54+
_path = "/projects/{project_id}/job_token_scope/allowlist"
55+
_obj_cls = AllowlistProject
56+
_from_parent_attrs = {"project_id": "project_id"}
57+
_create_attrs = RequiredOptional(required=("target_project_id",))
58+
59+
60+
class AllowlistGroup(ObjectDeleteMixin, RESTObject):
61+
_id_attr = "target_group_id" # note: only true for create endpoint
62+
63+
def get_id(self) -> int:
64+
"""Returns the id of the resource. This override deals with
65+
the fact that either an `id` or a `target_group_id` attribute
66+
is returned by the server depending on the endpoint called."""
67+
target_group_id = cast(int, super().get_id())
68+
if target_group_id is not None:
69+
return target_group_id
70+
return cast(int, self.id)
71+
72+
73+
class AllowlistGroupManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
74+
_path = "/projects/{project_id}/job_token_scope/groups_allowlist"
75+
_obj_cls = AllowlistGroup
76+
_from_parent_attrs = {"project_id": "project_id"}
77+
_create_attrs = RequiredOptional(required=("target_group_id",))
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#allow-any-project-to-access-your-project
2+
def test_enable_limit_access_to_this_project(gl, project):
3+
scope = project.job_token_scope.get()
4+
5+
scope.enabled = True
6+
scope.save()
7+
8+
scope.refresh()
9+
10+
assert scope.inbound_enabled
11+
12+
13+
def test_disable_limit_access_to_this_project(gl, project):
14+
scope = project.job_token_scope.get()
15+
16+
scope.enabled = False
17+
scope.save()
18+
19+
scope.refresh()
20+
21+
assert not scope.inbound_enabled
22+
23+
24+
def test_add_project_to_job_token_scope_allowlist(gl, project):
25+
project_to_add = gl.projects.create({"name": "Ci_Cd_token_add_proj"})
26+
27+
scope = project.job_token_scope.get()
28+
resp = scope.allowlist.create({"target_project_id": project_to_add.id})
29+
30+
assert resp.source_project_id == project.id
31+
assert resp.target_project_id == project_to_add.id
32+
33+
project_to_add.delete()
34+
35+
36+
def test_projects_job_token_scope_allowlist_contains_added_project_name(gl, project):
37+
scope = project.job_token_scope.get()
38+
project_name = "Ci_Cd_token_named_proj"
39+
project_to_add = gl.projects.create({"name": project_name})
40+
scope.allowlist.create({"target_project_id": project_to_add.id})
41+
42+
scope.refresh()
43+
assert any(allowed.name == project_name for allowed in scope.allowlist.list())
44+
45+
project_to_add.delete()
46+
47+
48+
def test_remove_project_by_id_from_projects_job_token_scope_allowlist(gl, project):
49+
scope = project.job_token_scope.get()
50+
51+
project_to_add = gl.projects.create({"name": "Ci_Cd_token_remove_proj"})
52+
53+
scope.allowlist.create({"target_project_id": project_to_add.id})
54+
55+
scope.refresh()
56+
57+
scope.allowlist.delete(project_to_add.id)
58+
59+
scope.refresh()
60+
assert not any(
61+
allowed.id == project_to_add.id for allowed in scope.allowlist.list()
62+
)
63+
64+
project_to_add.delete()
65+
66+
67+
def test_add_group_to_job_token_scope_allowlist(gl, project):
68+
group_to_add = gl.groups.create(
69+
{"name": "add_group", "path": "allowlisted-add-test"}
70+
)
71+
72+
scope = project.job_token_scope.get()
73+
resp = scope.groups_allowlist.create({"target_group_id": group_to_add.id})
74+
75+
assert resp.source_project_id == project.id
76+
assert resp.target_group_id == group_to_add.id
77+
78+
group_to_add.delete()
79+
80+
81+
def test_projects_job_token_scope_groups_allowlist_contains_added_group_name(
82+
gl, project
83+
):
84+
scope = project.job_token_scope.get()
85+
group_name = "list_group"
86+
group_to_add = gl.groups.create(
87+
{"name": group_name, "path": "allowlisted-add-and-list-test"}
88+
)
89+
90+
scope.groups_allowlist.create({"target_group_id": group_to_add.id})
91+
92+
scope.refresh()
93+
assert any(allowed.name == group_name for allowed in scope.groups_allowlist.list())
94+
95+
group_to_add.delete()
96+
97+
98+
def test_remove_group_by_id_from_projects_job_token_scope_groups_allowlist(gl, project):
99+
scope = project.job_token_scope.get()
100+
101+
group_to_add = gl.groups.create(
102+
{"name": "delete_group", "path": "allowlisted-delete-test"}
103+
)
104+
105+
scope.groups_allowlist.create({"target_group_id": group_to_add.id})
106+
107+
scope.refresh()
108+
109+
scope.groups_allowlist.delete(group_to_add.id)
110+
111+
scope.refresh()
112+
assert not any(
113+
allowed.name == group_to_add.name for allowed in scope.groups_allowlist.list()
114+
)
115+
116+
group_to_add.delete()

0 commit comments

Comments
 (0)

Footer

© 2026 GitHub, Inc.