Skip to content

Check the Shared Hook Before Installing and Deny a Commit-Time hooksPath Override - #2178

Merged
ptr727 merged 4 commits into
developfrom
feature/worktree-shared-hooks
Sep 30, 2026
Merged

ptr727 merged 4 commits into
developfrom
feature/worktree-shared-hooks

Conversation

@ptr727

@ptr727 ptr727 commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Summary

Refs #1816.

  • repo-worktree "Preparing Git Hooks". A linked worktree shares the base clone's git config, and with no core.hooksPath set it also shares the base clone's hooks directory. Running pre-commit install there rewrote the hook for every checkout. The section now:
    • checks for an existing hook with git rev-parse --git-path hooks before installing;
    • identifies a linked worktree by --git-dir differing from --git-common-dir, both run from the root;
    • forbids changing a shared hook or setting from a linked worktree, and binds a repository override to the same limit;
    • lets a standalone clone install into its own hooks;
    • runs the Husky.Net install in a linked worktree only where core.hooksPath already reads .husky;
    • names a commit-time core.hooksPath override as a hook bypass.
  • gh-write-guard denies git -c core.hooksPath=... commit|push and the --config-env forms beside --no-verify, with self-test rows. It refactors _git_subcommand_arglists onto a new _git_subcommand_invocations that keeps the global options.
  • Guard READMEs name the new denial.

The remaining bypass routes, all older than this change, are filed as #2177: a persistent git config core.hooksPath, the GIT_CONFIG_* environment forms, wrapped or aliased git, and a heredoc false positive.

Verification

  • gh-write-guard.py --selftest passes. With the new check disabled, the four new deny rows fail.
  • Hook-path resolution was probed in a scratch base clone and linked worktree, with and without a relative core.hooksPath.
  • Four local strict-review passes ran, raising 7, 2, 1, and 0 findings. The last pass is clean at the pushed head.

🤖 Generated with Claude Code

ptr727 and others added 4 commits September 30, 2026 11:55
…ath Override

repo-worktree's hook step told a session to run `pre-commit install`
from a new worktree's root. With no core.hooksPath set, a linked
worktree's hooks path is the base clone's shared directory, so that
install rewrites the hook for every checkout. The step now checks the
resolved hooks path first, never installs or switches a shared hook
from a linked worktree, and names a commit-time core.hooksPath
override as a hook bypass.

gh-write-guard now denies `-c core.hooksPath=` and `--config-env`
naming that key on a commit or push, beside --no-verify.

Fixes #1816

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…e Clones

The local review found the new rule contradicting the unchanged
Husky.Net bullet, which writes core.hooksPath into the shared config,
and stranding a standalone clone with no way to install its own hook.
The rule now keys on a linked worktree (git-dir differs from
git-common-dir), lets a standalone clone install locally, runs the
Husky.Net install only where the setting already reads .husky, drops
--path-format for older git, and binds a repository override too.
The guard docs name the -c and --config-env forms rather than every
per-invocation override.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…Root

The second local pass found the rule forbidding the Husky.Net step it
sits under, which rewrites core.hooksPath to the value it already
holds, and a subdirectory run reading a primary checkout as linked.
The rule now forbids changing a shared hook or setting, and runs its
git-dir test from the worktree root.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The third local pass found that the .husky precondition left a
standalone clone, whose config is its own, with no instruction to
install at all, where the old unconditional step covered it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 30, 2026 19:06
@coderabbitai

coderabbitai Bot commented Sep 30, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: a6c5376e-fc97-43d5-b55f-b1d86ad7ed5e

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Sep 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.47%. Comparing base (3196954) to head (e61345f).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #2178   +/-   ##
========================================
  Coverage    56.47%   56.47%           
========================================
  Files           16       16           
  Lines         7455     7455           
========================================
  Hits          4210     4210           
  Misses        3245     3245           
Flag Coverage Δ
python-3.13 56.47% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI 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.

Copilot review overview

🔵 Needs a closer look

It changes a security bypass-prevention gate and fleet-wide carried governance content, which the repository treats as design-level and durable-when-wrong, so it warrants final human sign-off despite passing all verification.

Review effort: Balanced
Findings: None

What changed in this PR

This PR closes a hook-safety gap surfaced by the linked issue: running a hook installer (pre-commit/prek/Husky.Net) from a linked worktree rewrote the hook that every checkout of the base clone shares, and a commit-time core.hooksPath override could silently skip hooks the way --no-verify does. It hardens the repo-worktree skill guidance and extends the gh-write-guard PreToolUse hook to deny the per-invocation core.hooksPath override, fitting into the fleet's agent-safety guardrail layer.

Changes:

  • repo-worktree "Preparing Git Hooks" now checks for an existing shared hook before installing, distinguishes linked worktrees (--git-dir vs --git-common-dir) from standalone clones, forbids changing a shared hook/setting from a linked worktree, and names a commit-time core.hooksPath override as a bypass.
  • gh-write-guard.py denies git -c core.hooksPath=... commit|push and both --config-env forms, via a new _overrides_hooks_path helper and a _git_subcommand_invocations refactor that preserves _git_subcommand_arglists; eight self-test rows cover the new positive and negative cases.
  • Guard READMEs document the new denial, and the generated skill copies plus their source digest are regenerated in sync.
File Description
host-setup/​agent-safety/​claude/​gh-write-guard.py Adds _overrides_hooks_path + _git_subcommand_invocations, wires the new deny into _check_bypass_flags, and adds self-test rows. Verified correct via direct execution and passing --selftest.
.agents/​skills/​repo-worktree/​SKILL.md Source-of-truth prose: shared-hook check, linked-worktree prohibition, commit-time override as bypass.
.github/​skills/​repo-worktree/​SKILL.md Generated copy, byte-identical to source (do not edit directly).
.claude-plugin/​fleet-skills/​skills/​repo-worktree/​SKILL.md Generated copy, byte-identical to source.
.claude-plugin/​fleet-skills/​.source-digests/​repo-worktree Regenerated digest; reproduces exactly via build_dist.skill_digest.
host-setup/​agent-safety/​README.md Requirement-4 prose extended to name the -c core.hooksPath= denial.
host-setup/​agent-safety/​claude/​README.md Guard bullet extended to name the core.hooksPath override denial.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ptr727
ptr727 merged commit 4b4a92b into develop Sep 30, 2026
11 checks passed
@ptr727
ptr727 deleted the feature/worktree-shared-hooks branch September 30, 2026 19:15
ptr727 added a commit that referenced this pull request Sep 30, 2026
…Deny a Commit-Time hooksPath Override (#2179)

## Summary

Promotes develop to main, carrying
[#2178](#2178).

That PR stops `repo-worktree`'s hook step from installing into the git
config or hooks directory a linked worktree shares with its base clone.
Such an install rewrote the hook for every checkout. The skill now
checks for an existing hook first, tells a linked worktree from a
standalone clone, and lets only the standalone clone install locally.
`gh-write-guard` now denies a commit-time `-c core.hooksPath=` or
`--config-env` override on a commit or push, beside `--no-verify`. The
remaining older bypass routes are filed as #2177.

Fixes #1816

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants