fix(hooks): guard-git.sh sed patterns work on macOS BSD sed#1146
Conversation
`\s` and the `s///;t;s///` flow-control chain are GNU sed extensions that BSD sed (macOS default) does not support. When a command like `cd /path/to/wt && git push` was issued from a different cwd, the cd-path extraction silently returned an empty string, the hook fell back to the calling shell's branch, and produced false "Branch does not match required pattern" denials. Changes: - Replace `\s` with `[[:space:]]` in all sed patterns (lines 36, 37, 124). - Split the `s/quoted/.../p;t;s/unquoted/.../p` chain on the `-C` extraction into two separate `sed -nE` invocations — BSD sed parses the chained `s///` after `t` as a label and errors with "undefined label". - Update the matching `grep -qE` cd/-C guards to `[[:space:]]` for consistency. Verified end-to-end on macOS with all four code paths the hook protects (cd && push, -C push, -C with quoted path, multi -C, cd + -C precedence). Closes #1145
|
Claude finished @carlos-alm's task —— View job Code Review CompleteReview Tasks
Root Cause AnalysisProblem Being Solved: BSD sed (macOS default) doesn't support GNU sed extensions Why This Approach: The solution correctly addresses the compatibility issue by:
Risk Assessment: Very low risk - this is a pure compatibility fix that makes the existing logic work correctly on both GNU and BSD sed without changing behavior. Backlog Compliance
Code Quality AssessmentStrengths:
Technical Review:
Security: ✅ No security implications - maintains same input validation and escaping Minor Suggestions
Root Cause AnalysisProblem Being Solved: Legitimate BSD sed compatibility issue blocking macOS users Backlog Compliance
Final Recommendation
Minor deduction: While excellently executed, this is infrastructure maintenance rather than feature development, hence 4/5 rather than 5/5. |
Greptile SummaryThis PR fixes BSD sed compatibility issues in
Confidence Score: 5/5Safe to merge — the changes are narrowly scoped POSIX compatibility fixes with no logic alterations. Every modified line is a direct replacement of a BSD-incompatible construct ( No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[git/gh command received] --> B{grep: contains git/gh?}
B -- No --> Z[exit 0 allow]
B -- Yes --> C[NCOMMAND: strip -C paths\nsed -E two-pass BSD-safe]
C --> D{Dangerous command?\nadd/reset/checkout/clean/stash}
D -- Yes --> DENY[deny with reason]
D -- No --> E{git push or gh pr create?}
E -- Yes --> F[detect_work_dir\ntarget=push]
F --> G{grep: -C flag present?\ngit+space+-C BSD-safe}
G -- Yes --> H[sed: extract quoted path\nfirst invocation]
H --> I{work_dir empty?}
I -- No --> K[use quoted path]
I -- Yes --> J[sed: extract unquoted path\nsecond invocation]
J --> K
G -- No --> L{grep: cd prefix?\nBSD-safe pattern}
L -- Yes --> M[sed: extract cd path\nBSD-safe pattern]
M --> K
K --> N[validate_branch_name\ngit rev-parse HEAD]
N --> O{branch matches pattern?}
O -- Yes --> Z
O -- No --> DENY
E -- No --> P{git commit?}
P -- Yes --> Q[detect_work_dir commit\ncheck edit log]
Q --> R{unexpected staged files?}
R -- Yes --> DENY
R -- No --> Z
Reviews (4): Last reviewed commit: "Merge branch 'main' into fix/1145-guard-..." | Re-trigger Greptile |
Summary
\sands///;t;s///flow-control are GNU sed extensions that BSD sed (macOS default) does not support. The pre-fix patterns silently produced empty output, causing the hook to fall back to the calling shell's cwd and emit false "Branch does not match required pattern" denials when pushing to another worktree (e.g.cd /path/to/wt && git push).\swith[[:space:]]in all sed patterns (lines 36, 37, 124) and updated the matchinggrep -qEcd/-C guards for consistency.s/quoted/.../p;t;s/unquoted/.../pchain on the-Cextraction into two separatesed -nEinvocations — BSD sed parses the chaineds///aftertas a label and errors withundefined label.Reproduction (pre-fix, macOS)
Test plan
sed: undefined label; empty cd-extract).cd <good-wt> && git pushfrom<bad-wt>→ ALLOWcd <bad-wt> && git pushfrom<good-wt>→ DENY (was silently ALLOWed pre-fix)git -C <good-wt> push→ ALLOWgit -C <bad-wt> push→ DENYgit -C "<bad-wt>" push(quoted path) → DENYgit -C <good-wt> -C <bad-wt> push(multi-C bypass) → DENY (last-Cwins)cd <good-wt> && git -C <bad-wt> push→ DENY (-Coverrides cd)[], new returns the actual path.Closes #1145