Skip to content

Commit 12f7a6a

Browse files
committed
fix: keep redline outputs under output-dir on Windows rooted paths
Path.is_absolute() is False on Windows for a rooted-but-driveless path like '/x/y', yet joining it onto output_dir still replaces the whole prefix, so the escape guard never fired (caught by the new unit test on the windows-latest CI matrix). Guard on drive/root/'..' components as well, and cover '..' traversal in the test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0142X9VTMpdo639kHKQa4PE1
1 parent 48ca443 commit 12f7a6a

2 files changed

Lines changed: 7 additions & 2 deletions

File tree

action/redline_changed.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,10 @@ def revision_count_from_stdout(stdout: Optional[str]) -> Optional[int]:
276276
def redline_output_paths(output_dir: str, source_path: str) -> Tuple[Path, Path]:
277277
"""Mirror the source's relative directory tree under output_dir."""
278278
rel = Path(source_path)
279-
if rel.is_absolute():
280-
# Joining an absolute path onto output_dir would escape it entirely.
279+
# An absolute path joined onto output_dir would replace it entirely, and a
280+
# '..' component would escape it. Note is_absolute() alone is not enough on
281+
# Windows, where a rooted-but-driveless path ('/x/y') still hijacks a join.
282+
if rel.is_absolute() or rel.drive or rel.root or '..' in rel.parts:
281283
try:
282284
rel = rel.relative_to(Path.cwd())
283285
except ValueError:

tests/test_action_script.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ def test_redline_output_paths_absolute_source_stays_under_output_dir(tmp_path, m
118118
outside = '/somewhere/else/entirely/b.docx'
119119
docx, _ = ra.redline_output_paths('out', outside)
120120
assert docx.as_posix() == 'out/b.redline.docx'
121+
traversal = '../outside/c.docx'
122+
docx, _ = ra.redline_output_paths('out', traversal)
123+
assert docx.as_posix() == 'out/c.redline.docx'
121124

122125

123126
def test_build_summary_lists_each_change():

0 commit comments

Comments
 (0)