Files
troupe-standup/wizard-work/beam/test_pathguard.py
T

67 lines
2.0 KiB
Python

import os
import tempfile
import pytest
from pathguard import safe_join, PathTraversalError
def test_basic_join():
with tempfile.TemporaryDirectory() as d:
out = safe_join(d, "a", "b.txt")
assert out == os.path.join(os.path.realpath(d), "a", "b.txt")
def test_dotdot_escape_rejected():
with tempfile.TemporaryDirectory() as d:
with pytest.raises(PathTraversalError):
safe_join(d, "..", "etc", "passwd")
def test_absolute_part_rejected():
with tempfile.TemporaryDirectory() as d:
with pytest.raises(PathTraversalError):
safe_join(d, "/etc/passwd")
def test_symlink_escape_rejected():
with tempfile.TemporaryDirectory() as d:
base = os.path.join(d, "base")
os.makedirs(base)
target = os.path.join(d, "secret.txt")
with open(target, "w") as f:
f.write("secret")
link = os.path.join(base, "link")
os.symlink(target, link)
# reading through link to outside must be rejected when resolved?
# safe_join resolves; link itself is inside base by name but points outside.
# Our function resolves symlinks and checks containment -> should reject.
with pytest.raises(PathTraversalError):
safe_join(base, "link")
def test_valid_nested():
with tempfile.TemporaryDirectory() as d:
sub = os.path.join(d, "sub")
os.makedirs(sub)
out = safe_join(d, "sub", "file.txt")
assert out.startswith(os.path.realpath(d) + os.sep)
def test_empty_parts_ignored():
with tempfile.TemporaryDirectory() as d:
out = safe_join(d, "", None, "x")
assert out.endswith("x")
def test_nul_rejected():
with tempfile.TemporaryDirectory() as d:
with pytest.raises(PathTraversalError):
safe_join(d, "a\x00b")
def test_base_not_dir():
with tempfile.TemporaryDirectory() as d:
f = os.path.join(d, "f")
open(f, "w").close()
with pytest.raises(PathTraversalError):
safe_join(f, "x")