Skip to content

Commit

Permalink
Merge pull request #1261 from BeChris/issue680
Browse files Browse the repository at this point in the history
git: worktree_commit, sanitize author and commiter name and email before creating the commit object. Fixes #680
  • Loading branch information
pjbgf authored Dec 28, 2024
2 parents 8b7f5ba + 4998140 commit 94bd4af
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
17 changes: 15 additions & 2 deletions worktree_commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"io"
"path"
"regexp"
"sort"
"strings"

Expand All @@ -23,6 +24,10 @@ var (
// ErrEmptyCommit occurs when a commit is attempted using a clean
// working tree, with no changes to be committed.
ErrEmptyCommit = errors.New("cannot create empty commit: clean working tree")

// characters to be removed from user name and/or email before using them to build a commit object
// See https://git-scm.com/docs/git-commit#_commit_information
invalidCharactersRe = regexp.MustCompile(`[<>\n]`)
)

// Commit stores the current contents of the index in a new commit along with
Expand Down Expand Up @@ -137,8 +142,8 @@ func (w *Worktree) updateHEAD(commit plumbing.Hash) error {

func (w *Worktree) buildCommitObject(msg string, opts *CommitOptions, tree plumbing.Hash) (plumbing.Hash, error) {
commit := &object.Commit{
Author: *opts.Author,
Committer: *opts.Committer,
Author: w.sanitize(*opts.Author),
Committer: w.sanitize(*opts.Committer),
Message: msg,
TreeHash: tree,
ParentHashes: opts.Parents,
Expand All @@ -164,6 +169,14 @@ func (w *Worktree) buildCommitObject(msg string, opts *CommitOptions, tree plumb
return w.r.Storer.SetEncodedObject(obj)
}

func (w *Worktree) sanitize(signature object.Signature) object.Signature {
return object.Signature{
Name: invalidCharactersRe.ReplaceAllString(signature.Name, ""),
Email: invalidCharactersRe.ReplaceAllString(signature.Email, ""),
When: signature.When,
}
}

type gpgSigner struct {
key *openpgp.Entity
cfg *packet.Config
Expand Down
48 changes: 48 additions & 0 deletions worktree_commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"time"

fixtures "github.com/go-git/go-git-fixtures/v4"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/object"
Expand Down Expand Up @@ -618,6 +619,44 @@ func (s *WorktreeSuite) TestJustStoreObjectsNotAlreadyStored(c *C) {
c.Assert(infoLicenseSecond.ModTime(), Equals, infoLicense.ModTime()) // object of LICENSE should have the same timestamp because no additional write operation was performed
}

func (s *WorktreeSuite) TestCommitInvalidCharactersInAuthorInfos(c *C) {
f := fixtures.Basic().One()
s.Repository = s.NewRepositoryWithEmptyWorktree(f)

expected := plumbing.NewHash("e8eecef2524c3a37cf0f0996603162f81e0373f1")

fs := memfs.New()
storage := memory.NewStorage()

r, err := Init(storage, fs)
c.Assert(err, IsNil)

w, err := r.Worktree()
c.Assert(err, IsNil)

util.WriteFile(fs, "foo", []byte("foo"), 0644)

_, err = w.Add("foo")
c.Assert(err, IsNil)

hash, err := w.Commit("foo\n", &CommitOptions{Author: invalidSignature()})
c.Assert(hash, Equals, expected)
c.Assert(err, IsNil)

assertStorageStatus(c, r, 1, 1, 1, expected)

// Check HEAD commit contains author informations with '<', '>' and '\n' stripped
lr, err := r.Log(&LogOptions{})
c.Assert(err, IsNil)

commit, err := lr.Next()
c.Assert(err, IsNil)

c.Assert(commit.Author.Name, Equals, "foo bad")
c.Assert(commit.Author.Email, Equals, "badfoo@foo.foo")

}

func assertStorageStatus(
c *C, r *Repository,
treesCount, blobCount, commitCount int, head plumbing.Hash,
Expand Down Expand Up @@ -657,6 +696,15 @@ func defaultSignature() *object.Signature {
}
}

func invalidSignature() *object.Signature {
when, _ := time.Parse(object.DateFormat, "Thu May 04 00:03:43 2017 +0200")
return &object.Signature{
Name: "foo <bad>\n",
Email: "<bad>\nfoo@foo.foo",
When: when,
}
}

func commitSignKey(c *C, decrypt bool) *openpgp.Entity {
s := strings.NewReader(armoredKeyRing)
es, err := openpgp.ReadArmoredKeyRing(s)
Expand Down

0 comments on commit 94bd4af

Please sign in to comment.