Problem
When commit.gpgsign = true is set in the user's global git config, all git commit calls issued by Crush's bash tool fail immediately with:
error: gpg failed to sign the data
fatal: failed to write commit object
The bash tool runs commands in a non-interactive, non-TTY subprocess. GPG's pinentry program requires a TTY to prompt for a passphrase. Because no TTY is available, pinentry exits with an error, GPG fails to sign, and git commit aborts — often without the user realising GPG signing was the cause.
Reproduction
- Enable GPG commit signing globally:
git config --global commit.gpgsign true
git config --global user.signingkey <KEYID>
- Ensure the
gpg-agent passphrase is not currently cached (e.g. fresh shell or agent restarted).
- Ask Crush to make any commit in a git repository.
- Observe the commit fails with
gpg failed to sign the data.
Expected Behaviour
One of:
- Crush detects the GPG failure, surfaces a clear error message, and suggests a workaround (e.g. pre-warm
gpg-agent).
- Crush temporarily exposes a TTY to the subprocess so
pinentry can prompt the user.
- Crush documents / detects
commit.gpgsign at session start and warns the user proactively.
Impact
Any user with commit.gpgsign = true (common in enterprise and security-conscious setups) cannot use Crush's commit workflow at all. The failure is silent by default — Crush's bash tool returns a non-zero exit code but the root cause is not obvious.
Suggested Approaches
- Pre-warm gpg-agent: Before issuing
git commit, run echo test | gpg --clearsign > /dev/null 2>&1 to trigger a passphrase prompt while a TTY is still accessible, caching the passphrase in the agent for subsequent calls.
- Detect and surface: Parse the git error output for
gpg failed to sign; when detected, emit a user-visible message explaining the cause and the workaround.
- SSH signing as documented alternative: Add a note in docs / onboarding that SSH commit signing (
gpg.format = ssh + key in ssh-agent) avoids the TTY requirement entirely and works cleanly in non-interactive subprocesses.
- Expose TTY for commit step: Where the shell infrastructure allows, attach a PTY to the
git commit subprocess so pinentry can function normally.
Workaround
Pre-cache the passphrase before starting a Crush session:
echo "test" | gpg --clearsign > /dev/null
Or switch to SSH-based commit signing:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
Related
The identical issue was reported against Kiro (another agentic coding tool): kirodotdev/Kiro#8303 — indicating this is a class-wide problem for AI coding assistants that drive git via non-interactive subprocesses.
Environment
- OS: Linux (WSL2)
gpg-agent running in supervised mode
pinentry-mode not set (defaults to ask)
Problem
When
commit.gpgsign = trueis set in the user's global git config, allgit commitcalls issued by Crush's bash tool fail immediately with:The bash tool runs commands in a non-interactive, non-TTY subprocess. GPG's
pinentryprogram requires a TTY to prompt for a passphrase. Because no TTY is available,pinentryexits with an error, GPG fails to sign, andgit commitaborts — often without the user realising GPG signing was the cause.Reproduction
gpg-agentpassphrase is not currently cached (e.g. fresh shell or agent restarted).gpg failed to sign the data.Expected Behaviour
One of:
gpg-agent).pinentrycan prompt the user.commit.gpgsignat session start and warns the user proactively.Impact
Any user with
commit.gpgsign = true(common in enterprise and security-conscious setups) cannot use Crush's commit workflow at all. The failure is silent by default — Crush's bash tool returns a non-zero exit code but the root cause is not obvious.Suggested Approaches
git commit, runecho test | gpg --clearsign > /dev/null 2>&1to trigger a passphrase prompt while a TTY is still accessible, caching the passphrase in the agent for subsequent calls.gpg failed to sign; when detected, emit a user-visible message explaining the cause and the workaround.gpg.format = ssh+ key inssh-agent) avoids the TTY requirement entirely and works cleanly in non-interactive subprocesses.git commitsubprocess sopinentrycan function normally.Workaround
Pre-cache the passphrase before starting a Crush session:
Or switch to SSH-based commit signing:
git config --global gpg.format ssh git config --global user.signingkey ~/.ssh/id_ed25519.pubRelated
The identical issue was reported against Kiro (another agentic coding tool): kirodotdev/Kiro#8303 — indicating this is a class-wide problem for AI coding assistants that drive
gitvia non-interactive subprocesses.Environment
gpg-agentrunning in supervised modepinentry-modenot set (defaults toask)