Files
troupe-standup/wizard-work/beam/test_pathguard.py
T
ledger 12a8558202 volt: q149 -- beam pathguard cells off pytest, gate green at 645 cells
The beam lane's gate was red from the commit that added
wizard-work/beam/test_pathguard.py: it imported pytest for
pytest.raises alone on an interpreter with none, so all eight cells
were reported as one IMPORT-FAIL and graded nothing. The lane already
vendored beam_assert.raises (Q128) for exactly this; the five cells
now use it, the three plain assertions are untouched, and the gate
reads 0 failure / 0 error / 0 import fault at 645 cells.

Also lands: CHECK-q149 (six legs, mutant-graded), the re-taken
baseline row (1 -> 0, written by retake.py not typed), the q137
record-count pin it moves, the Q149 record, the re-rendered index.

Evidence: /root/.hermes/wizard-outputs/volt/q149-beam-gate/
2026-11-01 14:58:07 +00:00

81 lines
2.7 KiB
Python

"""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")