Skip to content

Navigation Menu

Sign in
Appearance settings

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

Provide feedback

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

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2d1b749

Browse filesBrowse files
TimKnight-DWPnejch
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
Copy full SHA for 2d1b749

File tree

Expand file treeCollapse file tree

4 files changed

+353
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+353
-0
lines changed
Open diff view settings
Collapse file

‎docs/gl_objects/job_token_scope.rst‎

Copy file name to clipboardExpand all lines: docs/gl_objects/job_token_scope.rst
+50Lines changed: 50 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
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+
Collapse file

‎gitlab/v4/objects/job_token_scope.py‎

Copy file name to clipboardExpand all lines: gitlab/v4/objects/job_token_scope.py
+48Lines 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",))
Collapse file
+116Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.