diff --git a/internal/git/git.go b/internal/git/git.go index 3072d6b7..16d7b278 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -26,6 +26,11 @@ type Git struct { repo *git.Repository } +type CommitData struct { + Message string + SHA string +} + func findDotGit(name string) (string, error) { if _, err := os.Stat(name); os.IsNotExist(err) { return findDotGit(path.Join("..", name)) @@ -49,19 +54,19 @@ func NewGit() (*Git, error) { return &Git{repo: repo}, nil } -// Message returns the commit message. In the case that a commit has multiple +// Commit returns the commit data. In the case that a commit has multiple // parents, the message of the last parent is returned. // //nolint:nonamedreturns -func (g *Git) Message() (message string, err error) { +func (g *Git) Commit() (commitData CommitData, err error) { ref, err := g.repo.Head() if err != nil { - return "", err + return CommitData{Message: ""}, err } commit, err := g.repo.CommitObject(ref.Hash()) if err != nil { - return "", err + return CommitData{Message: "", SHA: ref.Hash().String()}, err } if commit.NumParents() > 1 { @@ -72,22 +77,22 @@ func (g *Git) Message() (message string, err error) { next, err = parents.Next() if err != nil { - return "", err + return CommitData{Message: ""}, err } if i == commit.NumParents() { - message = next.Message + commitData = CommitData{Message: next.Message, SHA: next.Hash.String()} } } } else { - message = commit.Message + commitData = CommitData{Message: commit.Message, SHA: commit.Hash.String()} } - return message, err + return commitData, err } -// Messages returns the list of commit messages in the range commit1..commit2. -func (g *Git) Messages(commit1, commit2 string) ([]string, error) { +// Commits returns the list of commit data in the range commit1..commit2. +func (g *Git) Commits(commit1, commit2 string) ([]CommitData, error) { hash1, err := g.repo.ResolveRevision(plumbing.Revision(commit1)) if err != nil { return nil, err @@ -117,10 +122,11 @@ func (g *Git) Messages(commit1, commit2 string) ([]string, error) { c1 = c[0] } - msgs := make([]string, 0) + commits := make([]CommitData, 0) for { - msgs = append(msgs, c2.Message) + commit := CommitData{Message: c2.Message, SHA: c2.Hash.String()} + commits = append(commits, commit) c2, err = c2.Parents().Next() if err != nil { @@ -132,20 +138,24 @@ func (g *Git) Messages(commit1, commit2 string) ([]string, error) { } } - return msgs, nil + return commits, nil } -// HasGPGSignature returns the commit message. In the case that a commit has multiple -// parents, the message of the last parent is returned. +// HasGPGSignature verifies that the given commit has a GPG signature. +// In the case that sha is empty. The last commit is checked. // //nolint:nonamedreturns -func (g *Git) HasGPGSignature() (ok bool, err error) { - ref, err := g.repo.Head() - if err != nil { - return false, err +func (g *Git) HasGPGSignature(sha string) (ok bool, err error) { + if sha == "" { + ref, err := g.repo.Head() + if err != nil { + return false, err + } + sha = ref.Hash().String() } - commit, err := g.repo.CommitObject(ref.Hash()) + + commit, err := g.repo.CommitObject(plumbing.NewHash(sha)) if err != nil { return false, err } @@ -156,13 +166,16 @@ func (g *Git) HasGPGSignature() (ok bool, err error) { } // VerifyPGPSignature validates PGP signature against a keyring. -func (g *Git) VerifyPGPSignature(armoredKeyrings []string) (*openpgp.Entity, error) { - ref, err := g.repo.Head() - if err != nil { - return nil, err +func (g *Git) VerifyPGPSignature(sha string, armoredKeyrings []string) (*openpgp.Entity, error) { + if sha == "" { + ref, err := g.repo.Head() + if err != nil { + return nil, err + } + sha = ref.Hash().String() } - commit, err := g.repo.CommitObject(ref.Hash()) + commit, err := g.repo.CommitObject(plumbing.NewHash(sha)) if err != nil { return nil, err } diff --git a/internal/policy/commit/check_gpg_identity.go b/internal/policy/commit/check_gpg_identity.go index a6e8279d..154344e7 100644 --- a/internal/policy/commit/check_gpg_identity.go +++ b/internal/policy/commit/check_gpg_identity.go @@ -73,7 +73,7 @@ func (c Commit) ValidateGPGIdentity(g *git.Git) policy.Check { //nolint:ireturn return check } - entity, err := g.VerifyPGPSignature(keyrings) + entity, err := g.VerifyPGPSignature(c.sha, keyrings) if err != nil { check.errors = append(check.errors, err) diff --git a/internal/policy/commit/check_gpg_signature.go b/internal/policy/commit/check_gpg_signature.go index ae4a04b3..a740fe7b 100644 --- a/internal/policy/commit/check_gpg_signature.go +++ b/internal/policy/commit/check_gpg_signature.go @@ -39,7 +39,7 @@ func (g GPGCheck) Errors() []error { func (c Commit) ValidateGPGSign(g *git.Git) policy.Check { //nolint:ireturn check := &GPGCheck{} - ok, err := g.HasGPGSignature() + ok, err := g.HasGPGSignature(c.sha) if err != nil { check.errors = append(check.errors, err) diff --git a/internal/policy/commit/commit.go b/internal/policy/commit/commit.go index 39af24e4..d175427d 100644 --- a/internal/policy/commit/commit.go +++ b/internal/policy/commit/commit.go @@ -83,6 +83,7 @@ type Commit struct { MaximumOfOneCommit bool `mapstructure:"maximumOfOneCommit"` msg string + sha string } // FirstWordRegex is theregular expression used to find the first word in a @@ -102,7 +103,7 @@ func (c *Commit) Compliance(options *policy.Options) (*policy.Report, error) { return report, errors.Errorf("failed to open git repo: %v", err) } - var msgs []string + var commits []git.CommitData switch o := options; { case o.CommitMsgFile != nil: @@ -112,28 +113,29 @@ func (c *Commit) Compliance(options *policy.Options) (*policy.Report, error) { return report, errors.Errorf("failed to read commit message file: %v", err) } - msgs = append(msgs, string(contents)) + commits = append(commits, git.CommitData{Message: string(contents)}) case o.RevisionRange != "": revs, err := extractRevisionRange(options) if err != nil { return report, errors.Errorf("failed to get commit message: %v", err) } - msgs, err = g.Messages(revs[0], revs[1]) + commits, err = g.Commits(revs[0], revs[1]) if err != nil { return report, errors.Errorf("failed to get commit message: %v", err) } default: - msg, err := g.Message() + commit, err := g.Commit() if err != nil { return report, errors.Errorf("failed to get commit message: %v", err) } - msgs = append(msgs, msg) + commits = append(commits, commit) } - for i := range msgs { - c.msg = msgs[i] + for i := range commits { + c.msg = commits[i].Message + c.sha = commits[i].SHA c.compliance(report, g, options) }