|
7 | 7 | import sys |
8 | 8 | import tempfile |
9 | 9 | from unittest import skip |
| 10 | +from unittest import mock |
10 | 11 |
|
11 | | -from git import GitCommandError, Repo |
| 12 | +from git import Git, GitCommandError, Repo |
12 | 13 | from git.exc import UnsafeOptionError, UnsafeProtocolError |
13 | 14 |
|
14 | 15 | from test.lib import TestBase, with_rw_directory, with_rw_repo, PathLikeMock |
@@ -346,6 +347,44 @@ def test_clone_from_unsafe_protocol(self): |
346 | 347 | Repo.clone_from(url, tmp_dir / "repo") |
347 | 348 | assert not tmp_file.exists() |
348 | 349 |
|
| 350 | + def test_clone_from_does_not_expand_environment_variables_in_url(self): |
| 351 | + urls = [ |
| 352 | + "https://example.com/$GITPYTHON_TEST_SECRET/repo.git", |
| 353 | + "https://example.com/${GITPYTHON_TEST_SECRET}/repo.git", |
| 354 | + "https://example.com/%GITPYTHON_TEST_SECRET%/repo.git", |
| 355 | + ] |
| 356 | + with mock.patch.dict(os.environ, {"GITPYTHON_TEST_SECRET": "sensitive-value"}): |
| 357 | + for url in urls: |
| 358 | + with mock.patch.object(Git, "_call_process", side_effect=RuntimeError) as call_process: |
| 359 | + with self.assertRaises(RuntimeError): |
| 360 | + Repo.clone_from(url, "unused") |
| 361 | + |
| 362 | + assert call_process.call_args[0][3] == url |
| 363 | + |
| 364 | + @with_rw_directory |
| 365 | + def test_clone_from_does_not_expand_environment_variables_in_stored_url(self, rw_dir): |
| 366 | + url = pathlib.Path(rw_dir) / "$GITPYTHON_TEST_SECRET" / "source" |
| 367 | + Git().init(url) |
| 368 | + |
| 369 | + with mock.patch.dict(os.environ, {"GITPYTHON_TEST_SECRET": "sensitive-value"}): |
| 370 | + cloned = Repo.clone_from(url, pathlib.Path(rw_dir) / "clone") |
| 371 | + |
| 372 | + assert cloned.remotes.origin.url == Git.polish_url(str(url), expand_vars=False) |
| 373 | + |
| 374 | + def test_clone_from_checks_polished_url_for_unsafe_protocol(self): |
| 375 | + with mock.patch.object(Git, "polish_url", return_value="ext::command"): |
| 376 | + with mock.patch.object(Git, "_call_process") as call_process: |
| 377 | + with self.assertRaises(UnsafeProtocolError): |
| 378 | + Repo.clone_from("$GITPYTHON_TEST_URL", "unused") |
| 379 | + |
| 380 | + call_process.assert_not_called() |
| 381 | + |
| 382 | + def test_polish_url_does_not_expand_environment_variables_for_cygwin(self): |
| 383 | + urls = ["$GITPYTHON_TEST_SECRET/repo", "user@example.com:$GITPYTHON_TEST_SECRET/repo"] |
| 384 | + with mock.patch.dict(os.environ, {"GITPYTHON_TEST_SECRET": "sensitive-value"}): |
| 385 | + for url in urls: |
| 386 | + assert Git.polish_url(url, is_cygwin=True, expand_vars=False) == url |
| 387 | + |
349 | 388 | def test_clone_from_unsafe_protocol_allowed(self): |
350 | 389 | with tempfile.TemporaryDirectory() as tdir: |
351 | 390 | tmp_dir = pathlib.Path(tdir) |
|
0 commit comments