Skip to content

fix(git-guards): semantic branch detection and trailer compliance#303

Merged
JacobPEvans merged 4 commits into
mainfrom
fix/git-guards-semantic-branch-detection
May 11, 2026
Merged

fix(git-guards): semantic branch detection and trailer compliance#303
JacobPEvans merged 4 commits into
mainfrom
fix/git-guards-semantic-branch-detection

Conversation

@JacobPEvans
Copy link
Copy Markdown
Owner

@JacobPEvans JacobPEvans commented May 11, 2026

Summary

Fixed three bugs in git-guards plugin:

  1. git -C <path> commit from main worktree was incorrectly denied — parsed but discarded the path instead of using it for branch detection
  2. Both guards used directory-name convention as proxy for "on main branch" — failed with bare repos and non-conventional layouts
  3. Assisted-by: Claude <...> trailer doesn't match Linux kernel spec format Assisted-by: Claude:<model>

Changes

git-permission-guard.py

  • Added _is_inside_work_tree() helper using git rev-parse --is-inside-work-tree (checks stdout, not just exit code) — safe for bare repos
  • Added _resolve_effective_dir() to capture and resolve -C paths during command parsing
  • Rewrote _is_on_main_branch() to take target_dir param and use semantic checks (work-tree + branch name) instead of directory-name convention
  • Now reads hook input cwd field for accurate path resolution

main-branch-guard.py

  • Removed 16 lines: get_worktree_root() function and directory-name convention block
  • Now relies solely on existing semantic checks: is_in_git_worktree() + current_branch == "main"

commit-trailer-guard.py (new 112-line PreToolUse hook)

  • Detects Assisted-by: Claude <...> in git commit commands
  • Rewrites to kernel spec format Assisted-by: Claude:<model> per https://docs.kernel.org/process/coding-assistants.html
  • Extracts model name from session transcript (8KB bounded tail read for performance)
  • Uses regex-only parsing (no shlex) to handle heredoc commit bodies safely

Test changes

  • New test files: test_main_branch_guard.py, test_commit_trailer_guard.py
  • Extended test_permission_guard.py with 8 new worktree regression tests for -C path resolution
  • Fixed test_hook.py: use git init -b main to avoid default branch assumptions in CI

Test Plan

  • All existing test suites pass (unit tests in scripts/test_*.py)
  • Regression tests for -C path resolution in permission guard
  • Bare repo safety verified (bare repo sibling directories correctly excluded)
  • Trailer rewrite verified for kernel spec compliance
  • CI default branch handling fixed (tests now initialize with -b main explicitly)

Assisted-by: Claude noreply@anthropic.com

…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>
Copilot AI review requested due to automatic review settings May 11, 2026 14:18
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

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.

Comment thread git-guards/scripts/commit-trailer-guard.py
Comment thread git-guards/scripts/git-permission-guard.py
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.py main-branch detection by threading an effective directory (from -C and hook cwd) through worktree checks and git branch --show-current, with explicit bare-repo handling.
  • Simplify main-branch-guard.py by 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 rewrite Assisted-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 a main/ 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.

Comment thread git-guards/scripts/commit-trailer-guard.py Outdated
Comment thread git-guards/scripts/test_permission_guard.py
Comment thread git-guards/scripts/test_main_branch_guard.py Outdated
Comment thread git-guards/scripts/test_permission_guard.py Outdated
Comment thread git-guards/scripts/test_main_branch_guard.py Outdated
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>
@JacobPEvans JacobPEvans changed the title fix(git-guards): semantic branch detection, bare-repo safety, and kernel trailer rewrite fix(git-guards): semantic branch detection and trailer compliance May 11, 2026
@JacobPEvans JacobPEvans merged commit d11a7be into main May 11, 2026
6 checks passed
@JacobPEvans JacobPEvans deleted the fix/git-guards-semantic-branch-detection branch May 11, 2026 19:21
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