Update/add tests for Repo.clone* · gitpython-developers/GitPython@b92f01a
@@ -13,7 +13,6 @@
1313import pickle
1414import sys
1515import tempfile
16-import uuid
1716from unittest import mock, skipIf, SkipTest
18171918import pytest
@@ -226,6 +225,7 @@ def test_clone_from_pathlib_withConfig(self, rw_dir):
226225"--config submodule.repo.update=checkout",
227226"--config filter.lfs.clean='git-lfs clean -- %f'",
228227 ],
228+allow_unsafe_options=True,
229229 )
230230231231self.assertEqual(cloned.config_reader().get_value("submodule", "active"), "repo")
@@ -266,39 +266,133 @@ def test_leaking_password_in_clone_logs(self, rw_dir):
266266to_path=rw_dir,
267267 )
268268269-def test_unsafe_options(self):
270-self.assertFalse(Repo.unsafe_options("github.com/deploy/deploy"))
269+@with_rw_repo("HEAD")
270+def test_clone_unsafe_options(self, rw_repo):
271+tmp_dir = pathlib.Path(tempfile.mkdtemp())
272+tmp_file = tmp_dir / "pwn"
273+unsafe_options = [
274+f"--upload-pack='touch {tmp_file}'",
275+f"-u 'touch {tmp_file}'",
276+"--config=protocol.ext.allow=always",
277+"-c protocol.ext.allow=always",
278+ ]
279+for unsafe_option in unsafe_options:
280+with self.assertRaises(UnsafeOptionError):
281+rw_repo.clone(tmp_dir, multi_options=[unsafe_option])
271282272-def test_unsafe_options_ext_url(self):
273-self.assertTrue(Repo.unsafe_options("ext::ssh"))
283+@with_rw_repo("HEAD")
284+def test_clone_unsafe_options_allowed(self, rw_repo):
285+tmp_dir = pathlib.Path(tempfile.mkdtemp())
286+tmp_file = tmp_dir / "pwn"
287+unsafe_options = [
288+f"--upload-pack='touch {tmp_file}'",
289+f"-u 'touch {tmp_file}'",
290+ ]
291+for i, unsafe_option in enumerate(unsafe_options):
292+destination = tmp_dir / str(i)
293+# The options will be allowed, but the command will fail.
294+with self.assertRaises(GitCommandError):
295+rw_repo.clone(destination, multi_options=[unsafe_option], allow_unsafe_options=True)
296+297+unsafe_options = [
298+"--config=protocol.ext.allow=always",
299+"-c protocol.ext.allow=always",
300+ ]
301+for i, unsafe_option in enumerate(unsafe_options):
302+destination = tmp_dir / str(i)
303+assert not destination.exists()
304+rw_repo.clone(destination, multi_options=[unsafe_option], allow_unsafe_options=True)
305+assert destination.exists()
274306275-def test_unsafe_options_multi_options_upload_pack(self):
276-self.assertTrue(Repo.unsafe_options("", ["--upload-pack='touch foo'"]))
307+@with_rw_repo("HEAD")
308+def test_clone_safe_options(self, rw_repo):
309+tmp_dir = pathlib.Path(tempfile.mkdtemp())
310+options = [
311+"--depth=1",
312+"--single-branch",
313+"-q",
314+ ]
315+for option in options:
316+destination = tmp_dir / option
317+assert not destination.exists()
318+rw_repo.clone(destination, multi_options=[option])
319+assert destination.exists()
277320278-def test_unsafe_options_multi_options_config_user(self):
279-self.assertFalse(Repo.unsafe_options("", ["--config user"]))
321+@with_rw_repo("HEAD")
322+def test_clone_from_unsafe_options(self, rw_repo):
323+tmp_dir = pathlib.Path(tempfile.mkdtemp())
324+tmp_file = tmp_dir / "pwn"
325+unsafe_options = [
326+f"--upload-pack='touch {tmp_file}'",
327+f"-u 'touch {tmp_file}'",
328+"--config=protocol.ext.allow=always",
329+"-c protocol.ext.allow=always",
330+ ]
331+for unsafe_option in unsafe_options:
332+with self.assertRaises(UnsafeOptionError):
333+Repo.clone_from(rw_repo.working_dir, tmp_dir, multi_options=[unsafe_option])
280334281-def test_unsafe_options_multi_options_config_protocol(self):
282-self.assertTrue(Repo.unsafe_options("", ["--config protocol.foo"]))
335+@with_rw_repo("HEAD")
336+def test_clone_from_unsafe_options_allowed(self, rw_repo):
337+tmp_dir = pathlib.Path(tempfile.mkdtemp())
338+tmp_file = tmp_dir / "pwn"
339+unsafe_options = [
340+f"--upload-pack='touch {tmp_file}'",
341+f"-u 'touch {tmp_file}'",
342+ ]
343+for i, unsafe_option in enumerate(unsafe_options):
344+destination = tmp_dir / str(i)
345+# The options will be allowed, but the command will fail.
346+with self.assertRaises(GitCommandError):
347+Repo.clone_from(
348+rw_repo.working_dir, destination, multi_options=[unsafe_option], allow_unsafe_options=True
349+ )
283350284-def test_clone_from_forbids_helper_urls_by_default(self):
285-with self.assertRaises(UnsafeOptionError):
286-Repo.clone_from("ext::sh -c touch% /tmp/foo", "tmp")
351+unsafe_options = [
352+"--config=protocol.ext.allow=always",
353+"-c protocol.ext.allow=always",
354+ ]
355+for i, unsafe_option in enumerate(unsafe_options):
356+destination = tmp_dir / str(i)
357+assert not destination.exists()
358+Repo.clone_from(rw_repo.working_dir, destination, multi_options=[unsafe_option], allow_unsafe_options=True)
359+assert destination.exists()
287360288361@with_rw_repo("HEAD")
289-def test_clone_from_allow_unsafe(self, repo):
290-bad_filename = pathlib.Path(f'{tempfile.gettempdir()}/{uuid.uuid4()}')
291-bad_url = f'ext::sh -c touch% {bad_filename}'
292-try:
293-repo.clone_from(
294-bad_url, 'tmp',
295-multi_options=["-c protocol.ext.allow=always"],
296-unsafe_protocols=True
297- )
298-except GitCommandError:
299-pass
300-self.assertTrue(bad_filename.is_file())
301-bad_filename.unlink()
362+def test_clone_from_safe_options(self, rw_repo):
363+tmp_dir = pathlib.Path(tempfile.mkdtemp())
364+options = [
365+"--depth=1",
366+"--single-branch",
367+"-q",
368+ ]
369+for option in options:
370+destination = tmp_dir / option
371+assert not destination.exists()
372+Repo.clone_from(rw_repo.common_dir, destination, multi_options=[option])
373+assert destination.exists()
374+375+def test_clone_from_unsafe_procol(self):
376+tmp_dir = pathlib.Path(tempfile.mkdtemp())
377+urls = [
378+"ext::sh -c touch% /tmp/pwn",
379+"fd::17/foo",
380+ ]
381+for url in urls:
382+with self.assertRaises(UnsafeProtocolError):
383+Repo.clone_from(url, tmp_dir)
384+385+def test_clone_from_unsafe_procol_allowed(self):
386+tmp_dir = pathlib.Path(tempfile.mkdtemp())
387+urls = [
388+"ext::sh -c touch% /tmp/pwn",
389+"fd::/foo",
390+ ]
391+for url in urls:
392+# The URL will be allowed into the command, but the command will
393+# fail since we don't have that protocol enabled in the Git config file.
394+with self.assertRaises(GitCommandError):
395+Repo.clone_from(url, tmp_dir, allow_unsafe_protocols=True)
302396303397@with_rw_repo("HEAD")
304398def test_max_chunk_size(self, repo):