Skip to content

Commit 9386847

Browse files
committed
feat: add support for groups_allowlist in job_token_scope
Signed-off-by: Tim Knight <tim.knight1@engineering.digital.dwp.gov.uk>
1 parent 6f4a2fb commit 9386847

File tree

5 files changed

+207
-7
lines changed

5 files changed

+207
-7
lines changed

docs/gl_objects/job_token_scope.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,24 @@ Remove a project from the project's inbound allowlist::
6969
Similar to above, the ID attributes you receive from the create and list
7070
APIs are not consistent. To safely retrieve the ID of the allowlisted project
7171
regardless of how the object was created, always use its ``.get_id()`` method.
72+
73+
Get a project's CI/CD job token inbound groups allowlist::
74+
75+
allowlist = scope.groups_allowlist.list()
76+
77+
Add a project to the project's inbound groups allowlist::
78+
79+
allowed_project = scope.groups_allowlist.create({"target_project_id": 42})
80+
81+
Remove a project from the project's inbound agroups llowlist::
82+
83+
allowed_project.delete()
84+
# or directly using a Group ID
85+
scope.groups_allowlist.delete(42)
86+
87+
.. warning::
88+
89+
Similar to above, the ID attributes you receive from the create and list
90+
APIs are not consistent. To safely retrieve the ID of the allowlisted group
91+
regardless of how the object was created, always use its ``.get_id()`` method.
92+

gitlab/v4/objects/job_token_scope.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class ProjectJobTokenScope(RefreshMixin, SaveMixin, RESTObject):
2424
_id_attr = None
2525

2626
allowlist: "AllowlistedProjectManager"
27+
groups_allowlist: "AllowlistedGroupManager"
2728

2829

