Skip to content

gh-write-guard requirement 4 does not cover an inline hooks-path override #1127

Description

@ptr727

The gap

Requirement 4 of host-setup/agent-safety/README.md denies explicit-bypass flags unconditionally, naming --admin on a merge and --no-verify on a commit or push. --no-verify is the flag that skips a committed git hook, so the requirement reads as covering that class.

It does not. Git also lets a single invocation relocate the hooks path through an inline -c configuration override, which skips every hook without using any flag the guard recognizes. Measured against claude/gh-write-guard.py: such a push returns no deny, while the same push with --no-verify returns a deny. The guard's source contains no reference to the hooks-path configuration key at all.

Why it matters now

PR #1125 adds .husky/pre-push, the first committed hook in this repo that gates behavior rather than formatting. Its design decision recorded at the time was that no new guard requirement was needed, because the existing --no-verify denial already covered the only bypass of a committed hook. That premise is what this issue reports as false. PR #1125's own prose was corrected to describe the hook as a backstop rather than a seal, so nothing in the repo currently claims otherwise, and the hook remains deliberately bypassable for a human.

The question is whether the guard should close the agent-facing half. A committed hook is meant to be bypassable on purpose, and requirement 4 exists because an agent choosing the bypass unprompted is the failure it guards. An override that reaches the same result without the recognized flag sits on the wrong side of that line.

What a fix would need

  • A spec change to requirement 4 covering an inline configuration override that relocates or disables the hooks path, alongside the flags it already names.
  • The implementation in claude/gh-write-guard.py, following that requirement's existing precision-over-recall stance and its handling of global options placed before the subcommand.
  • Selftest cases for the deny, and for the shapes that must stay allowed, since an inline -c carrying an unrelated key is ordinary and common.

Deliberately not written here: the exact invocation. The requirement text and the selftest are where it belongs, not in an issue body that is the first thing a search reaches.

Decision

The maintainer chose to file this rather than grow #1125, which has already run ten local review rounds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions