Severity: minor
When gpg fails, the user is told only its exit status: GPG decryption failed: exit status 2. gpg's own reason ("No secret key", "Inappropriate ioctl for device" from pinentry without GPG_TTY, a cancelled pinentry, an expired key) is written to stderr, which the program captures and throws away, so a PGP-unlocker failure cannot be diagnosed from the message, and the advice appended to it ("still opens with its mnemonic") points the wrong way.
Reproduction (vault with a PGP unlocker as current; a GNUPGHOME that lacks the secret key stands in for any gpg failure):
GNUPGHOME=/tmp/empty secret get foo
# Error: failed to unlock vault: failed to get long-term key: failed to get unlocker identity: failed to decrypt age private key with GPG: GPG decryption failed: exit status 2; the vault 'default' still opens with its mnemonic: ...
gpg --decrypt itself says gpg: decryption failed: No secret key. Encryption (unlocker add pgp) and the fingerprint lookup report the same way.
(gpgDecryptDefault), L439 (gpgEncryptDefault), L386 (ResolveGPGKeyFingerprint): each uses cmd.Output(), which stores gpg's stderr in the *exec.ExitError but the %w message does not include it.
Correct behaviour: the error includes gpg's stderr (trimmed), for example GPG decryption failed: exit status 2: gpg: decryption failed: No secret key.
Definition of done
A gpg failure in decrypt, encrypt and key lookup names gpg's reason from its stderr in the error.
A regression test runs the real gpg against an empty GNUPGHOME through GPGDecryptFunc and requires the error to contain gpg's message; it fails before the fix.
Model: fable-5-1
Severity: minor
When `gpg` fails, the user is told only its exit status: `GPG decryption failed: exit status 2`. gpg's own reason ("No secret key", "Inappropriate ioctl for device" from pinentry without `GPG_TTY`, a cancelled pinentry, an expired key) is written to stderr, which the program captures and throws away, so a PGP-unlocker failure cannot be diagnosed from the message, and the advice appended to it ("still opens with its mnemonic") points the wrong way.
Reproduction (vault with a PGP unlocker as current; a `GNUPGHOME` that lacks the secret key stands in for any gpg failure):
```
GNUPGHOME=/tmp/empty secret get foo
# Error: failed to unlock vault: failed to get long-term key: failed to get unlocker identity: failed to decrypt age private key with GPG: GPG decryption failed: exit status 2; the vault 'default' still opens with its mnemonic: ...
```
`gpg --decrypt` itself says `gpg: decryption failed: No secret key`. Encryption (`unlocker add pgp`) and the fingerprint lookup report the same way.
Where: https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/secret/pgpunlocker.go#L452 (`gpgDecryptDefault`), L439 (`gpgEncryptDefault`), L386 (`ResolveGPGKeyFingerprint`): each uses `cmd.Output()`, which stores gpg's stderr in the `*exec.ExitError` but the `%w` message does not include it.
Correct behaviour: the error includes gpg's stderr (trimmed), for example `GPG decryption failed: exit status 2: gpg: decryption failed: No secret key`.
**Definition of done**
- A gpg failure in decrypt, encrypt and key lookup names gpg's reason from its stderr in the error.
- A regression test runs the real `gpg` against an empty `GNUPGHOME` through `GPGDecryptFunc` and requires the error to contain gpg's message; it fails before the fix.
Model: fable-5-1
sneak
was assigned by clawbot2026-10-13 00:30:39 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: minor
When
gpgfails, the user is told only its exit status:GPG decryption failed: exit status 2. gpg's own reason ("No secret key", "Inappropriate ioctl for device" from pinentry withoutGPG_TTY, a cancelled pinentry, an expired key) is written to stderr, which the program captures and throws away, so a PGP-unlocker failure cannot be diagnosed from the message, and the advice appended to it ("still opens with its mnemonic") points the wrong way.Reproduction (vault with a PGP unlocker as current; a
GNUPGHOMEthat lacks the secret key stands in for any gpg failure):gpg --decryptitself saysgpg: decryption failed: No secret key. Encryption (unlocker add pgp) and the fingerprint lookup report the same way.Where:
gpgDecryptDefault), L439 (gpgEncryptDefault), L386 (ResolveGPGKeyFingerprint): each usescmd.Output(), which stores gpg's stderr in the*exec.ExitErrorbut the%wmessage does not include it.Correct behaviour: the error includes gpg's stderr (trimmed), for example
GPG decryption failed: exit status 2: gpg: decryption failed: No secret key.Definition of done
gpgagainst an emptyGNUPGHOMEthroughGPGDecryptFuncand requires the error to contain gpg's message; it fails before the fix.Model: fable-5-1