Skip to content

fix(lefthook): keep the check-affected pre-push job parseable on Windows - #11360

Merged
kyle-sexton merged 1 commit into
mainfrom
fix/lefthook-check-affected-windows-quotes
Oct 30, 2026
Merged

kyle-sexton merged 1 commit into
mainfrom
fix/lefthook-check-affected-windows-quotes

Conversation

@kyle-sexton

Copy link
Copy Markdown
Member

Summary

Fixes #11356. On Windows, the check-affected pre-push job exited 2 before running any check and blocked every push from this repo.

Cause

Lefthook 2.2.2 on Windows runs a multi-line run: body as sh.exe -c "<body>" and does not escape the double quotes inside the body. Windows argument parsing ends the -c string at the first inner quote, so sh reported -c: line 2: unexpected EOF while looking for matching ')'.

Fix

The job body now contains no double quotes: single quotes for the echo text and the trap, and unquoted $mb (a commit SHA) and $tmp (a mktemp -d path). Neither can contain spaces. A comment on the job records why. The merge-base rule is unchanged: check code still comes from the merge-base, never from the pushed branch.

Verification

  • On Windows: lefthook run pre-push --job check-affected --force passed (exit 0). Before the fix it failed with the parse error.
  • This branch's own push ran the fixed job through the real pre-push hook: check-affected passed in 26 s.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UJUn7KoThXoYQoxfvdCVi7

On Windows, lefthook passes a multi-line run body to sh -c wrapped in
double quotes without escaping the ones inside it, so sh got a cut-off
script, exited 2, and blocked every push. The body now uses no double
quotes; the merge-base SHA and mktemp path hold no spaces.

Closes #11356

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJUn7KoThXoYQoxfvdCVi7
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 30, 2026 21:37
@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 30, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T21:38:48.943863Z 7882ed2 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7882ed2005

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lefthook.yml
Comment on lines +28 to +29
git archive $mb -- .claude/hooks/check-affected-pre-push.sh lib/hook-utils.sh 2>/dev/null | tar -x -C $tmp 2>/dev/null
[ -f $tmp/.claude/hooks/check-affected-pre-push.sh ] || exit 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve temporary paths containing spaces

When TMPDIR contains spaces, these unquoted $tmp expansions silently skip the pre-push checks. mktemp --help explicitly says it uses $TMPDIR by default; it does not guarantee a space-free path. In the check-affected job, word splitting makes tar -C receive only part of the path, and the subsequent file test fails and exits 0. Reproducing with a space-containing TMPDIR and an archived check that exits 1 blocks correctly before this commit but passes without executing the check afterward. Preserve the temporary path as a single argument while addressing the Windows quoting issue.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

claude-security-review reviewed 7882ed2005bc1a4734589365ceb1d87c66f3e104: 0 finding(s), 0 as inline comments.

No security findings.

The only changed file is lefthook.yml, the check-affected pre-push job. The change removes double quotes from the run: body so lefthook on Windows doesn't cut off the sh -c string.

I checked it against what the job gates. It runs check code taken from the merge-base (git archive $mb), not from the pushed branch, so a pushed branch can't change what the hook executes. The diff leaves that unchanged.

  • $mb unquoted: git merge-base outputs a commit SHA, so word-splitting can't change it. The if ! mb=... guard is the same as before.
  • $tmp unquoted: this is the only loosened spot. The new comment says mktemp -d paths hold no spaces. That assumes TMPDIR has none, and a Windows profile path such as C:\Users\Jane Doe\... could. A split trap 'rm -rf $tmp' would then run rm -rf on partial paths. The TMPDIR value belongs to the developer's own environment, not to a pull request, issue or comment author. Nothing untrusted reaches it, and none of the three impacts applies (leak, compromise or charge). It is a local robustness edge, so I'm not reporting it as a finding.
  • Trust controls and plugin manifests: the diff changes no trusted actor, token scope, kill switch, merge hold or plugin manifest. The PR context was read as data and contained no embedded directives.

