Keep a local project scan inside its intended directory tree

Direct answer

A project scanner should choose its traversal boundary before it begins reading entries. Path.is_symlink() lets this example skip a directory entry that points outside the temporary root. The normal case reports only inside.py; the symbolic-link branch is either skipped or, on platforms where links cannot be created, reported as unavailable rather than silently followed.

A symlink is the relevant edge case because a lexical path under project/ can resolve to another tree. Filtering the entry before recursion is simpler to review than discovering the escape after files have already been visited.

This snippet is intentionally shallow: it does not recursively walk directories, resolve hard links, or establish a sandbox against hostile filesystem races. For a broader scanner, maintain a no-follow rule at every descent and record skipped paths in a non-sensitive form. The example only demonstrates the policy for one directory entry.

Complete example

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    root = Path(directory) / "project"
    outside = Path(directory) / "outside"
    root.mkdir()
    outside.mkdir()
    (root / "inside.py").write_text("x", encoding="utf-8")
    (outside / "secret.py").write_text("x", encoding="utf-8")
    link = root / "linked"
    try:
        link.symlink_to(outside, target_is_directory=True)
    except OSError:
        skipped = "symlink-unavailable"
    else:
        visible = [item.name for item in root.iterdir() if not item.is_symlink()]
        assert visible == ["inside.py"]
        skipped = "symlink-skipped"
    print(f"files=1 {skipped}")

Expected stdout:

files=1 symlink-skipped

Sources

- pathlib documentation

Prepared with AI assistance. The example uses synthetic data; its stated limits apply.

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic