Skip to content

Commit c0ed846

Browse files
codexByron
authored andcommitted
Match Git submodule symlink validation
Replace resolved-path containment with Git-compatible component validation: normalize and confine the checkout path, then reject every existing symlink component before filesystem use. This follows git.git commit e8d0608944 (validate_submodule_path) and t/t7423-submodule-symlinks.sh, including rejection of symlinks that still resolve inside the worktree. Validation: .venv/bin/python -m pytest test/test_submodule.py -q; focused path regressions; pre-commit run --files git/objects/submodule/base.py test/test_submodule.py; mypy git/objects/submodule/base.py; git diff --check.
1 parent 675df36 commit c0ed846

2 files changed

Lines changed: 11 additions & 7 deletions

File tree

git/objects/submodule/base.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,14 @@ def _to_relative_path(cls, parent_repo: "Repo", path: PathLike) -> PathLike:
416416

417417
@property
418418
def abspath(self) -> PathLike:
419-
path = super().abspath
420419
root = self.repo.working_tree_dir
421-
assert root is not None
422-
if _to_relative_path(osp.realpath(root), osp.realpath(path)) == ".":
423-
raise ValueError("Submodule checkout path must not be the repository root")
420+
if root is None:
421+
return super().abspath
422+
path = root
423+
for component in os.fspath(self._to_relative_path(self.repo, self.path)).split("/"):
424+
path = join_path_native(path, component)
425+
if osp.islink(path):
426+
raise ValueError("Submodule checkout path %r contains a symbolic link" % self.path)
424427
return path
425428

426429
@classmethod

test/test_submodule.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,9 +1385,10 @@ def test_update_rejects_checkout_path_outside_parent(self, rwdir):
13851385
submodule.update(init=True)
13861386

13871387
@with_rw_directory
1388-
def test_update_rejects_checkout_path_through_outside_symlink(self, rwdir):
1388+
def test_update_rejects_checkout_path_through_symlink(self, rwdir):
13891389
parent = git.Repo.init(osp.join(rwdir, "parent"))
1390-
os.symlink(osp.join(rwdir, "outside"), osp.join(parent.working_tree_dir, "link"))
1390+
os.mkdir(osp.join(parent.working_tree_dir, "target"))
1391+
os.symlink("target", osp.join(parent.working_tree_dir, "link"))
13911392
submodule = Submodule(
13921393
parent,
13931394
Submodule.NULL_BIN_SHA,
@@ -1397,7 +1398,7 @@ def test_update_rejects_checkout_path_through_outside_symlink(self, rwdir):
13971398
)
13981399

13991400
with mock.patch.object(Submodule, "_clone_repo", side_effect=AssertionError("clone attempted")):
1400-
with pytest.raises(ValueError, match="is not in repository"):
1401+
with pytest.raises(ValueError, match="contains a symbolic link"):
14011402
submodule.update(init=True)
14021403

14031404
@with_rw_directory

0 commit comments

Comments
 (0)