| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a5d8b7f commit e19314d
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,8 +2,6 @@ | |||
| 2 | 2 | Personal Access Tokens | |
| 3 | 3 | ###################### | |
| 4 | 4 | ||
| 5 | - Get a list of personal access tokens | ||
| 6 | - | ||
| 7 | 5 | References | |
| 8 | 6 | ---------- | |
| 9 | 7 | ||
@@ -12,8 +10,14 @@ References | |||
| 12 | 10 | + :class:`gitlab.v4.objects.PersonalAccessToken` | |
| 13 | 11 | + :class:`gitlab.v4.objects.PersonalAcessTokenManager` | |
| 14 | 12 | + :attr:`gitlab.Gitlab.personal_access_tokens` | |
| 13 | + + :class:`gitlab.v4.objects.UserPersonalAccessToken` | ||
| 14 | + + :class:`gitlab.v4.objects.UserPersonalAcessTokenManager` | ||
| 15 | + + :attr:`gitlab.Gitlab.User.personal_access_tokens` | ||
| 16 | + | ||
| 17 | + * GitLab API: | ||
| 15 | 18 | ||
| 16 | - * GitLab API: https://docs.gitlab.com/ee/api/personal_access_tokens.html | ||
| 19 | + + https://docs.gitlab.com/ee/api/personal_access_tokens.html | ||
| 20 | + + https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token | ||
| 17 | 21 | ||
| 18 | 22 | Examples | |
| 19 | 23 | -------- | |
@@ -26,3 +30,25 @@ List personal access tokens:: | |||
| 26 | 30 | List personal access tokens from other user_id (admin only):: | |
| 27 | 31 | ||
| 28 | 32 | access_tokens = gl.personal_access_tokens.list(user_id=25) | |
| 33 | + | ||
| 34 | + Revoke a personal access token fetched via list:: | ||
| 35 | + | ||
| 36 | + access_token = access_tokens[0] | ||
| 37 | + access_token.delete() | ||
| 38 | + | ||
| 39 | + Revoke a personal access token by id:: | ||
| 40 | + | ||
| 41 | + gl.personal_access_tokens.delete(123) | ||
| 42 | + | ||
| 43 | + Create a personal access token for a user (admin only):: | ||
| 44 | + | ||
| 45 | + user = gl.users.get(25, lazy=True) | ||
| 46 | + access_token = user.personal_access_tokens.create({"name": "test", "scopes": "api"}) | ||
| 47 | + | ||
| 48 | + .. note:: As you can see above, you can only create personal access tokens | ||
| 49 | + via the Users API, but you cannot revoke these objects directly. | ||
| 50 | + This is because the create API uses a different endpoint than the list and revoke APIs. | ||
| 51 | + You need to fetch the token via the list API first to revoke it. | ||
| 52 | + | ||
| 53 | + As of 14.2, GitLab does not provide a GET API for single personal access tokens. | ||
| 54 | + You must use the list method to retrieve single tokens. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,17 +1,32 @@ | |||
| 1 | - from gitlab.base import RESTManager, RESTObject | ||
| 2 | - from gitlab.mixins import ListMixin | ||
| 1 | + from gitlab.base import RequiredOptional, RESTManager, RESTObject | ||
| 2 | + from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin | ||
| 3 | 3 | ||
| 4 | 4 | __all__ = [ | |
| 5 | 5 | "PersonalAccessToken", | |
| 6 | 6 | "PersonalAccessTokenManager", | |
| 7 | + "UserPersonalAccessToken", | ||
| 8 | + "UserPersonalAccessTokenManager", | ||
| 7 | 9 | ] | |
| 8 | 10 | ||
| 9 | 11 | ||
| 10 | - class PersonalAccessToken(RESTObject): | ||
| 12 | + class PersonalAccessToken(ObjectDeleteMixin, RESTObject): | ||
| 11 | 13 | pass | |
| 12 | 14 | ||
| 13 | 15 | ||
| 14 | - class PersonalAccessTokenManager(ListMixin, RESTManager): | ||
| 16 | + class PersonalAccessTokenManager(DeleteMixin, ListMixin, RESTManager): | ||
| 15 | 17 | _path = "/personal_access_tokens" | |
| 16 | 18 | _obj_cls = PersonalAccessToken | |
| 17 | 19 | _list_filters = ("user_id",) | |
| 20 | + | ||
| 21 | + | ||
| 22 | + class UserPersonalAccessToken(RESTObject): | ||
| 23 | + pass | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + class UserPersonalAccessTokenManager(CreateMixin, RESTManager): | ||
| 27 | + _path = "/users/%(user_id)s/personal_access_tokens" | ||
| 28 | + _obj_cls = UserPersonalAccessToken | ||
| 29 | + _from_parent_attrs = {"user_id": "id"} | ||
| 30 | + _create_attrs = RequiredOptional( | ||
| 31 | + required=("name", "scopes"), optional=("expires_at",) | ||
| 32 | + ) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | 18 | from .custom_attributes import UserCustomAttributeManager # noqa: F401 | |
| 19 | 19 | from .events import UserEventManager # noqa: F401 | |
| 20 | + from .personal_access_tokens import UserPersonalAccessTokenManager # noqa: F401 | ||
| 20 | 21 | ||
| 21 | 22 | __all__ = [ | |
| 22 | 23 | "CurrentUserEmail", | |
@@ -122,6 +123,7 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject): | |||
| 122 | 123 | impersonationtokens: "UserImpersonationTokenManager" | |
| 123 | 124 | keys: "UserKeyManager" | |
| 124 | 125 | memberships: "UserMembershipManager" | |
| 126 | + personal_access_tokens: UserPersonalAccessTokenManager | ||
| 125 | 127 | projects: "UserProjectManager" | |
| 126 | 128 | status: "UserStatusManager" | |
| 127 | 129 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,46 +1,94 @@ | |||
| 1 | 1 | """ | |
| 2 | - GitLab API: https://docs.gitlab.com/ee/api/personal_access_tokens.html | ||
| 2 | + GitLab API: | ||
| 3 | + https://docs.gitlab.com/ee/api/personal_access_tokens.html | ||
| 4 | + https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token | ||
| 3 | 5 | """ | |
| 4 | 6 | ||
| 5 | 7 | import pytest | |
| 6 | 8 | import responses | |
| 7 | 9 | ||
| 10 | + user_id = 1 | ||
| 11 | + token_id = 1 | ||
| 12 | + token_name = "Test Token" | ||
| 13 | + | ||
| 14 | + token_url = "http://localhost/api/v4/personal_access_tokens" | ||
| 15 | + single_token_url = f"{token_url}/{token_id}" | ||
| 16 | + user_token_url = f"http://localhost/api/v4/users/{user_id}/personal_access_tokens" | ||
| 17 | + | ||
| 18 | + content = { | ||
| 19 | + "id": token_id, | ||
| 20 | + "name": token_name, | ||
| 21 | + "revoked": False, | ||
| 22 | + "created_at": "2020-07-23T14:31:47.729Z", | ||
| 23 | + "scopes": ["api"], | ||
| 24 | + "active": True, | ||
| 25 | + "user_id": user_id, | ||
| 26 | + "expires_at": None, | ||
| 27 | + } | ||
| 28 | + | ||
| 8 | 29 | ||
| 9 | 30 | @pytest.fixture | |
| 10 | - def resp_list_personal_access_token(): | ||
| 11 | - content = [ | ||
| 12 | - { | ||
| 13 | - "id": 4, | ||
| 14 | - "name": "Test Token", | ||
| 15 | - "revoked": False, | ||
| 16 | - "created_at": "2020-07-23T14:31:47.729Z", | ||
| 17 | - "scopes": ["api"], | ||
| 18 | - "active": True, | ||
| 19 | - "user_id": 24, | ||
| 20 | - "expires_at": None, | ||
| 21 | - } | ||
| 22 | - ] | ||
| 31 | + def resp_create_user_personal_access_token(): | ||
| 32 | + with responses.RequestsMock() as rsps: | ||
| 33 | + rsps.add( | ||
| 34 | + method=responses.POST, | ||
| 35 | + url=user_token_url, | ||
| 36 | + json=content, | ||
| 37 | + content_type="application/json", | ||
| 38 | + status=200, | ||
| 39 | + ) | ||
| 40 | + yield rsps | ||
| 23 | 41 | ||
| 42 | + | ||
| 43 | + @pytest.fixture | ||
| 44 | + def resp_personal_access_token(no_content): | ||
| 24 | 45 | with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: | |
| 25 | 46 | rsps.add( | |
| 26 | 47 | method=responses.GET, | |
| 27 | - url="http://localhost/api/v4/personal_access_tokens", | ||
| 28 | - json=content, | ||
| 48 | + url=token_url, | ||
| 49 | + json=[content], | ||
| 29 | 50 | content_type="application/json", | |
| 30 | 51 | status=200, | |
| 31 | 52 | ) | |
| 53 | + rsps.add( | ||
| 54 | + method=responses.DELETE, | ||
| 55 | + url=single_token_url, | ||
| 56 | + json=no_content, | ||
| 57 | + content_type="application/json", | ||
| 58 | + status=204, | ||
| 59 | + ) | ||
| 32 | 60 | yield rsps | |
| 33 | 61 | ||
| 34 | 62 | ||
| 35 | - def test_list_personal_access_tokens(gl, resp_list_personal_access_token): | ||
| 63 | + def test_create_personal_access_token(gl, resp_create_user_personal_access_token): | ||
| 64 | + user = gl.users.get(1, lazy=True) | ||
| 65 | + access_token = user.personal_access_tokens.create( | ||
| 66 | + {"name": token_name, "scopes": "api"} | ||
| 67 | + ) | ||
| 68 | + assert access_token.revoked is False | ||
| 69 | + assert access_token.name == token_name | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + def test_list_personal_access_tokens(gl, resp_personal_access_token): | ||
| 36 | 73 | access_tokens = gl.personal_access_tokens.list() | |
| 37 | 74 | assert len(access_tokens) == 1 | |
| 38 | 75 | assert access_tokens[0].revoked is False | |
| 39 | - assert access_tokens[0].name == "Test Token" | ||
| 76 | + assert access_tokens[0].name == token_name | ||
| 40 | 77 | ||
| 41 | 78 | ||
| 42 | - def test_list_personal_access_tokens_filter(gl, resp_list_personal_access_token): | ||
| 43 | - access_tokens = gl.personal_access_tokens.list(user_id=24) | ||
| 79 | + def test_list_personal_access_tokens_filter(gl, resp_personal_access_token): | ||
| 80 | + access_tokens = gl.personal_access_tokens.list(user_id=user_id) | ||
| 44 | 81 | assert len(access_tokens) == 1 | |
| 45 | 82 | assert access_tokens[0].revoked is False | |
| 46 | - assert access_tokens[0].user_id == 24 | ||
| 83 | + assert access_tokens[0].user_id == user_id | ||
| 84 | + | ||
| 85 | + | ||
| 86 | + def test_revoke_personal_access_token(gl, resp_personal_access_token): | ||
| 87 | + access_token = gl.personal_access_tokens.list(user_id=user_id)[0] | ||
| 88 | + access_token.delete() | ||
| 89 | + assert resp_personal_access_token.assert_call_count(single_token_url, 1) | ||
| 90 | + | ||
| 91 | + | ||
| 92 | + def test_revoke_personal_access_token_by_id(gl, resp_personal_access_token): | ||
| 93 | + gl.personal_access_tokens.delete(token_id) | ||
| 94 | + assert resp_personal_access_token.assert_call_count(single_token_url, 1) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments