Skip to content

Add gpg-pinentry-guard plugin to prevent broken GPG signing prompts#30521

Open
Clovel wants to merge 1 commit intoanthropics:mainfrom
Clovel:fix/pinentry-terminal-conflict
Open

Add gpg-pinentry-guard plugin to prevent broken GPG signing prompts#30521
Clovel wants to merge 1 commit intoanthropics:mainfrom
Clovel:fix/pinentry-terminal-conflict

Conversation

@Clovel
Copy link
Copy Markdown

@Clovel Clovel commented Mar 3, 2026

Summary

Adds a gpg-pinentry-guard plugin — a PreToolUse hook that prevents broken GPG pinentry prompts during git commits.

Fixes #30539.

The Problem

When commit.gpgsign=true is enabled and the passphrase is not cached, git commit triggers pinentry-curses which cannot read keyboard input because Claude Code's Ink renderer holds exclusive control of the terminal. The commit fails with gpg: signing failed: No passphrase given.

What This Plugin Does

A Bash PreToolUse hook that detects when a git command would trigger a broken terminal pinentry and blocks it early with actionable guidance.

Detection pipeline:

  1. Is this a git signing command? (commit, tag, merge)
  2. Is GPG signing enabled? (commit.gpgsign, tag.gpgsign, merge.gpgsign, or -S/-s flags)
  3. Is --no-gpg-sign already present? → allow
  4. Is the pinentry GUI-based? → allow (no terminal conflict)
  5. Is the passphrase cached in gpg-agent? → allow (no pinentry needed)
  6. Otherwise → block with guidance

Files Changed

plugins/gpg-pinentry-guard/
├── .claude-plugin/plugin.json          # Plugin metadata
├── hooks/
│   ├── hooks.json                      # PreToolUse hook config
│   └── gpg_signing_guard.sh            # Detection and blocking logic
└── README.md                           # Documentation and workarounds

Test Results

Scenario Expected Result
Non-git command allow PASS
git status, git push allow PASS
git commit --no-gpg-sign allow PASS
git commit -m "test" (gpgsign=true, uncached) block PASS
git tag -s v1.0 block PASS
git add && git commit (compound) block PASS
GPG_TTY=... git commit (env prefix) block PASS
git -C /path commit (flag prefix) block PASS
/usr/bin/git commit (full path) block PASS
git --no-pager commit (extra flags) block PASS
(git commit) (subshell) block PASS
Command starting with -e (printf safety) allow PASS

16/16 passing.

🤖 Generated with Claude Code

PreToolUse hook plugin that intercepts git commands which would trigger
GPG signing with a terminal-based pinentry (pinentry-curses, pinentry-tty).

Claude Code's Ink renderer holds exclusive control of the terminal's
keyboard input. When pinentry opens /dev/tty to read the passphrase,
keystrokes are captured by the Ink renderer instead, causing
"gpg: signing failed: No passphrase given".

The hook detects this by checking:
- Whether the command triggers GPG signing (commit, tag, merge)
- Whether signing is enabled via git config or explicit flags
- Whether the pinentry is terminal-based vs GUI
- Whether the passphrase is already cached in gpg-agent

When a broken prompt would occur, the hook blocks the command (exit 2)
with actionable guidance: cache passphrase, use --no-gpg-sign, switch
to GUI pinentry, or increase cache timeout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Clovel Clovel force-pushed the fix/pinentry-terminal-conflict branch from 620d925 to 41afa99 Compare March 3, 2026 22:33
@Clovel Clovel changed the title Add gpg-pinentry-guard plugin and audit for terminal pinentry conflict Add gpg-pinentry-guard plugin to prevent broken GPG signing prompts Mar 3, 2026
@Clovel
Copy link
Copy Markdown
Author

Clovel commented Mar 16, 2026

Any news from any maintainers ?

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.

GPG pinentry terminal conflict: signing fails with "No passphrase given" when using terminal-based pinentry

1 participant