Skip to content

Commit

Permalink
git: worktree_commit, Add crypto.Signer option to CommitOptions.
Browse files Browse the repository at this point in the history
This change adds a new crypto.Signer option to CommitOptions as an
alternative to SignKey to allow alternative commit signers to be used.
This change byitself does not add other signing methods (e.g. ssh,
x509, gitsign), but gives callers the ability to add their own.

This roughly follows git's sign_buffer approach where go-git handles the
commit message body encoding, and hands off the encoded []byte to the signing
implementation for the signature to be returned.

Signed-off-by: Billy Lynch <billy@chainguard.dev>
  • Loading branch information
wlynch committed Jan 18, 2024
1 parent a6e934f commit e1bb0e2
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 11 deletions.
5 changes: 5 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package git

import (
"crypto"
"errors"
"fmt"
"regexp"
Expand Down Expand Up @@ -507,6 +508,10 @@ type CommitOptions struct {
// commit will not be signed. The private key must be present and already
// decrypted.
SignKey *openpgp.Entity
// Signer denotes a cryptographic signer to sign the commit with.
// A nil value here means the commit will not be signed.
// Takes precedence over SignKey.
Signer crypto.Signer
// Amend will create a new commit object and replace the commit that HEAD currently
// points to. Cannot be used with All nor Parents.
Amend bool
Expand Down
53 changes: 43 additions & 10 deletions worktree_commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package git

import (
"bytes"
"crypto"
"crypto/rand"
"errors"
"io"
"path"
"sort"
"strings"
Expand All @@ -14,6 +17,7 @@ import (
"github.com/go-git/go-git/v5/storage"

"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/go-git/go-billy/v5"
)

Expand Down Expand Up @@ -125,12 +129,17 @@ func (w *Worktree) buildCommitObject(msg string, opts *CommitOptions, tree plumb
ParentHashes: opts.Parents,
}

if opts.SignKey != nil {
sig, err := w.buildCommitSignature(commit, opts.SignKey)
// Convert SignKey into a Signer if set. Existing Signer should take priority.
signer := opts.Signer
if signer == nil && opts.SignKey != nil {
signer = &gpgSigner{key: opts.SignKey}
}
if signer != nil {
sig, err := w.buildCommitSignature(commit, signer)
if err != nil {
return plumbing.ZeroHash, err
}
commit.PGPSignature = sig
commit.PGPSignature = string(sig)
}

obj := w.r.Storer.NewEncodedObject()
Expand All @@ -140,20 +149,44 @@ func (w *Worktree) buildCommitObject(msg string, opts *CommitOptions, tree plumb
return w.r.Storer.SetEncodedObject(obj)
}

func (w *Worktree) buildCommitSignature(commit *object.Commit, signKey *openpgp.Entity) (string, error) {
type gpgSigner struct {
key *openpgp.Entity
}

func (s *gpgSigner) Public() crypto.PublicKey {
return s.key.PrimaryKey
}

func (s *gpgSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
var cfg *packet.Config
if opts != nil {
cfg = &packet.Config{
DefaultHash: opts.HashFunc(),
}
}

var b bytes.Buffer
if err := openpgp.ArmoredDetachSign(&b, s.key, bytes.NewReader(digest), cfg); err != nil {
return nil, err
}
return b.Bytes(), nil
}

func (w *Worktree) buildCommitSignature(commit *object.Commit, signer crypto.Signer) ([]byte, error) {
encoded := &plumbing.MemoryObject{}
if err := commit.Encode(encoded); err != nil {
return "", err
return nil, err
}
r, err := encoded.Reader()
if err != nil {
return "", err
return nil, err
}
var b bytes.Buffer
if err := openpgp.ArmoredDetachSign(&b, signKey, r, nil); err != nil {
return "", err
b, err := io.ReadAll(r)
if err != nil {
return nil, err
}
return b.String(), nil

return signer.Sign(rand.Reader, b, nil)
}

// buildTreeHelper converts a given index.Index file into multiple git objects
Expand Down
1 change: 0 additions & 1 deletion worktree_commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ func (s *WorktreeSuite) TestCommitAmend(c *C) {
_, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)


amendedHash, err := w.Commit("bar\n", &CommitOptions{Amend: true})
c.Assert(err, IsNil)

Expand Down

0 comments on commit e1bb0e2

Please sign in to comment.