gitlab_*_access_token: handle revoked field in group and project access tokens (#10196)
Some checks are pending
EOL CI / EOL Sanity (Ⓐ2.16) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py2.7) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.11) (push) Waiting to run
EOL CI / EOL Units (Ⓐ2.16+py3.6) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+alpine3+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+fedora38+py:azp/posix/3/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/1/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/2/) (push) Waiting to run
EOL CI / EOL I (Ⓐ2.16+opensuse15+py:azp/posix/3/) (push) Waiting to run
nox / Run extra sanity tests (push) Waiting to run

fix(gitlab): handle `revoked` field in group and project access tokens
This commit is contained in:
Massimo Gengarelli 2025-06-06 06:16:54 +02:00 committed by GitHub
parent 97e386f85b
commit b86e4af103
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 118 additions and 18 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- "gitlab_group_access_token, gitlab_project_access_token - fix handling of group and project access tokens for changes in GitLab 17.10 (https://github.com/ansible-collections/community.general/pull/10196)."

View file

@ -185,7 +185,7 @@ class GitLabGroupAccessToken(object):
@param name of the access token
'''
def find_access_token(self, group, name):
access_tokens = group.access_tokens.list(all=True)
access_tokens = [x for x in group.access_tokens.list(all=True) if not getattr(x, 'revoked', False)]
for access_token in access_tokens:
if (access_token.name == name):
self.access_token_object = access_token

View file

@ -183,7 +183,7 @@ class GitLabProjectAccessToken(object):
@param name of the access token
'''
def find_access_token(self, project, name):
access_tokens = project.access_tokens.list(all=True)
access_tokens = [x for x in project.access_tokens.list(all=True) if not getattr(x, 'revoked', False)]
for access_token in access_tokens:
if (access_token.name == name):
self.access_token_object = access_token

View file

@ -287,11 +287,36 @@ def resp_delete_group(url, request):
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/access_tokens", method="get")
def resp_list_group_access_tokens(url, request):
headers = {'content-type': 'application/json'}
content = ('[{"user_id" : 1, "scopes" : ["api"], "name" : "token1", "expires_at" : "2021-01-31",'
'"id" : 1, "active" : false, "created_at" : "2021-01-20T22:11:48.151Z", "revoked" : true,'
'"access_level": 40},{"user_id" : 2, "scopes" : ["api"], "name" : "token2", "expires_at" : "2021-02-31",'
'"id" : 2, "active" : true, "created_at" : "2021-02-20T22:11:48.151Z", "revoked" : false,'
'"access_level": 40}]')
content = (
'[{"id":689,"name":"test-token","revoked":true,"created_at":"2025-06-02T09:18:01.484Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1779,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"group","resource_id":1730},'
'{"id":690,"name":"test-token","revoked":true,"created_at":"2025-06-02T09:36:30.650Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1780,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"group","resource_id":1730},'
'{"id":691,"name":"test-token","revoked":false,"created_at":"2025-06-02T09:39:18.252Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1781,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"group","resource_id":1730},'
'{"id":695,"name":"test-token-no-revoked","created_at":"2025-06-02T09:39:18.252Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1781,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"group","resource_id":1730},'
'{"id":692,"name":"test-token-two","revoked":true,"created_at":"2025-06-02T09:41:18.442Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1782,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"group","resource_id":1730},'
'{"id":693,"name":"test-token-three","revoked":true,"created_at":"2025-06-02T09:50:00.976Z"'
',"description":null,"scopes":["read_repository","write_repository"],"user_id":1783,'
'"last_used_at":null,"active":false,"expires_at":"2025-06-04","access_level":40,'
'"resource_type":"group","resource_id":1730},'
'{"id":694,"name":"test-token-three","revoked":true,"created_at":"2025-06-02T09:56:45.779Z"'
',"description":null,"scopes":["read_repository","write_repository"],"user_id":1784,'
'"last_used_at":null,"active":false,"expires_at":"2025-06-04","access_level":40,'
'"resource_type":"group","resource_id":1730}]'
)
content = content.encode("utf-8")
return response(200, content, headers, None, 5, request)
@ -306,7 +331,7 @@ def resp_create_group_access_tokens(url, request):
return response(201, content, headers, None, 5, request)
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/access_tokens/1", method="delete")
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/access_tokens/[0-9]+", method="delete")
def resp_revoke_group_access_tokens(url, request):
headers = {'content-type': 'application/json'}
content = ('')
@ -567,11 +592,36 @@ def resp_delete_protected_branch(url, request):
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/access_tokens", method="get")
def resp_list_project_access_tokens(url, request):
headers = {'content-type': 'application/json'}
content = ('[{"user_id" : 1, "scopes" : ["api"], "name" : "token1", "expires_at" : "2021-01-31",'
'"id" : 1, "active" : false, "created_at" : "2021-01-20T22:11:48.151Z", "revoked" : true,'
'"access_level": 40},{"user_id" : 2, "scopes" : ["api"], "name" : "token2", "expires_at" : "2021-02-31",'
'"id" : 2, "active" : true, "created_at" : "2021-02-20T22:11:48.151Z", "revoked" : false,'
'"access_level": 40}]')
content = (
'[{"id":689,"name":"test-token","revoked":true,"created_at":"2025-06-02T09:18:01.484Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1779,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"project","resource_id":1730},'
'{"id":690,"name":"test-token","revoked":true,"created_at":"2025-06-02T09:36:30.650Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1780,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"project","resource_id":1730},'
'{"id":691,"name":"test-token","revoked":false,"created_at":"2025-06-02T09:39:18.252Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1781,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"project","resource_id":1730},'
'{"id":695,"name":"test-token-no-revoked","created_at":"2025-06-02T09:39:18.252Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1781,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"group","resource_id":1730},'
'{"id":692,"name":"test-token-two","revoked":true,"created_at":"2025-06-02T09:41:18.442Z",'
'"description":null,"scopes":["read_repository","write_repository"],"user_id":1782,'
'"last_used_at":null,"active":false,"expires_at":"2025-07-02","access_level":40,'
'"resource_type":"project","resource_id":1730},'
'{"id":693,"name":"test-token-three","revoked":true,"created_at":"2025-06-02T09:50:00.976Z"'
',"description":null,"scopes":["read_repository","write_repository"],"user_id":1783,'
'"last_used_at":null,"active":false,"expires_at":"2025-06-04","access_level":40,'
'"resource_type":"project","resource_id":1730},'
'{"id":694,"name":"test-token-three","revoked":true,"created_at":"2025-06-02T09:56:45.779Z"'
',"description":null,"scopes":["read_repository","write_repository"],"user_id":1784,'
'"last_used_at":null,"active":false,"expires_at":"2025-06-04","access_level":40,'
'"resource_type":"project","resource_id":1730}]'
)
content = content.encode("utf-8")
return response(200, content, headers, None, 5, request)
@ -586,7 +636,7 @@ def resp_create_project_access_tokens(url, request):
return response(201, content, headers, None, 5, request)
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/access_tokens/1", method="delete")
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/access_tokens/[0-9]+", method="delete")
def resp_revoke_project_access_tokens(url, request):
headers = {'content-type': 'application/json'}
content = ('')

