fix: keep path identity when validators accept macOS path aliases - #240
Open
zengchang233 wants to merge 1 commit into
Open
zengchang233 wants to merge 1 commit into
zengchang233 wants to merge 1 commit into
Conversation
aeaec5c made the validators tolerate /var vs /private/var on macOS, but two of those changes widen or break the checks: - The Bash validator strips a leading /private from the active loop dir and then matches it as a substring of the command. A command writing round-1-todos.md under another directory that merely ends with the loop path, such as /tmp/other/tmp/p/.humanize/rlcr/s, passes; on Linux, where /private/tmp and /tmp can be unrelated, a loop under /private/tmp/p also authorizes /tmp/p. Accept the other spelling only when canonicalize_path resolves both to the same existing directory, and require the path to start at a word boundary. Otherwise the exact loop path is required, as before. - The Write and Edit validators fall back to _normalize_path only when canonicalize_path fails, but it returns the raw path with status 0 when neither realpath nor python3 is available, so <loop>/./goal-tracker.md is rejected. Normalize the canonicalizer's result as well. Regression tests cover both spellings of the loop path, suffix and nested directories, a platform without the alias (realpath that does not resolve /private) and the tracker paths with realpath and python3 unavailable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
aeaec5c (from #141) made the loop validators accept both
/var/...and/private/var/...spellings of the active loop directory on macOS. Two of those changes go further than intended: one lets the Bash validator accept paths outside the loop, and the other makes the Write/Edit validators reject a valid goal-tracker path. This PR keeps the macOS tolerance and fixes both problems.I found these while applying the aeaec5c hook fixes to a local 1.16.0 install for the macOS sed stall described in #238.
Problems
1. The Bash validator's todos check matches a substring
hooks/loop-bash-validator.shstrips a leading/privatefrom the active loop directory, then matches the rest anywhere in the command. So a command that writesround-1-todos.mdis accepted in two cases where it should not be:/tmp/p/.humanize/rlcr/s, writing to/tmp/other/tmp/p/.humanize/rlcr/s/round-1-todos.mdpasses./tmpon Linux. There,/private/tmpand/tmpcan be unrelated directories. A loop under/private/tmp/palso authorizes/tmp/p.2. The Write/Edit validators' goal-tracker check has no lexical fallback
hooks/loop-write-validator.shandhooks/loop-edit-validator.shuse_normalize_pathonly whencanonicalize_pathfails. But when neitherrealpathnorpython3is available,canonicalize_pathreturns the raw path with status 0. The lexical fallback therefore never runs, and<loop>/./goal-tracker.mdor<loop>//goal-tracker.mdis rejected.Fix
${ACTIVE_LOOP_DIR#/private}and/private${ACTIVE_LOOP_DIR#/private}withcanonicalize_path. Accept(/private)?<path>only when both resolve to the same existing directory; otherwise require the exact active loop path, as before aeaec5c. The match must also start at a path boundary, so a directory that merely ends with the loop path is not accepted._normalize_path.Tests
New cases in
tests/test-allowlist-validators.sh:/private) spelling of the loop dir<loop>/./goal-tracker.mdwithrealpathandpython3unavailable<loop>//goal-tracker.mdwithrealpathandpython3unavailable/privatespelling where it is not an alias (realpathstub that leaves paths unchanged)Results:
devhooks: 49 pass, 5 fail (41–45).Verification
/bin/bash3.2 (run-all-tests.shneeds bash 4), ondevand on this branch, from the same location. The same files fail on both, with identical FAIL lines. There are no new failures.tests/test-cancel-signal-file.shfails 50 of 68 cases on bothdevand this branch when the checkout lives under/private/tmp. It passes 68/68 from a checkout under$HOME. I have not looked into it here.codex review --base dev), which reported no findings.Related: #238
🤖 Generated with Claude Code