Include gpg's stderr in the error when gpg fails #179

Merged
clawbot merged 1 commits from fix/146-gpg-stderr into next 2026-10-15 05:31:51 +02:00
Collaborator

Fixes #146.

When gpg failed while decrypting, encrypting or looking up a key fingerprint, the error gave only gpg's exit status, such as GPG decryption failed: exit status 2, and dropped the reason gpg wrote to stderr. cmd.Output keeps that stderr in the *exec.ExitError it returns, and withGPGStderr now appends it, trimmed, to the error in all three places. If gpg wrote nothing to stderr, as when a signal kills it, the error is left as it was. For a missing secret key the decrypt error now ends exit status 2: gpg: public key decryption failed: No secret key, then gpg's second line.

One test runs the real gpg through GPGDecryptFunc with an empty GNUPGHOME and requires gpg's message in the error. Another puts a stand-in gpg that fails without writing to stderr on PATH and requires the error to end at the exit status.

  • Judgement call: the real-gpg test gives gpg data that is not an OpenPGP message instead of a message encrypted to a missing key. gpg reports both the same way, and this case starts no gpg-agent to stop.
  • Judgement call: that test sets LC_ALL=C so that gpg's message is in English.
  • gpg's stderr can run to more than one line, and the error then does too.
  • Partially verified: encrypt and key lookup have no test of their own; they call the same function as decrypt.
  • Not changed: getDefaultGPGKey in internal/cli/unlockers.go also drops gpg's stderr when it lists secret keys; the issue does not name it.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/secret/issues/146. When gpg failed while decrypting, encrypting or looking up a key fingerprint, the error gave only gpg's exit status, such as `GPG decryption failed: exit status 2`, and dropped the reason gpg wrote to stderr. `cmd.Output` keeps that stderr in the `*exec.ExitError` it returns, and `withGPGStderr` now appends it, trimmed, to the error in all three places. If gpg wrote nothing to stderr, as when a signal kills it, the error is left as it was. For a missing secret key the decrypt error now ends `exit status 2: gpg: public key decryption failed: No secret key`, then gpg's second line. One test runs the real gpg through `GPGDecryptFunc` with an empty `GNUPGHOME` and requires gpg's message in the error. Another puts a stand-in gpg that fails without writing to stderr on `PATH` and requires the error to end at the exit status. - Judgement call: the real-gpg test gives gpg data that is not an OpenPGP message instead of a message encrypted to a missing key. gpg reports both the same way, and this case starts no gpg-agent to stop. - Judgement call: that test sets `LC_ALL=C` so that gpg's message is in English. - gpg's stderr can run to more than one line, and the error then does too. - Partially verified: encrypt and key lookup have no test of their own; they call the same function as decrypt. - Not changed: `getDefaultGPGKey` in `internal/cli/unlockers.go` also drops gpg's stderr when it lists secret keys; the issue does not name it. Model: opus-5-5
clawbot added the needs-review label 2026-10-15 01:12:14 +02:00
clawbot self-assigned this 2026-10-15 01:12:14 +02:00
clawbot force-pushed fix/146-gpg-stderr from 5e938bb57e to 488cfd1080 2026-10-15 01:35:26 +02:00 Compare
Author
Collaborator
  • internal/secret/pgpunlocker.go line 428 (withGPGStderr): when gpg fails without writing anything to stderr, for example when it is killed by a signal, the error now ends in a bare separator: GPG decryption failed: exit status 1: , which the vault's advice turns into exit status 1: ; the vault 'default' still opens with its mnemonic: .... Before this change the same failure read exit status 1. Acceptable: add : and gpg's stderr only when the trimmed stderr is not empty, return the error unchanged otherwise, and test that case (the fake gpg that installFakeGPG in internal/secret/pgpunlocker_test.go puts on PATH already fails without writing to stderr).

Model: opus-5-5

- `internal/secret/pgpunlocker.go` line 428 (`withGPGStderr`): when gpg fails without writing anything to stderr, for example when it is killed by a signal, the error now ends in a bare separator: `GPG decryption failed: exit status 1: `, which the vault's advice turns into `exit status 1: ; the vault 'default' still opens with its mnemonic: ...`. Before this change the same failure read `exit status 1`. Acceptable: add `: ` and gpg's stderr only when the trimmed stderr is not empty, return the error unchanged otherwise, and test that case (the fake gpg that `installFakeGPG` in `internal/secret/pgpunlocker_test.go` puts on `PATH` already fails without writing to stderr). Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-15 02:29:12 +02:00
clawbot force-pushed fix/146-gpg-stderr from 488cfd1080 to db21c96750 2026-10-15 03:01:21 +02:00 Compare
clawbot force-pushed fix/146-gpg-stderr from db21c96750 to f9523d6623 2026-10-15 03:20:08 +02:00 Compare
clawbot force-pushed fix/146-gpg-stderr from f9523d6623 to 7900c878e1 2026-10-15 04:13:32 +02:00 Compare
Author
Collaborator
  • Bare separator after the exit status: withGPGStderr now adds : and gpg's stderr only when the trimmed stderr is not empty, and returns the error unchanged otherwise. The new test TestGPGDecryptErrorWithoutGPGStderr runs the fake gpg from installFakeGPG and requires the error to be exactly GPG decryption failed: exit status 1.

Model: opus-5-5

- Bare separator after the exit status: `withGPGStderr` now adds `: ` and gpg's stderr only when the trimmed stderr is not empty, and returns the error unchanged otherwise. The new test `TestGPGDecryptErrorWithoutGPGStderr` runs the fake gpg from `installFakeGPG` and requires the error to be exactly `GPG decryption failed: exit status 1`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-15 04:41:03 +02:00
clawbot added 1 commit 2026-10-15 04:50:43 +02:00
When gpg failed while decrypting, encrypting or looking up a key
fingerprint, the error gave only gpg's exit status, so the user could
not tell why. cmd.Output keeps gpg's stderr in the *exec.ExitError it
returns; the three errors now end with that stderr, trimmed. When gpg
wrote nothing to stderr, the error is left as it was.

gpg's stderr can run to more than one line, and the error then does too.

The regression test gives gpg data that is not an OpenPGP message
instead of one encrypted to a missing key: gpg reports both the same
way, and this case starts no gpg-agent the test would have to stop.

Model: opus-5-5
clawbot force-pushed fix/146-gpg-stderr from 7900c878e1 to d1f858c303 2026-10-15 04:50:43 +02:00 Compare
Author
Collaborator

Review passed.

Model: opus-5-5

Review passed. Model: opus-5-5
clawbot merged commit fdfe2c92f6 into next 2026-10-15 05:31:51 +02:00
clawbot deleted branch fix/146-gpg-stderr 2026-10-15 05:31:52 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/secret#179