Skip to content

Commit a81525a

Browse files
committed
feat: add keys endpoint
1 parent 74f5e62 commit a81525a

File tree

7 files changed

+153
-0
lines changed

7 files changed

+153
-0
lines changed

docs/api-objects.rst

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ API examples
2525
gl_objects/geo_nodes
2626
gl_objects/groups
2727
gl_objects/issues
28+
gl_objects/keys
2829
gl_objects/boards
2930
gl_objects/labels
3031
gl_objects/notifications

docs/gl_objects/keys.rst

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
####
2+
Keys
3+
####
4+
5+
Keys
6+
====
7+
8+
Reference
9+
---------
10+
11+
* v4 API
12+
13+
+ :class:`gitlab.v4.objects.Key`
14+
+ :class:`gitlab.v4.objects.KeyManager`
15+
+ :attr:`gitlab.Gitlab.keys`
16+
17+
* GitLab API: https://docs.gitlab.com/ce/api/keys.html
18+
19+
Examples
20+
--------
21+
22+
Get an ssh key by its id (requires admin access)::
23+
24+
key = gl.keys.get(key_id)
25+
26+
Get an ssh key (requires admin access) or a deploy key by its fingerprint::
27+
28+
key = gl.keys.get(fingerprint="SHA256:ERJJ/OweAM6jA8OjJ/gXs4N5fqUaREEJnz/EyfywfXY")

gitlab/client.py

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def __init__(
119119
self.hooks = objects.HookManager(self)
120120
self.issues = objects.IssueManager(self)
121121
self.issues_statistics = objects.IssuesStatisticsManager(self)
122+
self.keys = objects.KeyManager(self)
122123
self.ldapgroups = objects.LDAPGroupManager(self)
123124
self.licenses = objects.LicenseManager(self)
124125
self.namespaces = objects.NamespaceManager(self)

gitlab/v4/objects/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
from .hooks import *
4444
from .issues import *
4545
from .jobs import *
46+
from .keys import *
4647
from .labels import *
4748
from .ldap import *
4849
from .members import *

gitlab/v4/objects/keys.py

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from gitlab.base import RESTManager, RESTObject
2+
from gitlab.mixins import GetMixin
3+
4+
__all__ = [
5+
"Key",
6+
"KeyManager",
7+
]
8+
9+
10+
class Key(RESTObject):
11+
pass
12+
13+
14+
class KeyManager(GetMixin, RESTManager):
15+
_path = "/keys"
16+
_obj_cls = Key
17+
18+
def get(self, id=None, **kwargs):
19+
if id is not None:
20+
return super(KeyManager, self).get(id, **kwargs)
21+
22+
if "fingerprint" not in kwargs:
23+
raise AttributeError("Missing attribute: id or fingerprint")
24+
25+
server_data = self.gitlab.http_get(self.path, **kwargs)
26+
return self._obj_cls(self, server_data)

tests/functional/api/test_keys.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
GitLab API:
3+
https://docs.gitlab.com/ce/api/keys.html
4+
"""
5+
import base64
6+
import hashlib
7+
8+
9+
def key_fingerprint(key):
10+
key_part = key.split()[1]
11+
decoded = base64.b64decode(key_part.encode("ascii"))
12+
digest = hashlib.sha256(decoded).digest()
13+
return "SHA256:" + base64.b64encode(digest).rstrip(b"=").decode("utf-8")
14+
15+
16+
def test_keys_ssh(gl, user, SSH_KEY):
17+
key = user.keys.create({"title": "foo@bar", "key": SSH_KEY})
18+
19+
# Get key by ID (admin only).
20+
key_by_id = gl.keys.get(key.id)
21+
assert key_by_id.title == key.title
22+
assert key_by_id.key == key.key
23+
24+
fingerprint = key_fingerprint(SSH_KEY)
25+
# Get key by fingerprint (admin only).
26+
key_by_fingerprint = gl.keys.get(fingerprint=fingerprint)
27+
assert key_by_fingerprint.title == key.title
28+
assert key_by_fingerprint.key == key.key
29+
30+
key.delete()
31+
32+
33+
def test_keys_deploy(gl, project, DEPLOY_KEY):
34+
key = project.keys.create({"title": "foo@bar", "key": DEPLOY_KEY})
35+
36+
fingerprint = key_fingerprint(DEPLOY_KEY)
37+
key_by_fingerprint = gl.keys.get(fingerprint=fingerprint)
38+
assert key_by_fingerprint.title == key.title
39+
assert key_by_fingerprint.key == key.key
40+
assert len(key_by_fingerprint.deploy_keys_projects) == 1
41+
42+
key.delete()

tests/unit/objects/test_keys.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
GitLab API: https://docs.gitlab.com/ce/api/keys.html
3+
"""
4+
import pytest
5+
import responses
6+
7+
from gitlab.v4.objects import Key
8+
9+
key_content = {"id": 1, "title": "title", "key": "ssh-keytype AAAAC3Nza/key comment"}
10+
11+
12+
@pytest.fixture
13+
def resp_get_key_by_id():
14+
with responses.RequestsMock() as rsps:
15+
rsps.add(
16+
method=responses.GET,
17+
url="http://localhost/api/v4/keys/1",
18+
json=key_content,
19+
content_type="application/json",
20+
status=200,
21+
)
22+
yield rsps
23+
24+
25+
@pytest.fixture
26+
def resp_get_key_by_fingerprint():
27+
with responses.RequestsMock() as rsps:
28+
rsps.add(
29+
method=responses.GET,
30+
url="http://localhost/api/v4/keys?fingerprint=foo",
31+
json=key_content,
32+
content_type="application/json",
33+
status=200,
34+
)
35+
yield rsps
36+
37+
38+
def test_get_key_by_id(gl, resp_get_key_by_id):
39+
key = gl.keys.get(1)
40+
assert isinstance(key, Key)
41+
assert key.id == 1
42+
assert key.title == "title"
43+
44+
45+
def test_get_key_by_fingerprint(gl, resp_get_key_by_fingerprint):
46+
key = gl.keys.get(fingerprint="foo")
47+
assert isinstance(key, Key)
48+
assert key.id == 1
49+
assert key.title == "title"
50+
51+
52+
def test_get_key_missing_attrs(gl):
53+
with pytest.raises(AttributeError):
54+
gl.keys.get()

0 commit comments

Comments
 (0)