Skip to content

Commit

Permalink
feat(api): add support for Gitlab Deploy Token API
Browse files Browse the repository at this point in the history
  • Loading branch information
ayoub mrini committed Apr 6, 2020
1 parent c5904c4 commit 01de524
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 8 deletions.
13 changes: 13 additions & 0 deletions docs/cli.rst
Expand Up @@ -207,6 +207,19 @@ Get a specific user by id:
$ gitlab user get --id 3
Create a deploy token for a project:

.. code-block:: console
$ gitlab -v project-deploy-token create --project-id 2 \
--name bar --username root --expires-at "2021-09-09" --scopes "read_repository"
List deploy tokens for a group:

.. code-block:: console
$ gitlab -v group-deploy-token list --group-id 3
Get a list of snippets for this project:

.. code-block:: console
Expand Down
137 changes: 137 additions & 0 deletions docs/gl_objects/deploy_tokens.rst
@@ -0,0 +1,137 @@
#######
Deploy tokens
#######

Deploy tokens allow read-only access to your repository and registry images
without having a user and a password.

Deploy tokens
=============

This endpoint requires admin access.

Reference
---------

* v4 API:

+ :class:`gitlab.v4.objects.DeployToken`
+ :class:`gitlab.v4.objects.DeployTokenManager`
+ :attr:`gitlab.Gitlab.deploytokens`

* GitLab API: https://docs.gitlab.com/ce/api/deploy_tokens.html

Examples
--------

Use the ``list()`` method to list all deploy tokens across the GitLab instance.

::

# List deploy tokens
deploy_tokens = gl.deploytokens.list()

Project deploy tokens
=====================

This endpoint requires project maintainer access or higher.

Reference
---------

* v4 API:

+ :class:`gitlab.v4.objects.ProjectDeployToken`
+ :class:`gitlab.v4.objects.ProjectDeployTokenManager`
+ :attr:`gitlab.v4.objects.Project.deploytokens`

* GitLab API: https://docs.gitlab.com/ce/api/deploy_tokens.html#project-deploy-tokens

Examples
--------

List the deploy tokens for a project::

deploy_tokens = project.deploytokens.list()

Create a new deploy token to access registry images of a project:

In addition to required parameters ``name`` and ``scopes``, this method accepts
the following parameters:

* ``expires_at`` Expiration date of the deploy token. Does not expire if no value is provided.
* ``username`` Username for deploy token. Default is ``gitlab+deploy-token-{n}``


::

deploy_token = project.deploytokens.create({'name': 'token1', 'scopes': ['read_registry'], 'username':'', 'expires_at':''})
# show its id
print(deploy_token.id)
# show the token value. Make sure you save it, you won't be able to access it again.
print(deploy_token.token)

.. warning::

With GitLab 12.9, even though ``username`` and ``expires_at`` are not required, they always have to be passed to the API.
You can set them to empty strings, see: https://gitlab.com/gitlab-org/gitlab/-/issues/211878.
Also, the ``username``'s value is ignored by the API and will be overriden with ``gitlab+deploy-token-{n}``,
see: https://gitlab.com/gitlab-org/gitlab/-/issues/211963
These issues were fixed in GitLab 12.10.

Remove a deploy token from the project::

deploy_token.delete()
# or
project.deploytokens.delete(deploy_token.id)


Group deploy tokens
===================

Reference
---------

* v4 API:

+ :class:`gitlab.v4.objects.GroupDeployToken`
+ :class:`gitlab.v4.objects.GroupDeployTokenManager`
+ :attr:`gitlab.v4.objects.Group.deploytokens`

* GitLab API: https://docs.gitlab.com/ce/api/deploy_tokens.html#group-deploy-tokens

Examples
--------

List the deploy tokens for a group::

deploy_tokens = group.deploytokens.list()

Create a new deploy token to access all repositories of all projects in a group:

In addition to required parameters ``name`` and ``scopes``, this method accepts
the following parameters:

* ``expires_at`` Expiration date of the deploy token. Does not expire if no value is provided.
* ``username`` Username for deploy token. Default is ``gitlab+deploy-token-{n}``

::

deploy_token = group.deploytokens.create({'name': 'token1', 'scopes': ['read_repository'], 'username':'', 'expires_at':''})
# show its id
print(deploy_token.id)

.. warning::

