Generated hook shim exits 0 when the lefthook binary is missing, silently skipping configured hooks (fail-open)
Description
The generated hook shim fails open: when the lefthook binary cannot be found, the shim prints Can't find lefthook in PATH and exits 0, so git proceeds and the repo's configured hooks are silently skipped. For a pre-push gate this means a broken environment disables the gate with no failure signal.
Generated with lefthook install v1.13.6 (template internal/templates/hook.tmpl, unmodified output).
Reproduction
- Create a repo with a
lefthook.ymldefining anypre-pushcommand. - Remove the lefthook binary from
PATH(simulate a broken/uninstalled environment). - Run the generated
pre-pushhook the way git does:
env -i PATH=/usr/bin HOME="$HOME" /path/to/generated/pre-push origin fake
echo $?
# Can't find lefthook in PATH
# 0 <-- hook "passed", push proceeds, hooks never ranExpected behavior
When a lefthook config exists in the repository but no binary can be found, the hook should abort the git operation (exit 1) rather than silently succeed — the same fail-closed contract that assert_lefthook_installed: true renders into the hook.
Repos without a lefthook config should keep the current silent no-op, since a shared core.hooksPath can serve many repos.
Why the existing knob doesn't cover this
assert_lefthook_installed is opt-in and baked in at install time: enabling it later still leaves the previously generated hooks fail-open until every repo re-runs lefthook install, and repos that adopt a lefthook.yml after their hooks were generated are permanently fail-open. A config-existence check in the shim's not-found branch covers both at runtime.
Suggested fix (verified locally on 1.13.6 output)
In hook.tmpl's not-found else branch:
else
echo "Can't find lefthook in PATH"
dir="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
# Fail closed when this repo actually uses lefthook; stay a no-op otherwise.
if test -f "$dir/lefthook.yml" || test -f "$dir/.lefthook.yml" || \
test -f "$dir/lefthook.yaml" || test -f "$dir/.config/lefthook.yml"
then
echo "ERROR: Operation is aborted due to lefthook settings."
echo "Make sure lefthook is available in your environment and re-try."
echo "To skip these checks use --no-verify git argument or set LEFTHOOK=0 env variable."
exit 1
fi
fiVerified paths after patching a local shim: not-found + config present → exit 1 (git aborts); not-found + no config → exit 0 (no-op preserved); LEFTHOOK=0 escape hatch still honored; binary present → normal execution.
Related in spirit: #1471 (stage_fixed failures also report success).
Source: evilmartians/lefthook