| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 57749d4 commit b13971d
12 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -37,3 +37,12 @@ Revoke a group access token:: | |||
| 37 | 37 | gl.groups.get(1).access_tokens.delete(42) | |
| 38 | 38 | # or | |
| 39 | 39 | access_token.delete() | |
| 40 | + | ||
| 41 | + Rotate a group access token and retrieve its new value:: | ||
| 42 | + | ||
| 43 | + token = group.access_tokens.get(42, lazy=True) | ||
| 44 | + token.rotate() | ||
| 45 | + print(token.token) | ||
| 46 | + # or directly using a token ID | ||
| 47 | + new_token = group.access_tokens.rotate(42) | ||
| 48 | + print(new_token.token) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -52,6 +52,15 @@ Revoke the personal access token currently used:: | |||
| 52 | 52 | ||
| 53 | 53 | gl.personal_access_tokens.delete("self") | |
| 54 | 54 | ||
| 55 | + Rotate a personal access token and retrieve its new value:: | ||
| 56 | + | ||
| 57 | + token = gl.personal_access_tokens.get(42, lazy=True) | ||
| 58 | + token.rotate() | ||
| 59 | + print(token.token) | ||
| 60 | + # or directly using a token ID | ||
| 61 | + new_token = gl.personal_access_tokens.rotate(42) | ||
| 62 | + print(new_token.token) | ||
| 63 | + | ||
| 55 | 64 | Create a personal access token for a user (admin only):: | |
| 56 | 65 | ||
| 57 | 66 | user = gl.users.get(25, lazy=True) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -32,8 +32,17 @@ Create project access token:: | |||
| 32 | 32 | ||
| 33 | 33 | access_token = gl.projects.get(1).access_tokens.create({"name": "test", "scopes": ["api"], "expires_at": "2023-06-06"}) | |
| 34 | 34 | ||
| 35 | - Revoke a project access tokens:: | ||
| 35 | + Revoke a project access token:: | ||
| 36 | 36 | ||
| 37 | 37 | gl.projects.get(1).access_tokens.delete(42) | |
| 38 | 38 | # or | |
| 39 | 39 | access_token.delete() | |
| 40 | + | ||
| 41 | + Rotate a project access token and retrieve its new value:: | ||
| 42 | + | ||
| 43 | + token = project.access_tokens.get(42, lazy=True) | ||
| 44 | + token.rotate() | ||
| 45 | + print(token.token) | ||
| 46 | + # or directly using a token ID | ||
| 47 | + new_token = project.access_tokens.rotate(42) | ||
| 48 | + print(new_token.token) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -288,6 +288,10 @@ class GitlabRevertError(GitlabOperationError): | |||
| 288 | 288 | pass | |
| 289 | 289 | ||
| 290 | 290 | ||
| 291 | + class GitlabRotateError(GitlabOperationError): | ||
| 292 | + pass | ||
| 293 | + | ||
| 294 | + | ||
| 291 | 295 | class GitlabLicenseError(GitlabOperationError): | |
| 292 | 296 | pass | |
| 293 | 297 | ||
@@ -397,6 +401,7 @@ def wrapped_f(*args: Any, **kwargs: Any) -> Any: | |||
| 397 | 401 | "GitlabRestoreError", | |
| 398 | 402 | "GitlabRetryError", | |
| 399 | 403 | "GitlabRevertError", | |
| 404 | + "GitlabRotateError", | ||
| 400 | 405 | "GitlabSearchError", | |
| 401 | 406 | "GitlabSetError", | |
| 402 | 407 | "GitlabStopError", | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -653,6 +653,65 @@ def download( | |||
| 653 | 653 | ) | |
| 654 | 654 | ||
| 655 | 655 | ||
| 656 | + class RotateMixin(_RestManagerBase): | ||
| 657 | + _computed_path: Optional[str] | ||
| 658 | + _from_parent_attrs: Dict[str, Any] | ||
| 659 | + _obj_cls: Optional[Type[base.RESTObject]] | ||
| 660 | + _parent: Optional[base.RESTObject] | ||
| 661 | + _parent_attrs: Dict[str, Any] | ||
| 662 | + _path: Optional[str] | ||
| 663 | + gitlab: gitlab.Gitlab | ||
| 664 | + | ||
| 665 | + @exc.on_http_error(exc.GitlabRotateError) | ||
| 666 | + def rotate( | ||
| 667 | + self, id: Union[str, int], expires_at: Optional[str] = None, **kwargs: Any | ||
| 668 | + ) -> Dict[str, Any]: | ||
| 669 | + """Rotate an access token. | ||
| 670 | + | ||
| 671 | + Args: | ||
| 672 | + id: ID of the token to rotate | ||
| 673 | + **kwargs: Extra options to send to the server (e.g. sudo) | ||
| 674 | + | ||
| 675 | + Raises: | ||
| 676 | + GitlabAuthenticationError: If authentication is not correct | ||
| 677 | + GitlabRotateError: If the server cannot perform the request | ||
| 678 | + """ | ||
| 679 | + path = f"{self.path}/{utils.EncodedId(id)}/rotate" | ||
| 680 | + data: Dict[str, Any] = {} | ||
| 681 | + if expires_at is not None: | ||
| 682 | + data = {"expires_at": expires_at} | ||
| 683 | + | ||
| 684 | + server_data = self.gitlab.http_post(path, post_data=data, **kwargs) | ||
| 685 | + if TYPE_CHECKING: | ||
| 686 | + assert not isinstance(server_data, requests.Response) | ||
| 687 | + return server_data | ||
| 688 | + | ||
| 689 | + | ||
| 690 | + class ObjectRotateMixin(_RestObjectBase): | ||
| 691 | + _id_attr: Optional[str] | ||
| 692 | + _attrs: Dict[str, Any] | ||
| 693 | + _module: ModuleType | ||
| 694 | + _parent_attrs: Dict[str, Any] | ||
| 695 | + _updated_attrs: Dict[str, Any] | ||
| 696 | + manager: base.RESTManager | ||
| 697 | + | ||
| 698 | + def rotate(self, **kwargs: Any) -> None: | ||
| 699 | + """Rotate the current access token object. | ||
| 700 | + | ||
| 701 | + Args: | ||
| 702 | + **kwargs: Extra options to send to the server (e.g. sudo) | ||
| 703 | + | ||
| 704 | + Raises: | ||
| 705 | + GitlabAuthenticationError: If authentication is not correct | ||
| 706 | + GitlabRotateError: If the server cannot perform the request | ||
| 707 | + """ | ||
| 708 | + if TYPE_CHECKING: | ||
| 709 | + assert isinstance(self.manager, RotateMixin) | ||
| 710 | + assert self.encoded_id is not None | ||
| 711 | + server_data = self.manager.rotate(self.encoded_id, **kwargs) | ||
| 712 | + self._update_attrs(server_data) | ||
| 713 | + | ||
| 714 | + | ||
| 656 | 715 | class SubscribableMixin(_RestObjectBase): | |
| 657 | 716 | _id_attr: Optional[str] | |
| 658 | 717 | _attrs: Dict[str, Any] | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,14 @@ | |||
| 1 | 1 | from typing import Any, cast, Union | |
| 2 | 2 | ||
| 3 | 3 | from gitlab.base import RESTManager, RESTObject | |
| 4 | - from gitlab.mixins import CreateMixin, DeleteMixin, ObjectDeleteMixin, RetrieveMixin | ||
| 4 | + from gitlab.mixins import ( | ||
| 5 | + CreateMixin, | ||
| 6 | + DeleteMixin, | ||
| 7 | + ObjectDeleteMixin, | ||
| 8 | + ObjectRotateMixin, | ||
| 9 | + RetrieveMixin, | ||
| 10 | + RotateMixin, | ||
| 11 | + ) | ||
| 5 | 12 | from gitlab.types import ArrayAttribute, RequiredOptional | |
| 6 | 13 | ||
| 7 | 14 | __all__ = [ | |
@@ -10,11 +17,13 @@ | |||
| 10 | 17 | ] | |
| 11 | 18 | ||
| 12 | 19 | ||
| 13 | - class GroupAccessToken(ObjectDeleteMixin, RESTObject): | ||
| 20 | + class GroupAccessToken(ObjectDeleteMixin, ObjectRotateMixin, RESTObject): | ||
| 14 | 21 | pass | |
| 15 | 22 | ||
| 16 | 23 | ||
| 17 | - class GroupAccessTokenManager(CreateMixin, DeleteMixin, RetrieveMixin, RESTManager): | ||
| 24 | + class GroupAccessTokenManager( | ||
| 25 | + CreateMixin, DeleteMixin, RetrieveMixin, RotateMixin, RESTManager | ||
| 26 | + ): | ||
| 18 | 27 | _path = "/groups/{group_id}/access_tokens" | |
| 19 | 28 | _obj_cls = GroupAccessToken | |
| 20 | 29 | _from_parent_attrs = {"group_id": "id"} | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,14 @@ | |||
| 1 | 1 | from typing import Any, cast, Union | |
| 2 | 2 | ||
| 3 | 3 | from gitlab.base import RESTManager, RESTObject | |
| 4 | - from gitlab.mixins import CreateMixin, DeleteMixin, ObjectDeleteMixin, RetrieveMixin | ||
| 4 | + from gitlab.mixins import ( | ||
| 5 | + CreateMixin, | ||
| 6 | + DeleteMixin, | ||
| 7 | + ObjectDeleteMixin, | ||
| 8 | + ObjectRotateMixin, | ||
| 9 | + RetrieveMixin, | ||
| 10 | + RotateMixin, | ||
| 11 | + ) | ||
| 5 | 12 | from gitlab.types import ArrayAttribute, RequiredOptional | |
| 6 | 13 | ||
| 7 | 14 | __all__ = [ | |
@@ -12,11 +19,11 @@ | |||
| 12 | 19 | ] | |
| 13 | 20 | ||
| 14 | 21 | ||
| 15 | - class PersonalAccessToken(ObjectDeleteMixin, RESTObject): | ||
| 22 | + class PersonalAccessToken(ObjectDeleteMixin, ObjectRotateMixin, RESTObject): | ||
| 16 | 23 | pass | |
| 17 | 24 | ||
| 18 | 25 | ||
| 19 | - class PersonalAccessTokenManager(DeleteMixin, RetrieveMixin, RESTManager): | ||
| 26 | + class PersonalAccessTokenManager(DeleteMixin, RetrieveMixin, RotateMixin, RESTManager): | ||
| 20 | 27 | _path = "/personal_access_tokens" | |
| 21 | 28 | _obj_cls = PersonalAccessToken | |
| 22 | 29 | _list_filters = ("user_id",) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,14 @@ | |||
| 1 | 1 | from typing import Any, cast, Union | |
| 2 | 2 | ||
| 3 | 3 | from gitlab.base import RESTManager, RESTObject | |
| 4 | - from gitlab.mixins import CreateMixin, DeleteMixin, ObjectDeleteMixin, RetrieveMixin | ||
| 4 | + from gitlab.mixins import ( | ||
| 5 | + CreateMixin, | ||
| 6 | + DeleteMixin, | ||
| 7 | + ObjectDeleteMixin, | ||
| 8 | + ObjectRotateMixin, | ||
| 9 | + RetrieveMixin, | ||
| 10 | + RotateMixin, | ||
| 11 | + ) | ||
| 5 | 12 | from gitlab.types import ArrayAttribute, RequiredOptional | |
| 6 | 13 | ||
| 7 | 14 | __all__ = [ | |
@@ -10,11 +17,13 @@ | |||
| 10 | 17 | ] | |
| 11 | 18 | ||
| 12 | 19 | ||
| 13 | - class ProjectAccessToken(ObjectDeleteMixin, RESTObject): | ||
| 20 | + class ProjectAccessToken(ObjectDeleteMixin, ObjectRotateMixin, RESTObject): | ||
| 14 | 21 | pass | |
| 15 | 22 | ||
| 16 | 23 | ||
| 17 | - class ProjectAccessTokenManager(CreateMixin, DeleteMixin, RetrieveMixin, RESTManager): | ||
| 24 | + class ProjectAccessTokenManager( | ||
| 25 | + CreateMixin, DeleteMixin, RetrieveMixin, RotateMixin, RESTManager | ||
| 26 | + ): | ||
| 18 | 27 | _path = "/projects/{project_id}/access_tokens" | |
| 19 | 28 | _obj_cls = ProjectAccessToken | |
| 20 | 29 | _from_parent_attrs = {"project_id": "id"} | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -32,6 +32,7 @@ def token_content(): | |||
| 32 | 32 | "active": True, | |
| 33 | 33 | "created_at": "2021-01-20T22:11:48.151Z", | |
| 34 | 34 | "revoked": False, | |
| 35 | + "token": "s3cr3t", | ||
| 35 | 36 | } | |
| 36 | 37 | ||
| 37 | 38 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -35,23 +35,12 @@ def resp_get_group_access_token(token_content): | |||
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | 37 | @pytest.fixture | |
| 38 | - def resp_create_group_access_token(): | ||
| 39 | - content = { | ||
| 40 | - "user_id": 141, | ||
| 41 | - "scopes": ["api"], | ||
| 42 | - "name": "token", | ||
| 43 | - "expires_at": "2021-01-31", | ||
| 44 | - "id": 42, | ||
| 45 | - "active": True, | ||
| 46 | - "created_at": "2021-01-20T22:11:48.151Z", | ||
| 47 | - "revoked": False, | ||
| 48 | - } | ||
| 49 | - | ||
| 38 | + def resp_create_group_access_token(token_content): | ||
| 50 | 39 | with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: | |
| 51 | 40 | rsps.add( | |
| 52 | 41 | method=responses.POST, | |
| 53 | 42 | url="http://localhost/api/v4/groups/1/access_tokens", | |
| 54 | - json=content, | ||
| 43 | + json=token_content, | ||
| 55 | 44 | content_type="application/json", | |
| 56 | 45 | status=200, | |
| 57 | 46 | ) | |
@@ -89,6 +78,19 @@ def resp_revoke_group_access_token(): | |||
| 89 | 78 | yield rsps | |
| 90 | 79 | ||
| 91 | 80 | ||
| 81 | + @pytest.fixture | ||
| 82 | + def resp_rotate_group_access_token(token_content): | ||
| 83 | + with responses.RequestsMock() as rsps: | ||
| 84 | + rsps.add( | ||
| 85 | + method=responses.POST, | ||
| 86 | + url="http://localhost/api/v4/groups/1/access_tokens/1/rotate", | ||
| 87 | + json=token_content, | ||
| 88 | + content_type="application/json", | ||
| 89 | + status=200, | ||
| 90 | + ) | ||
| 91 | + yield rsps | ||
| 92 | + | ||
| 93 | + | ||
| 92 | 94 | def test_list_group_access_tokens(gl, resp_list_group_access_token): | |
| 93 | 95 | access_tokens = gl.groups.get(1, lazy=True).access_tokens.list() | |
| 94 | 96 | assert len(access_tokens) == 1 | |
@@ -118,3 +120,10 @@ def test_revoke_group_access_token( | |||
| 118 | 120 | gl.groups.get(1, lazy=True).access_tokens.delete(42) | |
| 119 | 121 | access_token = gl.groups.get(1, lazy=True).access_tokens.list()[0] | |
| 120 | 122 | access_token.delete() | |
| 123 | + | ||
| 124 | + | ||
| 125 | + def test_rotate_group_access_token(group, resp_rotate_group_access_token): | ||
| 126 | + access_token = group.access_tokens.get(1, lazy=True) | ||
| 127 | + access_token.rotate() | ||
| 128 | + assert isinstance(access_token, GroupAccessToken) | ||
| 129 | + assert access_token.token == "s3cr3t" | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments