Found by the local review pass on #2243 (#1452). It is not live today, and it predates that change in scripts/carry.py.
escapes_repo_root in spec/validate.py matches a drive letter only at the start of a value (^[A-Za-z]:). A drive-shaped component later in the path, such as real/C:x, passes it.
Both scripts/carry.py's relative_root and spec/validate.py's new symlinked_component walk a tree path one component at a time with current /= part. On Windows, joining a drive-relative component throws away everything joined before it, so PureWindowsPath("D:/root") / "C:x" is C:x. The symlink check then reads a path relative to drive C's current directory rather than one under the root. If that path is a symlink, symlinked_component's relative_to(root) raises an uncaught ValueError and the validator crashes rather than reporting an error.
Reaching it needs a Windows host, a : inside a component (NTFS reads it as an alternate data stream), and a symlink at that spot. The one tree spec/files.json declares trips none of these.
Suggested shape
Refuse a drive-letter spelling in any component rather than only at the start, in escapes_repo_root and in relative_root alike, so both tools refuse the value before either walk joins it.
Found by the local review pass on #2243 (#1452). It is not live today, and it predates that change in
scripts/carry.py.escapes_repo_rootinspec/validate.pymatches a drive letter only at the start of a value (^[A-Za-z]:). A drive-shaped component later in the path, such asreal/C:x, passes it.Both
scripts/carry.py'srelative_rootandspec/validate.py's newsymlinked_componentwalk a tree path one component at a time withcurrent /= part. On Windows, joining a drive-relative component throws away everything joined before it, soPureWindowsPath("D:/root") / "C:x"isC:x. The symlink check then reads a path relative to drive C's current directory rather than one under the root. If that path is a symlink,symlinked_component'srelative_to(root)raises an uncaughtValueErrorand the validator crashes rather than reporting an error.Reaching it needs a Windows host, a
:inside a component (NTFS reads it as an alternate data stream), and a symlink at that spot. The one treespec/files.jsondeclares trips none of these.Suggested shape
Refuse a drive-letter spelling in any component rather than only at the start, in
escapes_repo_rootand inrelative_rootalike, so both tools refuse the value before either walk joins it.