Skip to content

Commit e521568

Browse files
committed
Add crypto.Signer option to CommitOptions.
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>
1 parent a6e934f commit e521568

File tree

3 files changed

+48
-11
lines changed

3 files changed

+48
-11
lines changed

options.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package git
22

33
import (
4+
"crypto"
45
"errors"
56
"fmt"
67
"regexp"
@@ -507,6 +508,10 @@ type CommitOptions struct {
507508
// commit will not be signed. The private key must be present and already
508509
// decrypted.
509510
SignKey *openpgp.Entity
511+
// Signer denotes a cryptographic signer to sign the commit with.
512+
// A nil value here means the commit will not be signed.
513+
// Takes precedence over SignKey.
514+
Signer crypto.Signer
510515
// Amend will create a new commit object and replace the commit that HEAD currently
511516
// points to. Cannot be used with All nor Parents.
512517
Amend bool

worktree_commit.go

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package git
22

33
import (
44
"bytes"
5+
"crypto"
6+
"crypto/rand"
57
"errors"
8+
"io"
69
"path"
710
"sort"
811
"strings"
@@ -14,6 +17,7 @@ import (
1417
"github.com/go-git/go-git/v5/storage"
1518

1619
"github.com/ProtonMail/go-crypto/openpgp"
20+
"github.com/ProtonMail/go-crypto/openpgp/packet"
1721
"github.com/go-git/go-billy/v5"
1822
)
1923

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

128-
if opts.SignKey != nil {
129-
sig, err := w.buildCommitSignature(commit, opts.SignKey)
132+
// Convert SignKey into a Signer if set. Existing Signer should take priority.
133+
signer := opts.Signer
134+
if signer == nil && opts.SignKey != nil {
135+
signer = &gpgSigner{key: opts.SignKey}
136+
}
137+
if signer != nil {
138+
sig, err := w.buildCommitSignature(commit, signer)
130139
if err != nil {
131140
return plumbing.ZeroHash, err
132141
}
133-
commit.PGPSignature = sig
142+
commit.PGPSignature = string(sig)
134143
}
135144

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

143-
func (w *Worktree) buildCommitSignature(commit *object.Commit, signKey *openpgp.Entity) (string, error) {
152+
type gpgSigner struct {
153+
key *openpgp.Entity
154+
}
155+
156+
func (s *gpgSigner) Public() crypto.PublicKey {
157+
return s.key.PrimaryKey
158+
}
159+
160+
func (s *gpgSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
161+
var cfg *packet.Config
162+
if opts != nil {
163+
cfg = &packet.Config{
164+
DefaultHash: opts.HashFunc(),
165+
}
166+
}
167+
168+
var b bytes.Buffer
169+
if err := openpgp.ArmoredDetachSign(&b, s.key, bytes.NewReader(digest), cfg); err != nil {
170+
return nil, err
171+
}
172+
return b.Bytes(), nil
173+
}
174+
175+
func (w *Worktree) buildCommitSignature(commit *object.Commit, signer crypto.Signer) ([]byte, error) {
144176
encoded := &plumbing.MemoryObject{}
145177
if err := commit.Encode(encoded); err != nil {
146-
return "", err
178+
return nil, err
147179
}
148180
r, err := encoded.Reader()
149181
if err != nil {
150-
return "", err
182+
return nil, err
151183
}
152-
var b bytes.Buffer
153-
if err := openpgp.ArmoredDetachSign(&b, signKey, r, nil); err != nil {
154-
return "", err
184+
b, err := io.ReadAll(r)
185+
if err != nil {
186+
return nil, err
155187
}
156-
return b.String(), nil
188+
189+
return signer.Sign(rand.Reader, b, nil)
157190
}
158191

159192
// buildTreeHelper converts a given index.Index file into multiple git objects

worktree_commit_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ func (s *WorktreeSuite) TestCommitAmend(c *C) {
131131
_, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
132132
c.Assert(err, IsNil)
133133

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy