"""pathguard cells, standard library only. Q149 (2026-11-01): this module imported `pytest` and used it for `pytest.raises` alone. The interpreter `beam/CHECK` resolves has no pytest -- Q128 moved the lane's four other pytest-only files onto `beam_assert` for exactly that reason -- so the import failed and `run_lane_tests.py` reported all eight cells as one `IMPORT-FAIL test_pathguard.py` line: eight cells graded nothing, and the lane gate was red with a message that reads like a missing library rather than a broken one. The fix is the lane's existing shim, not a new idiom: `beam_assert.raises` is the `pytest.raises(X)` equivalent this directory already vendors. Cell bodies are unchanged. """ import os import tempfile from beam_assert import raises 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 raises(PathTraversalError): safe_join(d, "..", "etc", "passwd") def test_absolute_part_rejected(): with tempfile.TemporaryDirectory() as d: with 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 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 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 raises(PathTraversalError): safe_join(f, "x")