Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1f858c303 |
@@ -388,7 +388,8 @@ func ResolveGPGKeyFingerprint(keyID string) (string, error) {
|
||||
return "", fmt.Errorf("%w: %s", ErrGPGKeyNotFound, keyID)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("failed to resolve GPG key fingerprint: %w", err)
|
||||
return "", fmt.Errorf(
|
||||
"failed to resolve GPG key fingerprint: %w", withGPGStderr(err))
|
||||
}
|
||||
|
||||
// Parse the output to extract the fingerprint
|
||||
@@ -418,6 +419,24 @@ func checkGPGAvailable() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// withGPGStderr appends gpg's stderr, which says why gpg failed, to err
|
||||
// from cmd.Output. cmd.Output keeps that stderr in the *exec.ExitError.
|
||||
// err is returned unchanged when gpg wrote nothing to stderr.
|
||||
func withGPGStderr(err error) error {
|
||||
var exitErr *exec.ExitError
|
||||
|
||||
if !errors.As(err, &exitErr) {
|
||||
return err
|
||||
}
|
||||
|
||||
stderr := strings.TrimSpace(string(exitErr.Stderr))
|
||||
if stderr == "" {
|
||||
return err
|
||||
}
|
||||
|
||||
return fmt.Errorf("%w: %s", err, stderr)
|
||||
}
|
||||
|
||||
// gpgEncryptDefault is the default implementation of GPG encryption
|
||||
func gpgEncryptDefault(data *memguard.LockedBuffer, keyID string) ([]byte, error) {
|
||||
if data == nil {
|
||||
@@ -437,7 +456,7 @@ func gpgEncryptDefault(data *memguard.LockedBuffer, keyID string) ([]byte, error
|
||||
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GPG encryption failed: %w", err)
|
||||
return nil, fmt.Errorf("GPG encryption failed: %w", withGPGStderr(err))
|
||||
}
|
||||
|
||||
return output, nil
|
||||
@@ -450,7 +469,7 @@ func gpgDecryptDefault(encryptedData []byte) (*memguard.LockedBuffer, error) {
|
||||
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GPG decryption failed: %w", err)
|
||||
return nil, fmt.Errorf("GPG decryption failed: %w", withGPGStderr(err))
|
||||
}
|
||||
|
||||
// Create a secure buffer for the decrypted data
|
||||
|
||||
@@ -102,3 +102,27 @@ func TestPGPUnlockerAddedTwiceKeepsFirst(t *testing.T) {
|
||||
assert.NotEqual(t, first.GetDirectory(), second.GetDirectory())
|
||||
assert.Equal(t, firstFiles, dirFiles(t, fs, first.GetDirectory()))
|
||||
}
|
||||
|
||||
// TestGPGDecryptErrorHasGPGReason runs the real gpg on data that is not an
|
||||
// OpenPGP message and checks that the error carries the reason gpg writes
|
||||
// to stderr.
|
||||
func TestGPGDecryptErrorHasGPGReason(t *testing.T) {
|
||||
// The empty GNUPGHOME keeps gpg away from the user's own keyring;
|
||||
// LC_ALL=C keeps gpg's message in English.
|
||||
t.Setenv("GNUPGHOME", t.TempDir())
|
||||
t.Setenv("LC_ALL", "C")
|
||||
|
||||
_, err := secret.GPGDecryptFunc([]byte("not an OpenPGP message"))
|
||||
require.ErrorContains(t, err, "gpg: no valid OpenPGP data found")
|
||||
}
|
||||
|
||||
// TestGPGDecryptErrorWithoutGPGStderr checks that when gpg fails without
|
||||
// writing to stderr, the error ends with the exit status and nothing after it.
|
||||
//
|
||||
//nolint:paralleltest // installFakeGPG uses t.Setenv
|
||||
func TestGPGDecryptErrorWithoutGPGStderr(t *testing.T) {
|
||||
installFakeGPG(t)
|
||||
|
||||
_, err := secret.GPGDecryptFunc([]byte("not an OpenPGP message"))
|
||||
require.EqualError(t, err, "GPG decryption failed: exit status 1")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user