Skip to content

Refuse a Windows Drive Component Anywhere in a Tree Path - #2247

Merged
ptr727 merged 2 commits into
developfrom
feature/auto-2244
Oct 1, 2026
Merged

ptr727 merged 2 commits into
developfrom
feature/auto-2244

Conversation

@ptr727

@ptr727 ptr727 commented Oct 1, 2026

Copy link
Copy Markdown
Owner

escapes_repo_root in spec/validate.py matched a Windows drive only at the start of a value, and relative_root in scripts/carry.py matched none. Both tools walk a tree path one component at a time with current /= part, and on Windows joining a component that carries a drive, such as C:x, discards everything joined before it. A value such as real/C:x passed both.

  • escapes_repo_root now refuses a component whenever PureWindowsPath(part).drive is non-empty. That is wider than a letter, since Windows reads any character followed by a colon as a drive (1:x, _:x).
  • relative_root refuses a component whenever PureWindowsPath(part).anchor is non-empty, which also covers a leading backslash. That spelling resets the walk to the drive root in the same way, and escapes_repo_root already refuses it.
  • Each suite has a test refusing these values. Both tests fail when the fix is reverted.

The local review pass also found that relative_root still accepts a backslash in the middle of a component. That gap predates this change and is filed as #2246.

Closes on promotion: #2244

🤖 Generated with Claude Code

ptr727 and others added 2 commits October 1, 2026 03:36
escapes_repo_root in spec/validate.py matched a drive letter only at the
start of a value, and relative_root in scripts/carry.py matched none, so a
value such as real/C:x passed both. On Windows, joining that component
discards everything joined before it, which sends either tool's
component walk outside the root. Both now refuse a drive-letter
spelling in any component before the walk runs, with a test in each
suite that fails with the fix reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows reads any character followed by a colon as a drive, not only a
letter, so real/1:x still discarded the root in both walks. carry.py
also accepted a component starting with a backslash, which resets the
walk to the drive root. Both now ask PureWindowsPath for the drive (and
in carry.py the root too) rather than matching a regex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 10:48
@coderabbitai

coderabbitai Bot commented Oct 1, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 0e1493dd-f0d5-4266-86ff-f221d1638010

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (develop@fbaa528). Learn more about missing BASE report.

Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #2247   +/-   ##
==========================================
  Coverage           ?   56.69%           
==========================================
  Files              ?       16           
  Lines              ?     7495           
  Branches           ?        0           
==========================================
  Hits               ?     4249           
  Misses             ?     3246           
  Partials           ?        0           
Flag Coverage Δ
python-3.13 56.69% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The change tightens security-adjacent path validation across two fleet tools and the shared spec, so final human review is warranted despite the change being small and well-tested.

Review effort: Balanced
Findings: None

What changed in this PR

This PR hardens path validation in two fleet tools so a Windows drive-shaped component is refused anywhere in a declared tree path, not only at the start. On Windows, joining a drive-relative component such as C:x onto a path discards everything joined before it, so a value like real/C:x could previously slip past validation and, in spec/validate.py, trigger an uncaught ValueError crash in the downstream symlink walk. The change closes that gap in both the spec validator and the carrier, keeping their refusal behavior aligned.

Changes:

  • escapes_repo_root in spec/validate.py now refuses a component whenever PureWindowsPath(part).drive is non-empty (any character followed by a colon), replacing the start-only ^[A-Za-z]: regex.
  • relative_root in scripts/carry.py refuses a component whenever PureWindowsPath(part).anchor is non-empty, covering both a drive and a leading-backslash root, before the path is joined or walked.
  • Added tests in both suites asserting these values are refused; both fail if the fix is reverted.
File Description
spec/​validate.py Refuse a drive-shaped component in any position of a tree path and reuse the parsed parts, preventing a later crash.
scripts/​carry.py Reject a Windows drive or root in any component before joining/walking the path.
tests/​test_spec_validate.py Extend the drive-letter refusal test with mid-path and digit-colon components.
tests/​test_carry.py Add a test covering drive, root, and backslash components refused by relative_root.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ptr727
ptr727 merged commit 1b6e590 into develop Oct 1, 2026
11 checks passed
@ptr727
ptr727 deleted the feature/auto-2244 branch October 1, 2026 10:54
ptr727 added a commit that referenced this pull request Oct 1, 2026
## Summary

Promotes develop to main, carrying the pull requests below, each already
reviewed and merged into develop.

- [#2203](#2203): Strip
every heredoc body a line opens in the wait-loop rule.
- [#2216](#2216): Point
the charset-unknown message at where a tier is classified.
- [#2218](#2218): Name the
leftover old tree when the Bash loader cannot remove it.
- [#2227](#2227): End the
guard's stdin redirect scan at a trailing comment.
- [#2230](#2230): Tell
apart the causes a labels payload is refused for.
- [#2232](#2232): Correct
the task names and pointers in the Python tasks snippet header.
- [#2234](#2234): Drop the
stale private-repository note from PhotoCleaner's registry entry.
- [#2237](#2237): State
the bootstrap's archive live channel in two skills.
- [#2239](#2239): Stop the
promotion count on a failed fetch in backlog-burndown.
- [#2241](#2241): Render
the include walk once per `build_dist.py --check` run.
- [#2243](#2243): Have the
tree check call `escapes_repo_root` and refuse a symlinked component.
- [#2247](#2247): Refuse a
Windows drive component anywhere in a tree path.
- [#2222](#2222): Tick the
adopted repos in the merge-bot and gate rollout stages.
- [#2121](#2121): Refuse a
dangling remote-tracking target in `local_review`.
- [#2249](#2249): Ignore a
quoted separator when the guard finds a loop's `done`.

Closes #2112
Closes #2171
Closes #1790
Closes #2152
Closes #1372
Closes #2149
Closes #1082
Closes #1772
Closes #1310
Closes #1379
Closes #1452
Closes #2244
Closes #2168
Closes #2106
Closes #2207

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants