Skip to content

fix(hooks): use portable sed for guard-git -C work_dir detection#1152

Closed
carlos-alm wants to merge 3 commits into
mainfrom
fix/1135-guard-git-bsd-sed
Closed

fix(hooks): use portable sed for guard-git -C work_dir detection#1152
carlos-alm wants to merge 3 commits into
mainfrom
fix/1135-guard-git-bsd-sed

Conversation

@carlos-alm
Copy link
Copy Markdown
Contributor

Summary

  • detect_work_dir() in .claude/hooks/guard-git.sh used a ;t; chained sed expression that GNU sed accepts but BSD sed (macOS default) rejects with undefined label.
  • When the sed errored, work_dir stayed empty and the hook fell back to the ambient cwd's branch — so git -C /other-worktree push from an agent in a worktree like worktree-agent-XXXX was always denied even when the targeted worktree had a valid branch.
  • Split the one-liner into two sed invocations (quoted form first, unquoted fallback). Behavior is identical on GNU sed and now works on BSD sed.

Test plan

  • Reproduce on macOS: printf '{"tool_input":{"command":"git -C /tmp push"}}' | bash .claude/hooks/guard-git.sh — sed error gone.
  • git -C /real-worktree push against a worktree on a valid branch — no deny.
  • Multi--C (last wins): git -C /a -C /b push resolves to /b.
  • Quoted -C "/path with spaces" — quoted regex still matches.
  • No -C, ambient invalid branch — still denied (unchanged behavior).

Closes #1135

The `;t;` chained sed expression in `detect_work_dir` is a GNU-ism: BSD sed
(macOS default) parses it as `t` branching to a label named `;s/...` and
errors out, leaving `work_dir` empty. The hook then falls back to the
ambient cwd's branch and denies legitimate `git -C /other-worktree push`
calls from agents running in worktrees with non-conforming branch names.

Split the one-liner into two sed invocations (quoted form first, then
unquoted as a fallback). Behavior is identical on GNU sed and now works
on BSD sed.

Closes #1135
@claude
Copy link
Copy Markdown

claude Bot commented May 18, 2026

Claude finished @carlos-alm's task —— View job


PR Review Complete

Todo List:

  • Phase 1: Root cause analysis - understand the BSD sed compatibility problem
  • Phase 2: Configuration change detection - check for high-risk changes
  • Phase 3: Test integrity - look for red flags in testing
  • Phase 4: Code quality review - examine the fix implementation
  • Phase 5: Backlog compliance assessment - evaluate against criteria
  • Final: Provide comprehensive rating and recommendation

Root Cause Analysis

Problem Being Solved: The detect_work_dir() function in .claude/hooks/guard-git.sh used a GNU sed-specific ;t; chained expression that BSD sed (macOS default) incorrectly parses as a branch to a label named ;s/..., causing sed to error with "undefined label". This left work_dir empty, making the hook fall back to the ambient cwd's branch and incorrectly deny legitimate git -C /other-worktree push commands from agents in worktrees.

Why This Approach: The solution correctly identifies that the issue is a sed dialect incompatibility, not a logical error. Splitting the complex one-liner into two separate sed invocations (quoted path pattern first, then unquoted fallback) maintains identical behavior on GNU sed while making it work on BSD sed. This preserves the exact same logic flow without changing the hook's security model.

Risk Assessment: ✅ Low Risk — This is a pure compatibility fix that doesn't change the security logic, just makes it work cross-platform.

Backlog Compliance

  • Zero-dep: ✅ — No new dependencies added, uses existing shell/sed tooling
  • Foundation-aligned: ✅ — Hook infrastructure supports P8 (tooling that aids agents); cross-platform compatibility supports P5 (embeddable-first)
  • Problem-fit: 3 — Useful operational fix that prevents hook failures on macOS, but doesn't directly address the core "lost AI" problem
  • Breaking: No — Behavioral change is purely additive (makes it work where it previously failed)
  • Tier: 1 (zero-dep ✅ + foundation-aligned ✅)

Critical Concerns

None. This is a well-executed compatibility fix.

Code Quality Assessment