With GitLab 12.9, even though ``username`` and ``expires_at`` are not required, they always have to be passed to the API.
You can set them to empty strings, see: https://gitlab.com/gitlab-org/gitlab/-/issues/211878.
Also, the ``username``'s value is ignored by the API and will be overriden with ``gitlab+deploy-token-{n}``,
see: https://gitlab.com/gitlab-org/gitlab/-/issues/211963
These issues were fixed in GitLab 12.10.

Remove a deploy token from the group::

deploy_token.delete()
# or
group.deploytokens.delete(deploy_token.id)

1 change: 1 addition & 0 deletions gitlab/__init__.py
Expand Up @@ -119,6 +119,7 @@ def __init__(

self.broadcastmessages = objects.BroadcastMessageManager(self)
self.deploykeys = objects.DeployKeyManager(self)
self.deploytokens = objects.DeployTokenManager(self)
self.geonodes = objects.GeoNodeManager(self)
self.gitlabciymls = objects.GitlabciymlManager(self)
self.gitignores = objects.GitignoreManager(self)
Expand Down
34 changes: 34 additions & 0 deletions gitlab/tests/test_gitlab.py
Expand Up @@ -920,6 +920,40 @@ def resp_application_create(url, request):
self.assertEqual(application.redirect_uri, "http://localhost:8080")
self.assertEqual(application.scopes, ["api", "email"])

def test_deploy_tokens(self):
@urlmatch(
scheme="http",
netloc="localhost",
path="/api/v4/projects/1/deploy_tokens",
method="post",
)
def resp_deploy_token_create(url, request):
headers = {"content-type": "application/json"}
content = """{
"id": 1,
"name": "test_deploy_token",
"username": "custom-user",
"expires_at": "2022-01-01T00:00:00.000Z",
"token": "jMRvtPNxrn3crTAGukpZ",
"scopes": [ "read_repository" ]}"""
content = content.encode("utf-8")
return response(200, content, headers, None, 5, request)

with HTTMock(resp_deploy_token_create):
deploy_token = self.gl.projects.get(1, lazy=True).deploytokens.create(
{
"name": "test_deploy_token",
"expires_at": "2022-01-01T00:00:00.000Z",
"username": "custom-user",
"scopes": ["read_repository"],
}
)
self.assertIsInstance(deploy_token, ProjectDeployToken)
self.assertEqual(deploy_token.id, 1),
self.assertEqual(deploy_token.expires_at, "2022-01-01T00:00:00.000Z"),
self.assertEqual(deploy_token.username, "custom-user")
self.assertEqual(deploy_token.scopes, ["read_repository"])

def _default_config(self):
fd, temp_path = tempfile.mkstemp()
os.write(fd, valid_config)
Expand Down
39 changes: 39 additions & 0 deletions gitlab/v4/objects.py
Expand Up @@ -695,6 +695,43 @@ class DeployKeyManager(ListMixin, RESTManager):
_obj_cls = DeployKey


class DeployToken(ObjectDeleteMixin, RESTObject):
pass


class DeployTokenManager(ListMixin, RESTManager):
_path = "/deploy_tokens"
_obj_cls = DeployToken


class ProjectDeployToken(ObjectDeleteMixin, RESTObject):
pass


class ProjectDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
_path = "/projects/%(project_id)s/deploy_tokens"
_from_parent_attrs = {"project_id": "id"}
_obj_cls = ProjectDeployToken
_create_attrs = (
("name", "scopes",),
("expires_at", "username",),
)


class GroupDeployToken(ObjectDeleteMixin, RESTObject):
pass


class GroupDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
_path = "/groups/%(group_id)s/deploy_tokens"
_from_parent_attrs = {"group_id": "id"}
_obj_cls = GroupDeployToken
_create_attrs = (
("name", "scopes",),
("expires_at", "username",),
)


class NotificationSettings(SaveMixin, RESTObject):
_id_attr = None

Expand Down Expand Up @@ -1301,6 +1338,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
("subgroups", "GroupSubgroupManager"),
("variables", "GroupVariableManager"),
("clusters", "GroupClusterManager"),
("deploytokens", "GroupDeployTokenManager"),
)

