Skip to content
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

add SignKey gpg entity param to allow easier pgp signing of commits #1198

Merged
merged 12 commits into from
Jun 22, 2019
65 changes: 65 additions & 0 deletions github/git_commits.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
package github

import (
"bytes"
"context"
"errors"
"fmt"
"strings"
"time"

"golang.org/x/crypto/openpgp"
)

// SignatureVerification represents GPG signature verification.
Expand Down Expand Up @@ -37,6 +42,11 @@ type Commit struct {
// is only populated for requests that fetch GitHub data like
// Pulls.ListCommits, Repositories.ListCommits, etc.
CommentCount *int `json:"comment_count,omitempty"`

// SigningKey denotes a key to sign the commit with. If not nil this key will
// be used to sign the commit. The private key must be present and already
// decrypted. Ignored if Verification.Signature is defined.
SigningKey *openpgp.Entity `json:"-"`
}

func (c Commit) String() string {
Expand Down Expand Up @@ -116,6 +126,13 @@ func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string
if commit.Tree != nil {
body.Tree = commit.Tree.SHA
}
if commit.SigningKey != nil {
signature, err := createSignature(commit.SigningKey, body)
if err != nil {
return nil, nil, err
}
body.Signature = &signature
}
if commit.Verification != nil {
body.Signature = commit.Verification.Signature
}
Expand All @@ -133,3 +150,51 @@ func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string

return c, resp, nil
}

func createSignature(signingKey *openpgp.Entity, commit *createCommit) (string, error) {
if signingKey == nil || commit == nil {
return "", errors.New("createSignature: invalid parameters")
}

message, err := createSignatureMessage(commit)
if err != nil {
return "", err
}

writer := new(bytes.Buffer)
reader := bytes.NewReader([]byte(message))
if err := openpgp.ArmoredDetachSign(writer, signingKey, reader, nil); err != nil {
return "", err
}

return writer.String(), nil
}

func createSignatureMessage(commit *createCommit) (string, error) {
if commit == nil || commit.Message == nil || *commit.Message == "" || commit.Author == nil {
return "", errors.New("createSignatureMessage: invalid parameters")
}

var message []string

if commit.Tree != nil {
message = append(message, fmt.Sprintf("tree %s", *commit.Tree))
}

for _, parent := range commit.Parents {
message = append(message, fmt.Sprintf("parent %s", parent))
}

message = append(message, fmt.Sprintf("author %s <%s> %d %s", commit.Author.GetName(), commit.Author.GetEmail(), commit.Author.GetDate().Unix(), commit.Author.GetDate().Format("-0700")))

committer := commit.Committer
if committer == nil {
committer = commit.Author
}
anandkumarpatel marked this conversation as resolved.
Show resolved Hide resolved

// There needs to be a double newline after committer
message = append(message, fmt.Sprintf("committer %s <%s> %d %s\n", committer.GetName(), committer.GetEmail(), committer.GetDate().Unix(), committer.GetDate().Format("-0700")))
anandkumarpatel marked this conversation as resolved.
Show resolved Hide resolved
message = append(message, *commit.Message)

return strings.Join(message, "\n"), nil
}
Loading