Strengths:

  • Excellent documentation: Lines 120-122 clearly explain the BSD sed parsing issue and why the fix is needed
  • Proper fallback logic: The if [ -z "$work_dir" ]; then check preserves the original two-pattern behavior
  • Minimal diff: Changes only what's necessary, doesn't refactor unrelated code
  • Security preservation: Maintains exact same work directory detection logic

Technical Analysis:
The original problematic line 124:

work_dir=$(echo "$search_str" | sed -nE 's/.*-C[[:space:]]+"([^"]+)".*/\1/p;t;s/.*-C[[:space:]]+([^[:space:]]+).*/\1/p')

Was correctly split into:

work_dir=$(echo "$search_str" | sed -nE 's/.*-C[[:space:]]+"([^"]+)".*/\1/p')
if [ -z "$work_dir" ]; then
  work_dir=$(echo "$search_str" | sed -nE 's/.*-C[[:space:]]+([^[:space:]]+).*/\1/p')
fi

This preserves the original semantics: try the quoted pattern first, if no match, try the unquoted pattern.

Security Analysis:

  • Hook maintains its security function of preventing cross-session interference
  • No command injection vectors introduced
  • Input sanitization behavior unchanged

Performance: Negligible impact — splits one sed call into potentially two, but only in the -C detection path.

Test Coverage

The PR description mentions manual testing on macOS:

  • ✅ Sed error elimination confirmed
  • ✅ Valid worktree operations no longer denied
  • ✅ Multi--C handling still works
  • ✅ Quoted path handling still works
  • ✅ Invalid branch denial still works

Manual testing approach is appropriate for a hook compatibility fix.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: This is a solid, well-documented cross-platform compatibility fix. It correctly identifies and solves the BSD sed parsing issue without changing security logic or introducing new risks. The approach is conservative and maintains backward compatibility. Only loses one star due to being an operational fix rather than a feature that advances core functionality.

Recommendation: Merge this PR. It's exactly the kind of fix needed to ensure the tooling works consistently across development environments.


@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 18, 2026

Greptile Summary

This PR fixes a BSD sed (macOS) incompatibility in detect_work_dir() inside .claude/hooks/guard-git.sh. The GNU sed ;t; chain in a single sed -nE expression caused t to be misinterpreted as a branch-to-label on BSD sed, silently leaving work_dir empty and causing false denials for valid git -C <worktree> pushes on macOS.

  • Replaces the single sed one-liner (quoted-then-unquoted via ;t;) with two sequential sed calls guarded by [ -z \"$work_dir\" ], which is semantically equivalent and works on both GNU and BSD sed.
  • Adds an inline comment explaining why the one-liner was problematic on BSD sed.

Confidence Score: 5/5

Safe to merge — the change is a targeted portability fix with no logic changes on GNU sed and correct behaviour on BSD sed.

The two-invocation approach is functionally identical to the original on GNU sed (quoted pattern succeeds → skip unquoted, same as before), eliminates the BSD sed parse error that broke macOS, and doesn't touch any other logic paths in the hook. The test plan covers the common cases including multi--C and spaces in paths.

No files require special attention.

Important Files Changed

Filename Overview
.claude/hooks/guard-git.sh Splits one BSD-incompatible sed one-liner into two portable invocations; logic is equivalent and all stated test cases are covered.

Reviews (3): Last reviewed commit: "Merge branch 'main' into fix/1135-guard-..." | Re-trigger Greptile

@carlos-alm
Copy link
Copy Markdown
Contributor Author

Superseded by #1146 (merged), which fixed both the ;t; chained sed (the root cause behind #1135) and the \s regex incompatibility in the same hook in one pass. Issue #1145 (closed by #1146) covered both BSD-sed defects.

Closing this PR — merging it now would actually regress main by replacing the already-portable [[:space:]] patterns with the non-portable \s form.

Will also close #1135 since it shares the root cause already fixed in #1146.

@carlos-alm
Copy link
Copy Markdown
Contributor Author

Superseded by #1146.

@carlos-alm carlos-alm closed this May 18, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators May 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

guard-git.sh: BSD sed incompatibility breaks -C work_dir detection on macOS

1 participant