critical-findings: 0

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-review: 2 inline finding(s) on 7882ed2005bc1a4734589365ceb1d87c66f3e104; the summary is in this lane's pull request comment.

claude-lane: claude-review

Comment thread lefthook.yml
if ! mb=$(git merge-base HEAD refs/remotes/origin/main 2>/dev/null); then
echo 'check-affected pre-push: skipped, no origin/main merge-base to take the check from; CI checks it.' >&2
exit 0
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new comment says "mktemp paths hold no spaces", but mktemp -d builds its path from $TMPDIR, which the user controls. If TMPDIR contains a space, say /Users/a b/tmp, then rm -rf $tmp splits into two arguments and deletes /Users/a plus a second path. The unquoted $tmp on lines 26-28 breaks the same way, but those only fail the job. This rm -rf deletes the wrong directory.

The risk is small, but the guard needs no double quotes. After line 24, add case $tmp in *' '*) rm -rf -- "..." ... is not possible without quotes, so use case $tmp in *[[:space:]]*) exit 0;; esac before the trap. That skips the job instead of deleting the wrong path, which fits the job's existing 'anything else passes' rule. The comment should also say that TMPDIR is assumed to have no spaces.

claude-lane: claude-review

Comment thread lefthook.yml
@@ -15,17 +15,19 @@ pre-push:
# commit too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue #11356 asks to "Keep the run: body free of double quotes", and nothing in the repository fails if one comes back. .claude/hooks/check-affected-pre-push.test.sh covers only the hook script, not this YAML body. A later edit that re-quotes "$mb" or "$tmp" would pass CI, pass a Linux or macOS push, and re-break every Windows push. The only guard is the comment.

Add a small check that parses lefthook.yml and asserts that no run: value of a job containing a newline contains ". This could be a case in an existing lefthook or hook test, such as lib/git-hooks/install.test.mjs.

claude-lane: claude-review

@github-actions

Copy link
Copy Markdown
Contributor

claude-review reviewed 7882ed2005bc1a4734589365ceb1d87c66f3e104: 2 finding(s), 2 as inline comments.

The fix is correct for the reported failure. The run: body has no double quotes left, and the merge-base rule is unchanged: check code is still extracted with git archive "$mb", never taken from the pushed branch. trap 'rm -rf $tmp' EXIT is single-quoted, so $tmp expands when the trap fires. I read the diff and checked for existing tests. I ran nothing, so the author's Windows results (exit 0, 26 s through the real pre-push hook) are author-claimed and unverified by me.

Two findings, both advisory:

  1. rm -rf $tmp splits on whitespace if TMPDIR contains a space, and that is a destructive path (inline comment on line 25).
  2. No test fails if a double quote returns to the run: body, so issue fix(lefthook): check-affected pre-push job fails to parse on Windows and blocks every push #11356's criterion "Keep the run: body free of double quotes" is met but unguarded (inline comment on line 15).

Closing issue #11356 was read. Its other criterion, to keep taking check code from the merge-base, is met, and .claude/hooks/check-affected-pre-push.test.sh already covers it.

No security, cost or manifest items. The change touches no plugin.json or marketplace.json, and it spends nothing billable.

@github-actions

Copy link
Copy Markdown
Contributor

PR body contract — issue linkage

This PR body does not yet satisfy the issue-linkage contract:

  • Missing a "## Related" section. List related PRs, ADRs, or decision-log entries this PR does not close.

Edit the body and this comment updates itself on the next run.

@github-actions github-actions Bot added the needs-issue-linkage Pull request body has no issue linkage line; set by the PR-contract check, advisory. label Oct 30, 2026
Merged via the queue into main with commit 3d19b7e Oct 30, 2026
65 of 77 checks passed
@kyle-sexton
kyle-sexton deleted the fix/lefthook-check-affected-windows-quotes branch October 30, 2026 21:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-issue-linkage Pull request body has no issue linkage line; set by the PR-contract check, advisory.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(lefthook): check-affected pre-push job fails to parse on Windows and blocks every push

1 participant