2930
class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
@@ -54,3 +55,23 @@ class AllowlistedProjectManager(ListMixin, CreateMixin, DeleteMixin, RESTManager
5455
_obj_cls = AllowlistedProject
5556
_from_parent_attrs = {"project_id": "project_id"}
5657
_create_attrs = RequiredOptional(required=("target_project_id",))
58+
59+
60+
class AllowlistedGroup(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_project_id` attribute
66+
is returned by the server depending on the endpoint called."""
67+
try:
68+
return cast(int, getattr(self, self._id_attr))
69+
except AttributeError:
70+
return cast(int, getattr(self, "id"))
71+
72+
73+
class AllowlistedGroupManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
74+
_path = "/projects/{project_id}/job_token_scope/groups_allowlist"
75+
_obj_cls = AllowlistedProject
76+
_from_parent_attrs = {"project_id": "project_id"}
77+
_create_attrs = RequiredOptional(required=("target_group_id",))

tests/functional/api/test_project_job_token_scope.py

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
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+
124
def test_add_project_to_job_token_scope_allowlist(gl, project):
225
project_to_add = gl.projects.create({"name": "Ci_Cd_token_add_proj"})
326

@@ -12,8 +35,6 @@ def test_add_project_to_job_token_scope_allowlist(gl, project):
1235

1336
def test_projects_job_token_scope_allowlist_contains_added_project_name(gl, project):
1437
scope = project.job_token_scope.get()
15-
assert len(scope.allowlist.list()) == 0
16-
1738
project_name = "Ci_Cd_token_named_proj"
1839
project_to_add = gl.projects.create({"name": project_name})
1940
scope.allowlist.create({"target_project_id": project_to_add.id})
@@ -26,18 +47,70 @@ def test_projects_job_token_scope_allowlist_contains_added_project_name(gl, proj
2647

2748
def test_remove_project_by_id_from_projects_job_token_scope_allowlist(gl, project):
2849
scope = project.job_token_scope.get()
29-
assert len(scope.allowlist.list()) == 0
3050

3151
project_to_add = gl.projects.create({"name": "Ci_Cd_token_remove_proj"})
3252

3353
scope.allowlist.create({"target_project_id": project_to_add.id})
3454

3555
scope.refresh()
36-
assert len(scope.allowlist.list()) != 0
3756

38-
scope.allowlist.remove(project_to_add.id)
57+
scope.allowlist.delete(project_to_add.id)
3958

4059
scope.refresh()
41-
assert len(scope.allowlist.list()) == 0
60+
assert not any(
61+
allowed.id == project_to_add.id for allowed in scope.allowlist.list()
62+
)
4263

4364
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()

tests/functional/fixtures/.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
GITLAB_IMAGE=gitlab/gitlab-ee
2-
GITLAB_TAG=16.9.1-ee.0
2+
GITLAB_TAG=nightly

tests/unit/objects/test_job_token_scope.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,55 @@
66
import responses
77

88
from gitlab.v4.objects import ProjectJobTokenScope
9+
from gitlab.v4.objects.job_token_scope import (
10+
AllowlistedGroupManager,
11+
AllowlistedProjectManager,
12+
)
913

1014
job_token_scope_content = {
1115
"inbound_enabled": True,
1216
"outbound_enabled": False,
1317
}
1418

19+
project_allowlist_content = [
20+
{
21+
"id": 4,
22+
"description": "",
23+
"name": "Diaspora Client",
24+
"name_with_namespace": "Diaspora / Diaspora Client",
25+
"path": "diaspora-client",
26+
"path_with_namespace": "diaspora/diaspora-client",
27+
"created_at": "2013-09-30T13:46:02Z",
28+
"default_branch": "main",
29+
"tag_list": ["example", "disapora client"],
30+
"topics": ["example", "disapora client"],
31+
"ssh_url_to_repo": "git@gitlab.example.com:diaspora/diaspora-client.git",
32+
"http_url_to_repo": "https://gitlab.example.com/diaspora/diaspora-client.git",
33+
"web_url": "https://gitlab.example.com/diaspora/diaspora-client",
34+
"avatar_url": "https://gitlab.example.com/uploads/project/avatar/4/uploads/avatar.png",
35+
"star_count": 0,
36+
"last_activity_at": "2013-09-30T13:46:02Z",
37+
"namespace": {
38+
"id": 2,
39+
"name": "Diaspora",
40+
"path": "diaspora",
41+
"kind": "group",
42+
"full_path": "diaspora",
43+
"parent_id": "",
44+
"avatar_url": "",
45+
"web_url": "https://gitlab.example.com/diaspora",
46+
},
47+
}
48+
]
49+
50+
groups_allowlist_content = [
51+
{
52+
"id": 4,
53+
"web_url": "https://gitlab.example.com/groups/diaspora/diaspora-group",
54+
"name": "namegroup",
55+
}
56+
]
57+
1558

1659
@pytest.fixture
1760
def resp_get_job_token_scope():
@@ -26,6 +69,32 @@ def resp_get_job_token_scope():
2669
yield rsps
2770

2871

72+
@pytest.fixture
73+
def resp_get_allowlist():
74+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
75+
rsps.add(
76+
method=responses.GET,
77+
url="http://localhost/api/v4/projects/1/job_token_scope/allowlist",
78+
json=project_allowlist_content,
79+
content_type="application/json",
80+
status=200,
81+
)
82+
yield rsps
83+
84+
85+
@pytest.fixture
86+
def resp_get_groups_allowlist():
87+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
88+
rsps.add(
89+
method=responses.GET,
90+
url="http://localhost/api/v4/projects/1/job_token_scope/groups_allowlist",
91+
json=groups_allowlist_content,
92+
content_type="application/json",
93+
status=200,
94+
)
95+
yield rsps
96+
97+
2998
@pytest.fixture
3099
def resp_patch_job_token_scope():
31100
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
@@ -61,3 +130,19 @@ def test_save_job_token_scope(job_token_scope, resp_patch_job_token_scope):
61130

62131
def test_update_job_token_scope(project, resp_patch_job_token_scope):
63132
project.job_token_scope.update(new_data={"enabled": False})
133+
134+
135+
def test_get_projects_allowlist(job_token_scope, resp_get_allowlist):
136+
allowlist = job_token_scope.allowlist
137+
assert isinstance(allowlist, AllowlistedProjectManager)
138+
139+
allowlist_content = allowlist.list()
140+
assert isinstance(allowlist_content, list)
141+
142+
143+
def test_get_groups_allowlist(job_token_scope, resp_get_groups_allowlist):
144+
allowlist = job_token_scope.groups_allowlist
145+
assert isinstance(allowlist, AllowlistedGroupManager)
146+
147+
allowlist_content = allowlist.list()
148+
assert isinstance(allowlist_content, list)

0 commit comments

Comments
 (0)