security-guidance: git status -uall walks every submodule, ~73s per call in a 66-submodule repo
Summary
security-guidance's gitutil._git_status_porcelain runs git status --porcelain=v1 -uall -z with no --ignore-submodules flag. In a repo with many nested submodules, each call takes over a minute, and the plugin runs it on every UserPromptSubmit, every Edit/Write/MultiEdit/NotebookEdit (PostToolUse) and every Stop/SubagentStop, in every open session.
Environment
- Claude Code: 2.1.286
- security-guidance: 2.0.8 (claude-plugins-official)
- Provider: 1P (claude.ai login)
- OS: Windows 11, git for Windows, NVMe SSD
- Repo: private, 66 nested submodule mounts (several repos are mounted more than once at different depths)
Repro
In any repo with dozens of initialized submodules, time the plugin's command against the same command with --ignore-submodules=dirty:
git status --porcelain=v1 -uall -z ~73,000 ms
git status --porcelain=v1 -uall -z --ignore-submodules=dirty ~200 ms
(Measured with git status --porcelain=v2 --branch variants in the same repo: 73,652 ms default vs 227 ms with --ignore-submodules=dirty.)
Impact
subprocess.run(..., timeout=30)killsgit.exebut on Windows not its per-submodule child processes, so each call keeps walking the tree after the timeout and the hook gets no result.- With 4 or 5 sessions open in the repo, these calls overlap and pile up. They competed with other git work on the same disk: a
git worktree addthat takes about 175 s on a quiet machine took 495 s with sessions open.
Suggested fix
Add --ignore-submodules=dirty to the status call in gitutil._git_status_porcelain (and any sibling status/diff calls). A submodule whose checked-out commit differs from the recorded gitlink still shows as modified, which is the only submodule change a superproject commit can contain. Only uncommitted edits and untracked files inside submodules are skipped, and the review's diff does not descend into submodules anyway.
The same one-flag fix was accepted upstream in the wmux terminal for its pane git-status badge, for the same repo.
Workaround
Disable the plugin per repo with "enabledPlugins": { "security-guidance@claude-plugins-official": false } in .claude/settings.local.json.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