View file

@ -68,9 +68,33 @@ class TestGitlabGroupAccessToken(GitlabModuleTestCase):
group = self.gitlab_instance.groups.get(1)
self.assertIsNotNone(group)
rvalue = self.moduleUtil.find_access_token(group, "token1")
rvalue = self.moduleUtil.find_access_token(group, "test-token")
self.assertEqual(rvalue, False)
self.assertIsNotNone(self.moduleUtil.access_token_object)
self.assertEqual(self.moduleUtil.access_token_object.id, 691)
self.assertFalse(self.moduleUtil.access_token_object.revoked)
@with_httmock(resp_get_group)
@with_httmock(resp_list_group_access_tokens)
def test_find_access_token_old_format(self):
group = self.gitlab_instance.groups.get(1)
self.assertIsNotNone(group)
rvalue = self.moduleUtil.find_access_token(group, "test-token-no-revoked")
self.assertEqual(rvalue, False)
self.assertIsNotNone(self.moduleUtil.access_token_object)
self.assertEqual(self.moduleUtil.access_token_object.id, 695)
self.assertFalse(hasattr(self.moduleUtil.access_token_object, "revoked"))
@with_httmock(resp_get_group)
@with_httmock(resp_list_group_access_tokens)
def test_find_revoked_access_token(self):
group = self.gitlab_instance.groups.get(1)
self.assertIsNotNone(group)
rvalue = self.moduleUtil.find_access_token(group, "test-token-three")
self.assertEqual(rvalue, False)
self.assertIsNone(self.moduleUtil.access_token_object)
@with_httmock(resp_get_group)
@with_httmock(resp_list_group_access_tokens)
@ -99,7 +123,7 @@ class TestGitlabGroupAccessToken(GitlabModuleTestCase):
groups = self.gitlab_instance.groups.get(1)
self.assertIsNotNone(groups)
rvalue = self.moduleUtil.find_access_token(groups, "token1")
rvalue = self.moduleUtil.find_access_token(groups, "test-token")
self.assertEqual(rvalue, False)
self.assertIsNotNone(self.moduleUtil.access_token_object)

View file

@ -68,9 +68,33 @@ class TestGitlabProjectAccessToken(GitlabModuleTestCase):
project = self.gitlab_instance.projects.get(1)
self.assertIsNotNone(project)
rvalue = self.moduleUtil.find_access_token(project, "token1")
rvalue = self.moduleUtil.find_access_token(project, "test-token")
self.assertEqual(rvalue, False)
self.assertIsNotNone(self.moduleUtil.access_token_object)
self.assertEqual(self.moduleUtil.access_token_object.id, 691)
self.assertFalse(self.moduleUtil.access_token_object.revoked)
@with_httmock(resp_get_project)
@with_httmock(resp_list_project_access_tokens)
def test_find_access_token_old_format(self):
project = self.gitlab_instance.projects.get(1)
self.assertIsNotNone(project)
rvalue = self.moduleUtil.find_access_token(project, "test-token-no-revoked")
self.assertEqual(rvalue, False)
self.assertIsNotNone(self.moduleUtil.access_token_object)
self.assertEqual(self.moduleUtil.access_token_object.id, 695)
self.assertFalse(hasattr(self.moduleUtil.access_token_object, "revoked"))
@with_httmock(resp_get_project)
@with_httmock(resp_list_project_access_tokens)
def test_find_revoked_access_token(self):
project = self.gitlab_instance.projects.get(1)
self.assertIsNotNone(project)
rvalue = self.moduleUtil.find_access_token(project, "test-token-three")
self.assertEqual(rvalue, False)
self.assertIsNone(self.moduleUtil.access_token_object)
@with_httmock(resp_get_project)
@with_httmock(resp_list_project_access_tokens)
@ -99,7 +123,7 @@ class TestGitlabProjectAccessToken(GitlabModuleTestCase):
project = self.gitlab_instance.projects.get(1)
self.assertIsNotNone(project)
rvalue = self.moduleUtil.find_access_token(project, "token1")
rvalue = self.moduleUtil.find_access_token(project, "test-token")
self.assertEqual(rvalue, False)
self.assertIsNotNone(self.moduleUtil.access_token_object)