Skip to content

Commit

Permalink
Remove credentials from 'url' for SCM replacement (#4207)
Browse files Browse the repository at this point in the history
* add 'remove_credentials' argument to SCMBase.get_remote_url

* modify comments

* do not remove credentials if it is a local path
  • Loading branch information
jgsogo authored and lasote committed Jan 2, 2019
1 parent 9d4baed commit 45eac22
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 11 deletions.
2 changes: 1 addition & 1 deletion conans/client/cmd/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def _capture_export_scm_data(conanfile, conanfile_dir, destination_folder, outpu
save(scm_src_file, src_path.replace("\\", "/"))

if scm_data.url == "auto":
origin = scm.get_qualified_remote_url()
origin = scm.get_qualified_remote_url(remove_credentials=True)
if not origin:
raise ConanException("Repo origin cannot be deduced by 'auto'")
if scm.is_local_repository():
Expand Down
24 changes: 19 additions & 5 deletions conans/client/tools/scm.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ def get_url_with_credentials(self, url):
url = url.replace("://", "://" + user_enc + ":" + pwd_enc + "@", 1)
return url

@classmethod
def _remove_credentials_url(cls, url):
parsed = urlparse(url)
netloc = parsed.hostname
if parsed.port:
netloc += ":{}".format(parsed.port)
replaced = parsed._replace(netloc=netloc)
return replaced.geturl()


class Git(SCMBase):
cmd_command = "git"
Expand Down Expand Up @@ -117,14 +126,16 @@ def excluded_files(self):
ret = []
return ret

def get_remote_url(self, remote_name=None):
def get_remote_url(self, remote_name=None, remove_credentials=False):
self._check_git_repo()
remote_name = remote_name or "origin"
remotes = self.run("remote -v")
for remote in remotes.splitlines():
name, url = remote.split(None, 1)
if name == remote_name:
url, _ = url.rsplit(None, 1)
if remove_credentials and not os.path.exists(url): # only if not local
url = self._remove_credentials_url(url)
return url
return None

Expand Down Expand Up @@ -261,12 +272,15 @@ def excluded_files(self):
excluded_list.append(os.path.normpath(filepath))
return excluded_list

def get_remote_url(self):
return self._show_item('url')
def get_remote_url(self, remove_credentials=False):
url = self._show_item('url')
if remove_credentials and not os.path.exists(url): # only if not local
url = self._remove_credentials_url(url)
return url

def get_qualified_remote_url(self):
def get_qualified_remote_url(self, remove_credentials=False):
# Return url with peg revision
url = self.get_remote_url()
url = self.get_remote_url(remove_credentials=remove_credentials)
revision = self.get_last_changed_revision()
return "{url}@{revision}".format(url=url, revision=revision)

Expand Down
10 changes: 5 additions & 5 deletions conans/model/scm.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ def checkout(self):
output += self.repo.checkout(url=self._data.url, revision=self._data.revision)
return output

def get_remote_url(self):
return self.repo.get_remote_url()
def get_remote_url(self, remove_credentials):
return self.repo.get_remote_url(remove_credentials=remove_credentials)

def get_revision(self):
return self.repo.get_revision()
Expand All @@ -91,11 +91,11 @@ def is_pristine(self):
def get_repo_root(self):
return self.repo.get_repo_root()

def get_qualified_remote_url(self):
def get_qualified_remote_url(self, remove_credentials):
if self._data.type == "git":
return self.repo.get_remote_url()
return self.repo.get_remote_url(remove_credentials=remove_credentials)
else:
return self.repo.get_qualified_remote_url()
return self.repo.get_qualified_remote_url(remove_credentials=remove_credentials)

def is_local_repository(self):
return self.repo.is_local_repository()
Empty file.
35 changes: 35 additions & 0 deletions conans/test/functional/scm/test_url_auto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# coding=utf-8

import unittest
import textwrap

from conans.test.utils.tools import TestClient
from conans.test.utils.tools import NO_SETTINGS_PACKAGE_ID, TestClient, TestServer, \
create_local_git_repo
from conans.model.ref import ConanFileReference, PackageReference


class RemoveCredentials(unittest.TestCase):

conanfile = textwrap.dedent("""\
from conans import ConanFile
class Lib(ConanFile):
scm = {"type": "git", "url": "auto"}
""")

def setUp(self):
self.ref = ConanFileReference.loads("lib/1.0@lasote/testing")
self.path, _ = create_local_git_repo({"conanfile.py": self.conanfile})
self.client = TestClient()
self.client.current_folder = self.path
self.client.runner("git remote add origin https://url.to.be.sustituted", cwd=self.path)

def test_https(self):
expected_url = 'https://myrepo.com.git'
origin_url = 'https://username:password@myrepo.com.git'

self.client.runner("git remote set-url origin {}".format(origin_url), cwd=self.path)
self.client.run("export . {}".format(self.ref))
self.assertIn("Repo origin deduced by 'auto': {}".format(expected_url), self.client.out)
Empty file.
21 changes: 21 additions & 0 deletions conans/test/unittests/client/tools/scm/test_git.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# coding=utf-8

import unittest

from conans.client.tools.scm import Git
from conans.test.utils.tools import temp_folder


class GitRemoteUrlTest(unittest.TestCase):

def test_remove_credentials(self):
""" Check that the 'remove_credentials' argument is taken into account """
expected_url = 'https://myrepo.com/path/to/repo.git'
origin_url = 'https://username:password@myrepo.com/path/to/repo.git'

git = Git(folder=temp_folder())
git.run("init .")
git.run("remote add origin {}".format(origin_url))

self.assertEqual(git.get_remote_url(), origin_url)
self.assertEqual(git.get_remote_url(remove_credentials=True), expected_url)
47 changes: 47 additions & 0 deletions conans/test/unittests/client/tools/scm/test_scm_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# coding=utf-8

import unittest

from conans.client.tools.scm import SCMBase


class RemoveCredentialsTest(unittest.TestCase):

def test_http(self):
expected_url = 'https://myrepo.com/path/to/repo.git'
test_urls = ['https://myrepo.com/path/to/repo.git',
'https://username:password@myrepo.com/path/to/repo.git',
'https://username@myrepo.com/path/to/repo.git',
'https://gitlab-ci-token:1324@myrepo.com/path/to/repo.git',
]

for it in test_urls:
self.assertEqual(expected_url, SCMBase._remove_credentials_url(it))

def test_http_with_port_number(self):
self.assertEqual('https://myrepo.com:8000/path/to/repo.git',
SCMBase._remove_credentials_url(
'https://username@myrepo.com:8000/path/to/repo.git'))

def test_ssh(self):
# Here, for ssh, we don't want to remove the user ('git' in this example)
self.assertEqual('git@github.com:conan-io/conan.git',
SCMBase._remove_credentials_url(
'git@github.com:conan-io/conan.git'))

def test_local_unix(self):
self.assertEqual('file:///srv/git/project.git',
SCMBase._remove_credentials_url('file:///srv/git/project.git'))
self.assertEqual('file:///srv/git/PROJECT.git',
SCMBase._remove_credentials_url('file:///srv/git/PROJECT.git'))

def test_local_windows(self):
self.assertEqual('file:///c:/srv/git/PROJECT',
SCMBase._remove_credentials_url('file:///c:/srv/git/PROJECT'))
self.assertEqual('file:///C:/srv/git/PROJECT',
SCMBase._remove_credentials_url('file:///C:/srv/git/PROJECT'))

def test_svn_ssh(self):
self.assertEqual('svn+ssh://10.106.191.164/home/svn/shproject',
SCMBase._remove_credentials_url(
'svn+ssh://username:password@10.106.191.164/home/svn/shproject'))
23 changes: 23 additions & 0 deletions conans/test/unittests/client/tools/scm/test_svn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# coding=utf-8

import unittest

from mock import patch

from conans.client.tools.scm import SVN
from conans.test.utils.tools import temp_folder


class SVNRemoteUrlTest(unittest.TestCase):

def test_remove_credentials(self):
""" Check that the 'remove_credentials' argument is taken into account """
expected_url = 'https://myrepo.com/path/to/repo'
origin_url = 'https://username:password@myrepo.com/path/to/repo'

svn = SVN(folder=temp_folder())

# Mocking, as we cannot change SVN remote to a non-existing url
with patch.object(svn, '_show_item', return_value=origin_url):
self.assertEqual(svn.get_remote_url(), origin_url)
self.assertEqual(svn.get_remote_url(remove_credentials=True), expected_url)

0 comments on commit 45eac22

Please sign in to comment.