Skip to content

Commit a785364

Browse files
committed
Review comments
1 parent 942ebf5 commit a785364

3 files changed

Lines changed: 23 additions & 6 deletions

File tree

dfetch/vcs/archive.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,17 +387,24 @@ def check_zip_members(zf: zipfile.ZipFile) -> list[zipfile.ZipInfo]:
387387

388388
@staticmethod
389389
def _is_unsafe_symlink_target(target: str) -> bool:
390-
r"""Return *True* when *target* is an absolute symlink destination.
390+
r"""Return *True* when *target* is an unsafe symlink destination.
391391
392392
Absolute targets (POSIX ``/`` or Windows drive/UNC anchors) are
393-
always unsafe regardless of context. Relative targets that contain
394-
``..`` components are NOT rejected here; they are validated after
395-
extraction by :meth:`_check_symlinks_in_dest` using the manifest
396-
root as the safety boundary.
393+
always unsafe. Relative targets containing ``..`` components are
394+
also rejected: during :meth:`tarfile.TarFile.extractall` an
395+
already-extracted symlink can be followed when writing a later
396+
member, so a ``..``-based target can escape *dest_dir* before
397+
:meth:`_check_symlinks_in_dest` runs. That method remains as a
398+
secondary check for any case not caught here.
397399
"""
398400
posix = pathlib.PurePosixPath(target)
399401
win = pathlib.PureWindowsPath(target)
400-
return posix.is_absolute() or bool(win.anchor)
402+
return (
403+
posix.is_absolute()
404+
or bool(win.anchor)
405+
or ".." in posix.parts
406+
or ".." in win.parts
407+
)
401408

402409
@staticmethod
403410
def _check_symlinks_in_dest(dest_dir: str) -> None:

features/fetch-archive.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,4 @@ Feature: Fetching dependencies from an archive (tar/zip)
254254
link.mk
255255
dfetch.yaml
256256
"""
257+
And 'MyProject/SomeProject/sub/dir/link.mk' is a symlink pointing to '../../other/target.mk'

features/steps/generic_steps.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,15 @@ def step_impl(_, name):
363363
assert os.path.exists(name), f"Expected {name} to exist, but it didn't!"
364364

365365

366+
@then("'{path}' is a symlink pointing to '{target}'")
367+
def step_impl(_, path, target):
368+
assert os.path.islink(
369+
path
370+
), f"Expected {path!r} to be a symbolic link, but it is not"
371+
actual = os.readlink(path)
372+
assert actual == target, f"Expected {path!r} to point to {target!r}, got {actual!r}"
373+
374+
366375
def multisub(patterns: List[Tuple[Pattern[str], str]], text: str) -> str:
367376
"""Apply a list of tuples that each contain a regex + replace string."""
368377
for pattern, replace in patterns:

0 commit comments

Comments
 (0)