Skip to content

Commit 833a48e

Browse files
committed
Confine submodule paths to their parent repository
1 parent 578b159 commit 833a48e

2 files changed

Lines changed: 47 additions & 15 deletions

File tree

git/objects/submodule/base.py

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from git.util import (
2929
IterableList,
3030
RemoteProgress,
31+
_to_relative_path,
3132
join_path_native,
3233
rmtree,
3334
to_native_path_linux,
@@ -379,23 +380,14 @@ def _to_relative_path(cls, parent_repo: "Repo", path: PathLike) -> PathLike:
379380
:raise ValueError:
380381
If path is not contained in the parent repository's working tree.
381382
"""
382-
path = to_native_path_linux(path)
383+
if parent_repo.working_tree_dir:
384+
path = _to_relative_path(parent_repo.working_tree_dir, path)
385+
else:
386+
path = to_native_path_linux(path)
383387
if path.endswith("/"):
384388
path = path[:-1]
385-
# END handle trailing slash
386-
387-
if osp.isabs(path) and parent_repo.working_tree_dir:
388-
working_tree_linux = to_native_path_linux(parent_repo.working_tree_dir)
389-
if not path.startswith(working_tree_linux):
390-
raise ValueError(
391-
"Submodule checkout path '%s' needs to be within the parents repository at '%s'"
392-
% (working_tree_linux, path)
393-
)
394-
path = path[len(working_tree_linux.rstrip("/")) + 1 :]
395-
if not path:
396-
raise ValueError("Absolute submodule path '%s' didn't yield a valid relative path" % path)
397-
# END verify converted relative path makes sense
398-
# END convert to a relative path
389+
if not path or path == ".":
390+
raise ValueError("Submodule checkout path must not be the repository root")
399391

400392
return path
401393

test/test_submodule.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,46 @@ class Repo:
12561256
msg = '_to_relative_path should be "submodule_path" but was "%s"' % relative_path
12571257
assert relative_path == "submodule_path", msg
12581258

1259+
@with_rw_directory
1260+
def test_to_relative_path_is_confined_to_parent(self, rwdir):
1261+
class Repo:
1262+
working_tree_dir = osp.join(rwdir, "parent")
1263+
1264+
os.makedirs(osp.join(Repo.working_tree_dir, "nested"))
1265+
1266+
assert Submodule._to_relative_path(Repo(), osp.join(Repo.working_tree_dir, "nested")) == "nested"
1267+
assert Submodule._to_relative_path(Repo(), osp.join("nested", "..", "module")) == "module"
1268+
self.assertRaises(ValueError, Submodule._to_relative_path, Repo(), Repo.working_tree_dir)
1269+
self.assertRaises(ValueError, Submodule._to_relative_path, Repo(), osp.join("..", "outside"))
1270+
self.assertRaises(
1271+
ValueError,
1272+
Submodule._to_relative_path,
1273+
Repo(),
1274+
osp.join(Repo.working_tree_dir + "-other", "module"),
1275+
)
1276+
1277+
@skipUnless(sys.platform == "win32", "Specifically for Windows.")
1278+
@with_rw_directory
1279+
def test_to_relative_path_windows_path_kinds(self, rwdir):
1280+
class Repo:
1281+
working_tree_dir = osp.join(rwdir, "parent")
1282+
1283+
inside_path = osp.join(Repo.working_tree_dir, "nested", "module")
1284+
_drive, rooted_inside_path = osp.splitdrive(inside_path)
1285+
1286+
assert Submodule._to_relative_path(Repo(), rooted_inside_path) == "nested/module"
1287+
assert Submodule._to_relative_path(Repo(), rooted_inside_path.replace("\\", "/")) == "nested/module"
1288+
assert Submodule._to_relative_path(Repo(), PathLikeMock(inside_path)) == "nested/module"
1289+
self.assertRaises(
1290+
ValueError,
1291+
Submodule._to_relative_path,
1292+
Repo(),
1293+
f"{osp.splitdrive(Repo.working_tree_dir)[0]}relative",
1294+
)
1295+
self.assertRaises(ValueError, Submodule._to_relative_path, Repo(), R"Z:\outside")
1296+
self.assertRaises(ValueError, Submodule._to_relative_path, Repo(), R"\\server\share\outside")
1297+
self.assertRaises(ValueError, Submodule._to_relative_path, Repo(), R"\\?\C:\outside")
1298+
12591299
@pytest.mark.xfail(
12601300
reason="for some unknown reason the assertion fails, even though it in fact is working in more common setup",
12611301
raises=AssertionError,

0 commit comments

Comments
 (0)