fix(git-guards): semantic branch detection and trailer compliance#303
Conversation
…nel trailer rewrite Replace convention-based directory-name checks with semantic git detection across both guards, fixing three distinct issues: - git-permission-guard: _is_on_main_branch() had no cwd= threading, so git -C <feature-wt> commit from a main-branch shell was incorrectly denied. Add _is_inside_work_tree() and _resolve_effective_dir() helpers; capture the -C path from the parsing loop; read hook_cwd from the hook input JSON. Bare repos short-circuit at --is-inside-work-tree (prints "false", exit 0) before any branch lookup, eliminating the false-positive block. - main-branch-guard: delete the Path(worktree_root).name == "main" convention block and its now-unused get_worktree_root() helper. The existing semantic check (is_in_git_worktree + current_branch == "main") is the sole trigger. Layout-agnostic and bare-repo-safe with no new code. - commit-trailer-guard (new): PreToolUse hook that detects "Assisted-by: Claude <...>" in git commit commands and rewrites to "Assisted-by: Claude:<model>" per the Linux kernel coding-assistants spec (https://docs.kernel.org/process/coding-assistants.html). Model is resolved from the session transcript jsonl; fails open if transcript is unavailable. Tests: 62 total across three files, all passing. New cases cover -C override, bare-repo, non-conventional layout, relative path resolution, and all trailer rewrite scenarios. Assisted-by: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces the commit-trailer-guard.py script, which automatically rewrites Assisted-by trailers in git commit messages to comply with the Linux kernel coding-assistants specification. It also refactors the branch detection logic in git-permission-guard.py and main-branch-guard.py to be more robust and layout-agnostic, specifically improving support for git worktrees and bare repositories. Feedback was provided regarding the regex patterns used for git global flag detection to ensure they handle combined flags and missing common parameters. Additionally, a redundant subprocess call in the branch check logic was identified for removal to improve performance.
There was a problem hiding this comment.
Pull request overview
This PR updates the git-guards plugin to make main-branch detection more semantically correct (worktree-aware, bare-repo-safe, and git -C-aware) and introduces a new guard that rewrites Claude “Assisted-by” trailers to match the Linux kernel coding-assistants format.
Changes:
- Fix
git-permission-guard.pymain-branch detection by threading an effective directory (from-Cand hookcwd) through worktree checks andgit branch --show-current, with explicit bare-repo handling. - Simplify
main-branch-guard.pyby removing the directory-name heuristic and relying solely on “inside worktree + current branch == main”. - Add
commit-trailer-guard.py(plus docs, hooks config, and tests) to rewriteAssisted-by: Claude <...>→Assisted-by: Claude:<model>.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| git-guards/scripts/test_permission_guard.py | Adds worktree/bare-repo fixtures and new BLOCKED_ON_MAIN branch-detection test cases. |
| git-guards/scripts/test_main_branch_guard.py | New semantic branch-detection tests for main-branch-guard using git fixtures. |
| git-guards/scripts/test_commit_trailer_guard.py | New tests validating Assisted-by trailer rewriting and fail-open behavior. |
| git-guards/scripts/main-branch-guard.py | Removes directory-name-based “main worktree” detection, leaving branch-based logic. |
| git-guards/scripts/git-permission-guard.py | Implements effective-dir resolution and bare-repo-safe “on main” detection. |
| git-guards/scripts/commit-trailer-guard.py | New PreToolUse hook to rewrite Assisted-by trailers using model from transcript jsonl. |
| git-guards/README.md | Documents the new commit-trailer-guard hook and updates the hook list. |
| git-guards/hooks/hooks.json | Registers commit-trailer-guard for Bash PreToolUse hooks. |
| git-guards/ARCHITECTURE.md | Updates diagrams to include commit-trailer-guard in the hook flow. |
Comments suppressed due to low confidence (1)
git-guards/scripts/main-branch-guard.py:150
- This guard now denies based on
current_branch == "main", but the message says the file is in the "main worktree". That can be misleading for repos that aren’t using amain/worktree layout (or any worktrees). Consider updating the message to refer to the "main branch" to match the actual check.
current_branch = get_current_branch(file_path)
if current_branch == "main":
deny(
f"BLOCKED: File '{file_path}' is in the main worktree. "
"Editing files in the main worktree is not allowed.\n\n"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
CI validates that all Python scripts in scripts/ are executable. New files commit-trailer-guard.py, test_commit_trailer_guard.py, and test_main_branch_guard.py were missing the executable permission. Assisted-by: Claude <noreply@anthropic.com>
…ipt read - commit-trailer-guard: read transcript tail (8 KB bounded) instead of loading the full file, avoiding cost on long sessions - test_permission_guard, test_main_branch_guard: use HEAD:main push form so fixtures work regardless of init.defaultBranch configuration - test_permission_guard, test_main_branch_guard: narrow fixture exception catch to FileNotFoundError so real setup failures surface instead of silently skipping tests Assisted-by: Claude <noreply@anthropic.com>
The setup_test_repo fixture used plain git init, which respects the system's init.defaultBranch setting. CI runners default to master, so git branch --show-current returned "master" and the semantic deny check never triggered. Assisted-by: Claude <noreply@anthropic.com>
Summary
Fixed three bugs in git-guards plugin:
git -C <path> commitfrom main worktree was incorrectly denied — parsed but discarded the path instead of using it for branch detectionAssisted-by: Claude <...>trailer doesn't match Linux kernel spec formatAssisted-by: Claude:<model>Changes
git-permission-guard.py
_is_inside_work_tree()helper usinggit rev-parse --is-inside-work-tree(checks stdout, not just exit code) — safe for bare repos_resolve_effective_dir()to capture and resolve-Cpaths during command parsing_is_on_main_branch()to taketarget_dirparam and use semantic checks (work-tree + branch name) instead of directory-name conventioncwdfield for accurate path resolutionmain-branch-guard.py
get_worktree_root()function and directory-name convention blockis_in_git_worktree()+current_branch == "main"commit-trailer-guard.py (new 112-line PreToolUse hook)
Assisted-by: Claude <...>in git commit commandsAssisted-by: Claude:<model>per https://docs.kernel.org/process/coding-assistants.htmlTest changes
test_main_branch_guard.py,test_commit_trailer_guard.pytest_permission_guard.pywith 8 new worktree regression tests for-Cpath resolutiontest_hook.py: usegit init -b mainto avoid default branch assumptions in CITest Plan
scripts/test_*.py)-Cpath resolution in permission guard-b mainexplicitly)Assisted-by: Claude noreply@anthropic.com