diff --git a/HISTORY.md b/HISTORY.md index edef710f0..50f855ba8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,8 @@ History is important, but our current roadmap can be found [here](https://github.com/cookiecutter/cookiecutter/projects) +## 2.1.1 (unreleased) + ## 2.1.0 (2022-05-30) ### Changes diff --git a/cookiecutter/vcs.py b/cookiecutter/vcs.py index 08cb2eb0c..bb4356b31 100644 --- a/cookiecutter/vcs.py +++ b/cookiecutter/vcs.py @@ -98,8 +98,12 @@ def clone(repo_url, checkout=None, clone_to_dir='.', no_input=False): stderr=subprocess.STDOUT, ) if checkout is not None: + checkout_params = [checkout] + # Avoid Mercurial "--config" and "--debugger" injection vulnerability + if repo_type == "hg": + checkout_params.insert(0, "--") subprocess.check_output( # nosec - [repo_type, 'checkout', checkout], + [repo_type, 'checkout', *checkout_params], cwd=repo_dir, stderr=subprocess.STDOUT, ) @@ -107,13 +111,13 @@ def clone(repo_url, checkout=None, clone_to_dir='.', no_input=False): output = clone_error.output.decode('utf-8') if 'not found' in output.lower(): raise RepositoryNotFound( - 'The repository {} could not be found, ' - 'have you made a typo?'.format(repo_url) + f'The repository {repo_url} could not be found, ' + 'have you made a typo?' ) if any(error in output for error in BRANCH_ERRORS): raise RepositoryCloneFailed( - 'The {} branch of repository {} could not found, ' - 'have you made a typo?'.format(checkout, repo_url) + f'The {checkout} branch of repository ' + f'{repo_url} could not found, have you made a typo?' ) logger.error('git clone failed with error: %s', output) raise diff --git a/tests/vcs/test_clone.py b/tests/vcs/test_clone.py index 9fc3b24fa..bd19ef1ab 100644 --- a/tests/vcs/test_clone.py +++ b/tests/vcs/test_clone.py @@ -122,8 +122,16 @@ def test_clone_should_invoke_vcs_command( mock_subprocess.assert_any_call( [repo_type, 'clone', repo_url], cwd=str(clone_dir), stderr=subprocess.STDOUT ) + + branch_info = [branch] + # We sanitize branch information for Mercurial + if repo_type == "hg": + branch_info.insert(0, "--") + mock_subprocess.assert_any_call( - [repo_type, 'checkout', branch], cwd=expected_repo_dir, stderr=subprocess.STDOUT + [repo_type, 'checkout', *branch_info], + cwd=expected_repo_dir, + stderr=subprocess.STDOUT, ) @@ -151,8 +159,8 @@ def test_clone_handles_repo_typo(mocker, clone_dir, error_message): vcs.clone(repository_url, clone_to_dir=str(clone_dir), no_input=True) assert str(err.value) == ( - 'The repository {} could not be found, have you made a typo?' - ).format(repository_url) + f'The repository {repository_url} could not be found, have you made a typo?' + ) @pytest.mark.parametrize( @@ -182,8 +190,8 @@ def test_clone_handles_branch_typo(mocker, clone_dir, error_message): assert str(err.value) == ( 'The unknown_branch branch of repository ' - '{} could not found, have you made a typo?' - ).format(repository_url) + f'{repository_url} could not found, have you made a typo?' + ) def test_clone_unknown_subprocess_error(mocker, clone_dir):