Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify check for symlinks that resolve outside root #4221

Merged
merged 3 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions src/black/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
gen_python_files,
get_gitignore,
get_root_relative_path,
normalize_path_maybe_ignore,
parse_pyproject_toml,
path_is_excluded,
resolves_outside_root_or_cannot_stat,
wrap_stream_for_windows,
)
from black.handle_ipynb_magics import (
Expand Down Expand Up @@ -763,12 +763,9 @@ def get_sources(
)
continue

normalized_path: Optional[str] = normalize_path_maybe_ignore(
path, root, report
)
if normalized_path is None:
if resolves_outside_root_or_cannot_stat(path, root, report):
if verbose:
out(f'Skipping invalid source: "{normalized_path}"', fg="red")
out(f'Skipping invalid source: "{path}"', fg="red")
continue

if is_stdin:
Expand All @@ -780,7 +777,7 @@ def get_sources(
continue

if verbose:
out(f'Found input source: "{normalized_path}"', fg="blue")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use the value of normalized_path, we do sources.add(path), so no point logging it

out(f'Found input source: "{path}"', fg="blue")
sources.add(path)
elif path.is_dir():
path = root / (path.resolve().relative_to(root))
Expand Down
25 changes: 11 additions & 14 deletions src/black/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,26 +254,24 @@ def get_gitignore(root: Path) -> PathSpec:
raise


def normalize_path_maybe_ignore(
def resolves_outside_root_or_cannot_stat(
path: Path,
root: Path,
report: Optional[Report] = None,
) -> Optional[str]:
"""Normalize `path`. May return `None` if `path` was ignored.

`report` is where "path ignored" output goes.
) -> bool:
"""
Returns whether the path is a symbolic link that points outside the
root directory. Also returns True if we failed to resolve the path.
"""
try:
abspath = path if path.is_absolute() else Path.cwd() / path
normalized_path = abspath.resolve()
root_relative_path = get_root_relative_path(normalized_path, root, report)

if sys.version_info < (3, 8, 6):
path = path.absolute() # https://bugs.python.org/issue33660
resolved_path = path.resolve()
return get_root_relative_path(resolved_path, root, report) is None
except OSError as e:
if report:
report.path_ignored(path, f"cannot be read because {e}")
return None

return root_relative_path
return True


def get_root_relative_path(
Expand Down Expand Up @@ -369,8 +367,7 @@ def gen_python_files(
report.path_ignored(child, "matches the --force-exclude regular expression")
continue

normalized_path = normalize_path_maybe_ignore(child, root, report)
if normalized_path is None:
if resolves_outside_root_or_cannot_stat(child, root, report):
continue

if child.is_dir():
Expand Down
11 changes: 7 additions & 4 deletions tests/test_black.py
Original file line number Diff line number Diff line change
Expand Up @@ -1760,12 +1760,15 @@ def test_bpo_33660_workaround(self) -> None:
return

# https://bugs.python.org/issue33660
# Can be removed when we drop support for Python 3.8.5
root = Path("/")
with change_directory(root):
path = Path("workspace") / "project"
report = black.Report(verbose=True)
normalized_path = black.normalize_path_maybe_ignore(path, root, report)
self.assertEqual(normalized_path, "workspace/project")
resolves_outside = black.resolves_outside_root_or_cannot_stat(
path, root, report
)
self.assertIs(resolves_outside, False)

def test_normalize_path_ignore_windows_junctions_outside_of_root(self) -> None:
if system() != "Windows":
Expand All @@ -1778,13 +1781,13 @@ def test_normalize_path_ignore_windows_junctions_outside_of_root(self) -> None:
os.system(f"mklink /J {junction_dir} {junction_target_outside_of_root}")

report = black.Report(verbose=True)
normalized_path = black.normalize_path_maybe_ignore(
resolves_outside = black.resolves_outside_root_or_cannot_stat(
junction_dir, root, report
)
# Manually delete for Python < 3.8
os.system(f"rmdir {junction_dir}")

self.assertEqual(normalized_path, None)
self.assertIs(resolves_outside, True)

def test_newline_comment_interaction(self) -> None:
source = "class A:\\\r\n# type: ignore\n pass\n"
Expand Down
Loading