@cli.register_custom_action("Group", ("to_project_id",))
Expand Down Expand Up @@ -4212,6 +4250,7 @@ class Project(SaveMixin, ObjectDeleteMixin, RESTObject):
("clusters", "ProjectClusterManager"),
("additionalstatistics", "ProjectAdditionalStatisticsManager"),
("issuesstatistics", "ProjectIssuesStatisticsManager"),
("deploytokens", "ProjectDeployTokenManager"),
)

@cli.register_custom_action("Project", ("submodule", "branch", "commit_sha"))
Expand Down
88 changes: 80 additions & 8 deletions tools/cli_test_v4.sh
Expand Up @@ -195,14 +195,6 @@ testcase "project upload" '
--filename '$(basename $0)' --filepath '$0' >/dev/null 2>&1
'

testcase "project deletion" '
GITLAB project delete --id "$PROJECT_ID"
'

testcase "group deletion" '
OUTPUT=$(try GITLAB group delete --id $GROUP_ID)
'

testcase "application settings get" '
GITLAB application-settings get >/dev/null 2>&1
'
Expand All @@ -222,3 +214,83 @@ testcase "values from files" '
echo $OUTPUT | grep -q "Multi line"
'

# Test deploy tokens
CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v project-deploy-token create --project-id $PROJECT_ID \
--name foo --username root --expires-at "2021-09-09" --scopes "read_registry")
CREATED_DEPLOY_TOKEN_ID=$(echo "$CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT" | grep ^id: | cut -d" " -f2)
testcase "create project deploy token" '
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "name: foo"
'
testcase "create project deploy token" '
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "expires-at: 2021-09-09T00:00:00.000Z"
'
testcase "create project deploy token" '
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep "scopes: " | grep -q "read_registry"
'
# Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/211963 is fixed
#testcase "create project deploy token" '
# echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "username: root"
#'

# Remove once https://gitlab.com/gitlab-org/gitlab/-/issues/211963 is fixed
testcase "create project deploy token" '
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "gitlab+deploy-token"
'

LIST_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v deploy-token list)
testcase "list all deploy tokens" '
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -q "name: foo"
'
testcase "list all deploy tokens" '
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -q "id: $CREATED_DEPLOY_TOKEN_ID"
'
testcase "list all deploy tokens" '
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -q "expires-at: 2021-09-09T00:00:00.000Z"
'
testcase "list all deploy tokens" '
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep "scopes: " | grep -q "read_registry"
'

testcase "list project deploy tokens" '
OUTPUT=$(GITLAB -v project-deploy-token list --project-id $PROJECT_ID)
echo $OUTPUT | grep -q "id: $CREATED_DEPLOY_TOKEN_ID"
'
testcase "delete project deploy token" '
GITLAB -v project-deploy-token delete --project-id $PROJECT_ID --id $CREATED_DEPLOY_TOKEN_ID
LIST_PROJECT_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v project-deploy-token list --project-id $PROJECT_ID)
echo $LIST_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
'
# Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/212523 is fixed
#testcase "delete project deploy token" '
# LIST_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v deploy-token list)
# echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
#'

CREATE_GROUP_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v group-deploy-token create --group-id $GROUP_ID \
--name bar --username root --expires-at "2021-09-09" --scopes "read_repository")
CREATED_DEPLOY_TOKEN_ID=$(echo "$CREATE_GROUP_DEPLOY_TOKEN_OUTPUT" | grep ^id: | cut -d" " -f2)
testcase "create group deploy token" '
echo $CREATE_GROUP_DEPLOY_TOKEN_OUTPUT | grep -q "name: bar"
'
testcase "list group deploy tokens" '
OUTPUT=$(GITLAB -v group-deploy-token list --group-id $GROUP_ID)
echo $OUTPUT | grep -q "id: $CREATED_DEPLOY_TOKEN_ID"
'
testcase "delete group deploy token" '
GITLAB -v group-deploy-token delete --group-id $GROUP_ID --id $CREATED_DEPLOY_TOKEN_ID
LIST_GROUP_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v group-deploy-token list --group-id $GROUP_ID)
echo $LIST_GROUP_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
'
# Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/212523 is fixed
#testcase "delete group deploy token" '
# LIST_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v deploy-token list)
# echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
#'

testcase "project deletion" '
GITLAB project delete --id "$PROJECT_ID"
'

testcase "group deletion" '
OUTPUT=$(try GITLAB group delete --id $GROUP_ID)
'

0 comments on commit 01de524

Please sign in to comment.