Skip to content

Commit 458ed61

Browse files
committed
GitLab integration: escape path
The path/namespace must be url-encoded. https://docs.gitlab.com/ee/api/index.html#namespaced-path-encoding We were assuming that only the `/` needed to be escape, and that the namespace can't have more `/`. But GitLab has subgroups, which is parsed as the username in our code.
1 parent c42586f commit 458ed61

File tree

2 files changed

+19
-17
lines changed

2 files changed

+19
-17
lines changed

readthedocs/oauth/services/gitlab.py

+8-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import json
44
import logging
55
import re
6-
from urllib.parse import urlparse
6+
from urllib.parse import quote_plus, urlparse
77

88
from allauth.socialaccount.providers.gitlab.views import GitLabOAuth2Adapter
99
from django.conf import settings
@@ -16,13 +16,9 @@
1616
SELECT_BUILD_STATUS,
1717
)
1818
from readthedocs.integrations.models import Integration
19-
from readthedocs.projects.models import Project
2019

2120
from ..constants import GITLAB
22-
from ..models import (
23-
RemoteOrganization,
24-
RemoteRepository,
25-
)
21+
from ..models import RemoteOrganization, RemoteRepository
2622
from .base import Service, SyncServiceError
2723

2824
log = logging.getLogger(__name__)
@@ -52,8 +48,11 @@ class GitLabService(Service):
5248
vcs_provider_slug = GITLAB
5349

5450
def _get_repo_id(self, project):
55-
# The ID or URL-encoded path of the project
56-
# https://docs.gitlab.com/ce/api/README.html#namespaced-path-encoding
51+
"""
52+
Get the ID or URL-encoded path of the project.
53+
54+
See https://docs.gitlab.com/ce/api/README.html#namespaced-path-encoding.
55+
"""
5756
if project.remote_repository:
5857
repo_id = project.remote_repository.remote_id
5958
else:
@@ -64,10 +63,7 @@ def _get_repo_id(self, project):
6463
if (username, repo) == (None, None):
6564
return None
6665

67-
repo_id = '{username}%2F{repo}'.format(
68-
username=username,
69-
repo=repo,
70-
)
66+
repo_id = quote_plus(f'{username}/{repo}')
7167
return repo_id
7268

7369
def get_next_url_to_paginate(self, response):

readthedocs/rtd_tests/tests/test_oauth.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010

1111
from readthedocs.builds.constants import BUILD_STATUS_SUCCESS, EXTERNAL
1212
from readthedocs.builds.models import Build, Version
13-
from readthedocs.integrations.models import (
14-
GitHubWebhook,
15-
GitLabWebhook,
16-
)
17-
from readthedocs.oauth.constants import GITHUB, BITBUCKET, GITLAB
13+
from readthedocs.integrations.models import GitHubWebhook, GitLabWebhook
14+
from readthedocs.oauth.constants import BITBUCKET, GITHUB, GITLAB
1815
from readthedocs.oauth.models import RemoteOrganization, RemoteRepository
1916
from readthedocs.oauth.services import (
2017
BitbucketService,
@@ -1009,6 +1006,15 @@ def get_private_repo_data(self):
10091006
})
10101007
return data
10111008

1009+
def test_project_path_is_escaped(self):
1010+
repo_id = self.service._get_repo_id(self.project)
1011+
self.assertEqual(repo_id, 'testorga%2Ftestrepo')
1012+
1013+
self.project.repo = 'https://gitlab.com/testorga/subgroup/testrepo.git'
1014+
self.project.save()
1015+
repo_id = self.service._get_repo_id(self.project)
1016+
self.assertEqual(repo_id, 'testorga%2Fsubgroup%2Ftestrepo')
1017+
10121018
def test_make_project_pass(self):
10131019
repo = self.service.create_repository(
10141020
self.repo_response_data, organization=self.org,

0 commit comments

Comments
 (0)