From b4683a677330d61bca778f701187463c9f2f59f9 Mon Sep 17 00:00:00 2001 From: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com> Date: Sun, 30 Aug 2026 18:04:41 +0000 Subject: [PATCH] v7next F0: hook-token prefix extraction + Windows containment (phase-review round 5) - scripts/x.py-not-real no longer matches by its existing .py prefix: the token regex gained a trailing lookahead - a partial token is prose, not a reference (a sentence period after a path still parses). - Containment uses pathlib parents membership instead of '/'-suffixed string prefixing, portable across Windows separators. --- scripts/v7next_adoption.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/v7next_adoption.py b/scripts/v7next_adoption.py index 2d6dc710c..5b8430420 100644 --- a/scripts/v7next_adoption.py +++ b/scripts/v7next_adoption.py @@ -189,9 +189,11 @@ def validate(rows: list[dict[str, str]], release: bool) -> list[str]: return errors -# Any-extension token, anchored so `not-scripts/x.py` is not misread as a -# scripts/ reference (round 4: lookbehind rejects a preceding path character). -_HOOK_PATH_RE = re.compile(r"(? list[str]: @@ -213,7 +215,9 @@ def _hook_resolution_errors(row: dict[str, str]) -> list[str]: top = p.split("/", 1)[0] candidate = (REPO_ROOT / p).resolve() top_root = (REPO_ROOT / top).resolve() - inside = candidate == top_root or str(candidate).startswith(str(top_root) + "/") + # pathlib containment, not string prefixing: portable across + # separators (round 5: the "/"-suffix check broke on Windows). + inside = candidate == top_root or top_root in candidate.parents if ".." in p.split("/") or not inside: errors.append(f"release: {row['id']} hook path escapes {top}/: {p}") elif not candidate.is_file():