Skip to content

fix: prompt for GPG passphrase on unlock (drop --batch)#26

Merged
lucatescari merged 1 commit into
devfrom
fix/gpg-pinentry-passphrase-prompt
May 12, 2026
Merged

fix: prompt for GPG passphrase on unlock (drop --batch)#26
lucatescari merged 1 commit into
devfrom
fix/gpg-pinentry-passphrase-prompt

Conversation

@lucatescari

Copy link
Copy Markdown
Owner

Summary

  • gitveil unlock failed with Inappropriate ioctl for device whenever the GPG private key was passphrase-protected. gpg_decrypt_from_file passed --batch (suppressing pinentry) and used .output() (closing stdin / capturing stderr), leaving pinentry no way to reach the user. Match git-crypt: drop --batch, inherit stdin/stderr, pipe only stdout for the plaintext.
  • Filter .gpg files in unlock by the fingerprints of secret keys present in the local keyring. Pinentry now fires at most once per unlock, and gpg no longer spams stderr with "no secret key" for every other collaborator.
  • Clear error when no collaborator file matches any local secret key.

Test plan

  • cargo fmt --check
  • cargo clippy --all-targets -- -D warnings
  • cargo test — 95 pass (33 unit + 40 integration + 16 GPG + 6 cross-compat)
  • Confirmed TDD red: with --batch reintroduced, the new unit test decrypt_command_does_not_use_batch fails with the expected diagnostic
  • New test_gpg_unlock_with_passphrase_protected_key exercises the full passphrase-protected roundtrip using gpg's pinentry-mode loopback + passphrase-file so it runs headless on Linux/macOS/Windows CI
  • New test_gpg_unlock_no_matching_secret_key_gives_clear_error verifies the new "no matching secret key" error path
  • Cross-check on real Linux/macOS terminal: pinentry prompts for the passphrase interactively (cannot be automated in CI without a TTY)

🤖 Generated with Claude Code

gpg_decrypt_from_file used --batch with .output(), which suppressed
pinentry and left stdin/stderr disconnected — passphrase-protected
secret keys failed with "Inappropriate ioctl for device". Mirror
git-crypt: drop --batch and inherit stdin/stderr so pinentry (terminal
or GUI) can reach the user; pipe only stdout for the plaintext.

Unlock now also enumerates local secret-key fingerprints up front and
only attempts files whose recipient we hold a key for, so pinentry
fires at most once and gpg doesn't spam stderr with "no secret key"
for every other collaborator. Clear error when nothing matches.

Tests (cross-platform): unit test asserting --batch is never in the
decrypt command (the direct regression), passphrase-protected unlock
roundtrip via gpg loopback + passphrase-file (no TTY needed in CI),
and clear-error case when the keyring has no matching secret key.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lucatescari lucatescari merged commit b60726b into dev May 12, 2026
3 checks passed
@lucatescari lucatescari deleted the fix/gpg-pinentry-passphrase-prompt branch May 12, 2026 12:58
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.

1 participant