Skip to content

Add crypto.Signer option to CommitOptions. #996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
git: worktree_commit, 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>
  • Loading branch information
wlynch committed Jan 18, 2024
commit e1bb0e2cb68265458d4540ae566c255263d918a2
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
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