Submodule tests · gitpython-developers/GitPython@9dc4392
@@ -3,6 +3,8 @@
33# the BSD License: http://www.opensource.org/licenses/bsd-license.php
44import os
55import shutil
6+import tempfile
7+from pathlib import Path
68import sys
79from unittest import skipIf
810@@ -12,7 +14,13 @@
1214from git.cmd import Git
1315from git.compat import is_win
1416from git.config import GitConfigParser, cp
15-from git.exc import InvalidGitRepositoryError, RepositoryDirtyError
17+from git.exc import (
18+GitCommandError,
19+InvalidGitRepositoryError,
20+RepositoryDirtyError,
21+UnsafeOptionError,
22+UnsafeProtocolError,
23+)
1624from git.objects.submodule.base import Submodule
1725from git.objects.submodule.root import RootModule, RootUpdateProgress
1826from git.repo.fun import find_submodule_git_dir, touch
@@ -1090,3 +1098,109 @@ def test_add_no_clone_multi_options_argument(self, rwdir):
10901098sm_config = GitConfigParser(file_or_files=osp.join(parent.git_dir, "modules", sm_name, "config"))
10911099with self.assertRaises(cp.NoOptionError):
10921100sm_config.get_value("core", "eol")
1101+1102+@with_rw_repo("HEAD")
1103+def test_submodule_add_unsafe_url(self, rw_repo):
1104+urls = [
1105+"ext::sh -c touch% /tmp/pwn",
1106+"fd::/foo",
1107+ ]
1108+for url in urls:
1109+with self.assertRaises(UnsafeProtocolError):
1110+Submodule.add(rw_repo, "new", "new", url)
1111+1112+@with_rw_repo("HEAD")
1113+def test_submodule_add_unsafe_url_allowed(self, rw_repo):
1114+urls = [
1115+"ext::sh -c touch% /tmp/pwn",
1116+"fd::/foo",
1117+ ]
1118+for url in urls:
1119+# The URL will be allowed into the command, but the command will
1120+# fail since we don't have that protocol enabled in the Git config file.
1121+with self.assertRaises(GitCommandError):
1122+Submodule.add(rw_repo, "new", "new", url, allow_unsafe_protocols=True)
1123+1124+@with_rw_repo("HEAD")
1125+def test_submodule_add_unsafe_options(self, rw_repo):
1126+tmp_dir = Path(tempfile.mkdtemp())
1127+tmp_file = tmp_dir / "pwn"
1128+unsafe_options = [
1129+f"--upload-pack='touch {tmp_file}'",
1130+f"-u 'touch {tmp_file}'",
1131+"--config=protocol.ext.allow=always",
1132+"-c protocol.ext.allow=always",
1133+ ]
1134+for unsafe_option in unsafe_options:
1135+with self.assertRaises(UnsafeOptionError):
1136+Submodule.add(rw_repo, "new", "new", str(tmp_dir), clone_multi_options=[unsafe_option])
1137+1138+@with_rw_repo("HEAD")
1139+def test_submodule_add_unsafe_options_allowed(self, rw_repo):
1140+tmp_dir = Path(tempfile.mkdtemp())
1141+tmp_file = tmp_dir / "pwn"
1142+unsafe_options = [
1143+f"--upload-pack='touch {tmp_file}'",
1144+f"-u 'touch {tmp_file}'",
1145+"--config=protocol.ext.allow=always",
1146+"-c protocol.ext.allow=always",
1147+ ]
1148+for unsafe_option in unsafe_options:
1149+with self.assertRaises(GitCommandError):
1150+Submodule.add(
1151+rw_repo, "new", "new", str(tmp_dir), clone_multi_options=[unsafe_option], allow_unsafe_options=True
1152+ )
1153+1154+@with_rw_repo("HEAD")
1155+def test_submodule_update_unsafe_url(self, rw_repo):
1156+urls = [
1157+"ext::sh -c touch% /tmp/pwn",
1158+"fd::/foo",
1159+ ]
1160+for url in urls:
1161+submodule = Submodule(rw_repo, b"\0" * 20, name="new", path="new", url=url)
1162+with self.assertRaises(UnsafeProtocolError):
1163+submodule.update()
1164+1165+@with_rw_repo("HEAD")
1166+def test_submodule_update_unsafe_url_allowed(self, rw_repo):
1167+urls = [
1168+"ext::sh -c touch% /tmp/pwn",
1169+"fd::/foo",
1170+ ]
1171+for url in urls:
1172+submodule = Submodule(rw_repo, b"\0" * 20, name="new", path="new", url=url)
1173+# The URL will be allowed into the command, but the command will
1174+# fail since we don't have that protocol enabled in the Git config file.
1175+with self.assertRaises(GitCommandError):
1176+submodule.update(allow_unsafe_protocols=True)
1177+1178+@with_rw_repo("HEAD")
1179+def test_submodule_update_unsafe_options(self, rw_repo):
1180+tmp_dir = Path(tempfile.mkdtemp())
1181+tmp_file = tmp_dir / "pwn"
1182+unsafe_options = [
1183+f"--upload-pack='touch {tmp_file}'",
1184+f"-u 'touch {tmp_file}'",
1185+"--config=protocol.ext.allow=always",
1186+"-c protocol.ext.allow=always",
1187+ ]
1188+submodule = Submodule(rw_repo, b"\0" * 20, name="new", path="new", url=str(tmp_dir))
1189+for unsafe_option in unsafe_options:
1190+with self.assertRaises(UnsafeOptionError):
1191+submodule.update(clone_multi_options=[unsafe_option])
1192+1193+@with_rw_repo("HEAD")
1194+def test_submodule_update_unsafe_options_allowed(self, rw_repo):
1195+tmp_dir = Path(tempfile.mkdtemp())
1196+tmp_file = tmp_dir / "pwn"
1197+unsafe_options = [
1198+f"--upload-pack='touch {tmp_file}'",
1199+f"-u 'touch {tmp_file}'",
1200+"--config=protocol.ext.allow=always",
1201+"-c protocol.ext.allow=always",
1202+ ]
1203+submodule = Submodule(rw_repo, b"\0" * 20, name="new", path="new", url=str(tmp_dir))
1204+for unsafe_option in unsafe_options:
1205+with self.assertRaises(GitCommandError):
1206+submodule.update(clone_multi_options=[unsafe_option], allow_unsafe_options=True)