`SelectOpenPGPSigningEntity` selects `keyRing[0]` when no key id is
supplied and then calls `entity.PrivateKey.Decrypt` directly. For a
keyring that contains only public keys — e.g. an armor-exported
public key file — `PrivateKey` is `nil` and the call panics with a
nil pointer dereference rather than surfacing an actionable error.
The keyed branch already guards against this; the default branch
did not.
Guard the default branch with the same nil check and return an
error pointing at `gpg --export-secret-keys` or `--gpg-key-id` so
the user knows how to recover. Cover the public-only-keyring case
in `TestSelectOpenPGPSigningEntity` so a future regression cannot
re-introduce the panic.
Assisted-by: claude/opus-4.7
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
Adds two layers of coverage for the SSH commit-signing path that the
previous commit wires through PlainGitBootstrapper.
TestPlainGitBootstrapper_resolveSigner exercises every branch of the
new dispatcher: nil configuration, GPG-only, SSH-only, encrypted-SSH-
without-passphrase failure, and the documented GPG-wins-when-both-
set precedence.
TestPlainGitBootstrapper_sshSignerProducesVerifiableCommit drives an
end-to-end roundtrip: resolveSigner returns an SSH signer, the signer
plugs into repository.WithSigner, gogit.Client.Commit produces a
commit object, and signature.VerifySSHSignature cryptographically
verifies the gpgsig header against the matching authorized_key.
Catches regressions in the SSH-signing wiring that the dispatcher
unit tests would miss.
Signed-off-by: Hidde Beydals <hidde@hhh.computer>