From e006a637a6c2d346843585e2caab206d3816b297 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Wed, 10 Aug 2022 01:36:50 +0300 Subject: [PATCH 01/20] feat(gitaly-git2go): sign commits with OpenPGP key --- cmd/gitaly-git2go/apply.go | 32 ++++++++++++++------ cmd/gitaly-git2go/cherry_pick.go | 22 +++++++++++--- cmd/gitaly-git2go/commit/commit.go | 24 ++++++++++----- cmd/gitaly-git2go/git2goutil/sign.go | 41 ++++++++++++++++++++++++++ cmd/gitaly-git2go/merge.go | 29 +++++++++++++----- cmd/gitaly-git2go/resolve_conflicts.go | 30 ++++++++++++++----- cmd/gitaly-git2go/revert.go | 22 +++++++++++--- go.mod | 2 +- 8 files changed, 162 insertions(+), 40 deletions(-) create mode 100644 cmd/gitaly-git2go/git2goutil/sign.go diff --git a/cmd/gitaly-git2go/apply.go b/cmd/gitaly-git2go/apply.go index 3a7f65b793..c0f9e397db 100644 --- a/cmd/gitaly-git2go/apply.go +++ b/cmd/gitaly-git2go/apply.go @@ -126,30 +126,44 @@ func (cmd *applySubcommand) applyPatch( } } - patchedTree, err := patchedIndex.WriteTreeTo(repo) + patchedTreeOID, err := patchedIndex.WriteTreeTo(repo) if err != nil { return nil, fmt.Errorf("write patched tree: %w", err) } + patchedTree, err := repo.LookupTree(patchedTreeOID) + if err != nil { + return nil, fmt.Errorf("lookup tree: %w", err) + } author := git.Signature(patch.Author) - patchedCommitOID, err := repo.CreateCommitFromIds("", &author, committer, patch.Message, patchedTree, parentCommitOID) + commitBytes, err := repo.CreateCommitBuffer(&author, committer, git.MessageEncodingUTF8, patch.Message, patchedTree, parentCommit) + if err != nil { + return nil, fmt.Errorf("create commit buffer: %w", err) + } + + signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) + if err != nil { + return nil, fmt.Errorf("read openpgp key: %w", err) + } + + patchedCommitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") if err != nil { return nil, fmt.Errorf("create commit: %w", err) } - return patchedCommitOID, nil + return patchedCommitID, nil } // threeWayMerge attempts a three-way merge as a fallback if applying the patch fails. // Fallback three-way merge is only possible if the patch records the pre-image blobs // and the repository contains them. It works as follows: // -// 1. An index that contains only the pre-image blobs of the patch is built. This is done -// by calling `git apply --build-fake-ancestor`. The tree of the index is the fake -// ancestor tree. -// 2. The fake ancestor tree is patched to produce the post-image tree of the patch. -// 3. Three-way merge is performed with fake ancestor tree as the common ancestor, the -// base commit's tree as our tree and the patched fake ancestor tree as their tree. +// 1. An index that contains only the pre-image blobs of the patch is built. This is done +// by calling `git apply --build-fake-ancestor`. The tree of the index is the fake +// ancestor tree. +// 2. The fake ancestor tree is patched to produce the post-image tree of the patch. +// 3. Three-way merge is performed with fake ancestor tree as the common ancestor, the +// base commit's tree as our tree and the patched fake ancestor tree as their tree. func (cmd *applySubcommand) threeWayMerge( ctx context.Context, repo *git.Repository, diff --git a/cmd/gitaly-git2go/cherry_pick.go b/cmd/gitaly-git2go/cherry_pick.go index ebf29759f1..ab0060bb85 100644 --- a/cmd/gitaly-git2go/cherry_pick.go +++ b/cmd/gitaly-git2go/cherry_pick.go @@ -102,21 +102,35 @@ func (cmd *cherryPickSubcommand) cherryPick(ctx context.Context, r *git2go.Cherr } } - tree, err := index.WriteTreeTo(repo) + treeOID, err := index.WriteTreeTo(repo) if err != nil { return "", fmt.Errorf("could not write tree: %w", err) } + tree, err := repo.LookupTree(treeOID) + if err != nil { + return "", fmt.Errorf("lookup tree: %w", err) + } - if tree.Equal(ours.TreeId()) { + if treeOID.Equal(ours.TreeId()) { return "", git2go.EmptyError{} } committer := git.Signature(git2go.NewSignature(r.CommitterName, r.CommitterMail, r.CommitterDate)) - commit, err := repo.CreateCommitFromIds("", pick.Author(), &committer, r.Message, tree, ours.Id()) + commitBytes, err := repo.CreateCommitBuffer(pick.Author(), &committer, git.MessageEncodingUTF8, r.Message, tree, ours) if err != nil { return "", fmt.Errorf("could not create cherry-pick commit: %w", err) } - return commit.String(), nil + signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } + + commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + if err != nil { + return "", fmt.Errorf("create commit: %w", err) + } + + return commitID.String(), nil } diff --git a/cmd/gitaly-git2go/commit/commit.go b/cmd/gitaly-git2go/commit/commit.go index 57ca1f5865..9e3be63308 100644 --- a/cmd/gitaly-git2go/commit/commit.go +++ b/cmd/gitaly-git2go/commit/commit.go @@ -38,20 +38,20 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { return "", fmt.Errorf("new index: %w", err) } - var parents []*git.Oid + var parents []*git.Commit if params.Parent != "" { parentOID, err := git.NewOid(params.Parent) if err != nil { return "", fmt.Errorf("parse base commit oid: %w", err) } - parents = []*git.Oid{parentOID} - baseCommit, err := repo.LookupCommit(parentOID) if err != nil { return "", fmt.Errorf("lookup commit: %w", err) } + parents = []*git.Commit{baseCommit} + baseTree, err := baseCommit.Tree() if err != nil { return "", fmt.Errorf("lookup tree: %w", err) @@ -76,15 +76,25 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { if err != nil { return "", fmt.Errorf("write tree: %w", err) } + tree, err := repo.LookupTree(treeOID) + if err != nil { + return "", fmt.Errorf("lookup tree: %w", err) + } author := git.Signature(params.Author) committer := git.Signature(params.Committer) - commitID, err := repo.CreateCommitFromIds("", &author, &committer, params.Message, treeOID, parents...) + commitBytes, err := repo.CreateCommitBuffer(&author, &committer, git.MessageEncodingUTF8, params.Message, tree, parents...) if err != nil { - if git.IsErrorClass(err, git.ErrorClassInvalid) { - return "", git2go.InvalidArgumentError(err.Error()) - } + return "", fmt.Errorf("create commit buffer: %w", err) + } + signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } + + commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + if err != nil { return "", fmt.Errorf("create commit: %w", err) } diff --git a/cmd/gitaly-git2go/git2goutil/sign.go b/cmd/gitaly-git2go/git2goutil/sign.go new file mode 100644 index 0000000000..e15b9f0f53 --- /dev/null +++ b/cmd/gitaly-git2go/git2goutil/sign.go @@ -0,0 +1,41 @@ +package git2goutil + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "strings" + + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/packet" +) + +// ReadKeyAndSign reads OpenPGP key and produces PKCS#7 detached signature. +func ReadKeyAndSign(contentToSign string) (string, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("get home dir: %w", err) + } + file, err := os.Open(filepath.Join(homeDir, "key.pem")) + if err != nil { + return "", fmt.Errorf("open file: %w", err) + } + + entity, err := openpgp.ReadEntity(packet.NewReader(file)) + if err != nil { + return "", fmt.Errorf("read entity: %w", err) + } + + sigBuf := new(bytes.Buffer) + if err := openpgp.ArmoredDetachSignText( + sigBuf, + entity, + strings.NewReader(contentToSign), + &packet.Config{}, + ); err != nil { + return "", fmt.Errorf("sign commit: %w", err) + } + + return sigBuf.String(), nil +} diff --git a/cmd/gitaly-git2go/merge.go b/cmd/gitaly-git2go/merge.go index 4ab3ef9fda..7d1e357e1f 100644 --- a/cmd/gitaly-git2go/merge.go +++ b/cmd/gitaly-git2go/merge.go @@ -86,10 +86,14 @@ func merge(request git2go.MergeCommand) (string, error) { } } - tree, err := index.WriteTreeTo(repo) + treeOID, err := index.WriteTreeTo(repo) if err != nil { return "", fmt.Errorf("could not write tree: %w", err) } + tree, err := repo.LookupTree(treeOID) + if err != nil { + return "", fmt.Errorf("lookup tree: %w", err) + } author := git.Signature(git2go.NewSignature(request.AuthorName, request.AuthorMail, request.AuthorDate)) committer := author @@ -97,18 +101,29 @@ func merge(request git2go.MergeCommand) (string, error) { committer = git.Signature(git2go.NewSignature(request.CommitterName, request.CommitterMail, request.CommitterDate)) } - var parents []*git.Oid + var parents []*git.Commit if request.Squash { - parents = []*git.Oid{ours.Id()} + parents = []*git.Commit{ours} } else { - parents = []*git.Oid{ours.Id(), theirs.Id()} + parents = []*git.Commit{ours, theirs} + } + + commitBytes, err := repo.CreateCommitBuffer(&author, &committer, git.MessageEncodingUTF8, request.Message, tree, parents...) + if err != nil { + return "", fmt.Errorf("create commit buffer: %w", err) } - commit, err := repo.CreateCommitFromIds("", &author, &committer, request.Message, tree, parents...) + + signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } + + commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") if err != nil { - return "", fmt.Errorf("could not create merge commit: %w", err) + return "", fmt.Errorf("create commit: %w", err) } - return commit.String(), nil + return commitID.String(), nil } func resolveConflicts(repo *git.Repository, index *git.Index) error { diff --git a/cmd/gitaly-git2go/resolve_conflicts.go b/cmd/gitaly-git2go/resolve_conflicts.go index 73062eb178..52a99d8c01 100644 --- a/cmd/gitaly-git2go/resolve_conflicts.go +++ b/cmd/gitaly-git2go/resolve_conflicts.go @@ -118,7 +118,7 @@ func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encode } if r.Content != "" && bytes.Equal([]byte(r.Content), mfr.Contents) { - return fmt.Errorf("Resolved content has no changes for file %s", r.NewPath) //nolint + return fmt.Errorf("Resolved content has no changes for file %s", r.NewPath) // nolint } conflictFile, err := conflict.Parse( @@ -177,29 +177,43 @@ func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encode conflictPaths = append(conflictPaths, conflictingPath) } - return fmt.Errorf("Missing resolutions for the following files: %s", strings.Join(conflictPaths, ", ")) //nolint + return fmt.Errorf("Missing resolutions for the following files: %s", strings.Join(conflictPaths, ", ")) // nolint } - tree, err := index.WriteTreeTo(repo) + treeOID, err := index.WriteTreeTo(repo) if err != nil { return fmt.Errorf("write tree to repo: %w", err) } + tree, err := repo.LookupTree(treeOID) + if err != nil { + return fmt.Errorf("lookup tree: %w", err) + } - signature := git2go.NewSignature(request.AuthorName, request.AuthorMail, request.AuthorDate) + sign := git2go.NewSignature(request.AuthorName, request.AuthorMail, request.AuthorDate) committer := &git.Signature{ - Name: signature.Name, - Email: signature.Email, + Name: sign.Name, + Email: sign.Email, When: request.AuthorDate, } - commit, err := repo.CreateCommitFromIds("", committer, committer, request.Message, tree, ours.Id(), theirs.Id()) + commitBytes, err := repo.CreateCommitBuffer(committer, committer, git.MessageEncodingUTF8, request.Message, tree, ours, theirs) if err != nil { return fmt.Errorf("could not create resolve conflict commit: %w", err) } + signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) + if err != nil { + return fmt.Errorf("read openpgp key: %w", err) + } + + commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + if err != nil { + return fmt.Errorf("create commit: %w", err) + } + response := git2go.ResolveResult{ MergeResult: git2go.MergeResult{ - CommitID: commit.String(), + CommitID: commitID.String(), }, } diff --git a/cmd/gitaly-git2go/revert.go b/cmd/gitaly-git2go/revert.go index aaeeb00ac9..030f1d7cf3 100644 --- a/cmd/gitaly-git2go/revert.go +++ b/cmd/gitaly-git2go/revert.go @@ -85,20 +85,34 @@ func (cmd *revertSubcommand) revert(ctx context.Context, request *git2go.RevertC return "", git2go.HasConflictsError{} } - tree, err := index.WriteTreeTo(repo) + treeOID, err := index.WriteTreeTo(repo) if err != nil { return "", fmt.Errorf("write tree: %w", err) } + tree, err := repo.LookupTree(treeOID) + if err != nil { + return "", fmt.Errorf("lookup tree: %w", err) + } - if tree.Equal(ours.TreeId()) { + if treeOID.Equal(ours.TreeId()) { return "", git2go.EmptyError{} } committer := git.Signature(git2go.NewSignature(request.AuthorName, request.AuthorMail, request.AuthorDate)) - commit, err := repo.CreateCommitFromIds("", &committer, &committer, request.Message, tree, ours.Id()) + commitBytes, err := repo.CreateCommitBuffer(&committer, &committer, git.MessageEncodingUTF8, request.Message, tree, ours) if err != nil { return "", fmt.Errorf("create revert commit: %w", err) } - return commit.String(), nil + signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } + + commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + if err != nil { + return "", fmt.Errorf("create commit: %w", err) + } + + return commitID.String(), nil } diff --git a/go.mod b/go.mod index 6c8052627a..bfa2bba278 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( gitlab.com/gitlab-org/labkit v1.16.0 go.uber.org/goleak v1.1.12 gocloud.dev v0.25.0 + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 golang.org/x/time v0.0.0-20220609170525-579cf78fd858 @@ -160,7 +161,6 @@ require ( github.com/xanzy/ssh-agent v0.3.0 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.9.0 // indirect - golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect -- GitLab From 587e845bbea7cf23cd33769a421c5a2e90a87759 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Wed, 10 Aug 2022 02:51:56 +0300 Subject: [PATCH 02/20] feat(gitaly-git2go): add key.der to testdata --- cmd/gitaly-git2go/git2goutil/sign.go | 2 +- internal/testhelper/testdata/home/key.der | Bin 0 -> 3679 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 internal/testhelper/testdata/home/key.der diff --git a/cmd/gitaly-git2go/git2goutil/sign.go b/cmd/gitaly-git2go/git2goutil/sign.go index e15b9f0f53..c7101afd8d 100644 --- a/cmd/gitaly-git2go/git2goutil/sign.go +++ b/cmd/gitaly-git2go/git2goutil/sign.go @@ -17,7 +17,7 @@ func ReadKeyAndSign(contentToSign string) (string, error) { if err != nil { return "", fmt.Errorf("get home dir: %w", err) } - file, err := os.Open(filepath.Join(homeDir, "key.pem")) + file, err := os.Open(filepath.Join(homeDir, "key.der")) if err != nil { return "", fmt.Errorf("open file: %w", err) } diff --git a/internal/testhelper/testdata/home/key.der b/internal/testhelper/testdata/home/key.der new file mode 100644 index 0000000000000000000000000000000000000000..c60b2dc15b0fef96e1d687b41eb6d9bc29c18f6e GIT binary patch literal 3679 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 Y9;TwFd_S{&s(c Date: Thu, 11 Aug 2022 00:32:33 +0300 Subject: [PATCH 03/20] feat(gitaly-git2go): sign commits with OpenPGP key, part 2 --- cmd/gitaly-git2go/apply.go | 13 +++++++++---- cmd/gitaly-git2go/cherry_pick.go | 17 ++++++++++++----- cmd/gitaly-git2go/commit.go | 15 ++++++++++++--- cmd/gitaly-git2go/commit/commit.go | 18 +++++++++++++++--- cmd/gitaly-git2go/git2goutil/commit.go | 3 +++ cmd/gitaly-git2go/git2goutil/sign.go | 11 +++-------- cmd/gitaly-git2go/main.go | 2 +- cmd/gitaly-git2go/merge.go | 22 ++++++++++++++-------- cmd/gitaly-git2go/resolve_conflicts.go | 17 ++++++++++++----- cmd/gitaly-git2go/revert.go | 17 ++++++++++++----- internal/gitaly/config/config.go | 6 ++++-- 11 files changed, 97 insertions(+), 44 deletions(-) create mode 100644 cmd/gitaly-git2go/git2goutil/commit.go diff --git a/cmd/gitaly-git2go/apply.go b/cmd/gitaly-git2go/apply.go index c0f9e397db..0f620c0096 100644 --- a/cmd/gitaly-git2go/apply.go +++ b/cmd/gitaly-git2go/apply.go @@ -42,12 +42,14 @@ func (iter *patchIterator) Value() git2go.Patch { return iter.value } func (iter *patchIterator) Err() error { return iter.error } type applySubcommand struct { - gitBinaryPath string + gitBinaryPath string + signingKeyPath string } func (cmd *applySubcommand) Flags() *flag.FlagSet { fs := flag.NewFlagSet("apply", flag.ExitOnError) fs.StringVar(&cmd.gitBinaryPath, "git-binary-path", "", "Path to the Git binary.") + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") return fs } @@ -141,9 +143,12 @@ func (cmd *applySubcommand) applyPatch( return nil, fmt.Errorf("create commit buffer: %w", err) } - signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) - if err != nil { - return nil, fmt.Errorf("read openpgp key: %w", err) + var signature string + if cmd.signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) + if err != nil { + return nil, fmt.Errorf("read openpgp key: %w", err) + } } patchedCommitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") diff --git a/cmd/gitaly-git2go/cherry_pick.go b/cmd/gitaly-git2go/cherry_pick.go index ab0060bb85..a34f2c89a8 100644 --- a/cmd/gitaly-git2go/cherry_pick.go +++ b/cmd/gitaly-git2go/cherry_pick.go @@ -14,10 +14,14 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type cherryPickSubcommand struct{} +type cherryPickSubcommand struct { + signingKeyPath string +} func (cmd *cherryPickSubcommand) Flags() *flag.FlagSet { - return flag.NewFlagSet("cherry-pick", flag.ExitOnError) + fs := flag.NewFlagSet("cherry-pick", flag.ExitOnError) + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") + return fs } func (cmd *cherryPickSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -122,9 +126,12 @@ func (cmd *cherryPickSubcommand) cherryPick(ctx context.Context, r *git2go.Cherr return "", fmt.Errorf("could not create cherry-pick commit: %w", err) } - signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) + var signature string + if cmd.signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } } commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") diff --git a/cmd/gitaly-git2go/commit.go b/cmd/gitaly-git2go/commit.go index cd0a1a31db..36e62aecfa 100644 --- a/cmd/gitaly-git2go/commit.go +++ b/cmd/gitaly-git2go/commit.go @@ -10,10 +10,19 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/cmd/gitaly-git2go/commit" ) -type commitSubcommand struct{} +type SigningKeyPathKey struct{} -func (commitSubcommand) Flags() *flag.FlagSet { return flag.NewFlagSet("commit", flag.ExitOnError) } +type commitSubcommand struct { + signingKeyPath string +} + +func (cmd *commitSubcommand) Flags() *flag.FlagSet { + fs := flag.NewFlagSet("commit", flag.ExitOnError) + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") + return fs +} -func (commitSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { +func (cmd *commitSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { + ctx = context.WithValue(ctx, SigningKeyPathKey{}, cmd.signingKeyPath) return commit.Run(ctx, decoder, encoder) } diff --git a/cmd/gitaly-git2go/commit/commit.go b/cmd/gitaly-git2go/commit/commit.go index 9e3be63308..77a64f263b 100644 --- a/cmd/gitaly-git2go/commit/commit.go +++ b/cmd/gitaly-git2go/commit/commit.go @@ -88,9 +88,13 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { return "", fmt.Errorf("create commit buffer: %w", err) } - signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) + var signature string + signingKeyPath := signingKeyPathFromContext(ctx) + if signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(signingKeyPath, string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } } commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") @@ -119,3 +123,11 @@ func apply(action git2go.Action, repo *git.Repository, index *git.Index) error { return errors.New("unsupported action") } } + +func signingKeyPathFromContext(ctx context.Context) string { + signingKeyPath, ok := ctx.Value(git2goutil.SigningKeyPathKey{}).(string) + if !ok { + return "" + } + return signingKeyPath +} diff --git a/cmd/gitaly-git2go/git2goutil/commit.go b/cmd/gitaly-git2go/git2goutil/commit.go new file mode 100644 index 0000000000..fafcb21dda --- /dev/null +++ b/cmd/gitaly-git2go/git2goutil/commit.go @@ -0,0 +1,3 @@ +package git2goutil + +type SigningKeyPathKey struct{} diff --git a/cmd/gitaly-git2go/git2goutil/sign.go b/cmd/gitaly-git2go/git2goutil/sign.go index c7101afd8d..4fecdae25b 100644 --- a/cmd/gitaly-git2go/git2goutil/sign.go +++ b/cmd/gitaly-git2go/git2goutil/sign.go @@ -4,20 +4,15 @@ import ( "bytes" "fmt" "os" - "path/filepath" "strings" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" ) -// ReadKeyAndSign reads OpenPGP key and produces PKCS#7 detached signature. -func ReadKeyAndSign(contentToSign string) (string, error) { - homeDir, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("get home dir: %w", err) - } - file, err := os.Open(filepath.Join(homeDir, "key.der")) +// ReadSigningKeyAndSign reads OpenPGP key and produces PKCS#7 detached signature. +func ReadSigningKeyAndSign(signingKeyPath, contentToSign string) (string, error) { + file, err := os.Open(signingKeyPath) if err != nil { return "", fmt.Errorf("open file: %w", err) } diff --git a/cmd/gitaly-git2go/main.go b/cmd/gitaly-git2go/main.go index e8a2c2c7b8..8ee0e7fd02 100644 --- a/cmd/gitaly-git2go/main.go +++ b/cmd/gitaly-git2go/main.go @@ -27,7 +27,7 @@ type subcmd interface { var subcommands = map[string]subcmd{ "apply": &applySubcommand{}, "cherry-pick": &cherryPickSubcommand{}, - "commit": commitSubcommand{}, + "commit": &commitSubcommand{}, "conflicts": &conflictsSubcommand{}, "merge": &mergeSubcommand{}, "rebase": &rebaseSubcommand{}, diff --git a/cmd/gitaly-git2go/merge.go b/cmd/gitaly-git2go/merge.go index 7d1e357e1f..f1139b5573 100644 --- a/cmd/gitaly-git2go/merge.go +++ b/cmd/gitaly-git2go/merge.go @@ -15,11 +15,14 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type mergeSubcommand struct{} +type mergeSubcommand struct { + signingKeyPath string +} func (cmd *mergeSubcommand) Flags() *flag.FlagSet { - flags := flag.NewFlagSet("merge", flag.ExitOnError) - return flags + fs := flag.NewFlagSet("merge", flag.ExitOnError) + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") + return fs } func (cmd *mergeSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -32,7 +35,7 @@ func (cmd *mergeSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder request.AuthorDate = time.Now() } - commitID, err := merge(request) + commitID, err := cmd.merge(request) return encoder.Encode(git2go.Result{ CommitID: commitID, @@ -40,7 +43,7 @@ func (cmd *mergeSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder }) } -func merge(request git2go.MergeCommand) (string, error) { +func (cmd *mergeSubcommand) merge(request git2go.MergeCommand) (string, error) { repo, err := git2goutil.OpenRepository(request.Repository) if err != nil { return "", fmt.Errorf("could not open repository: %w", err) @@ -113,9 +116,12 @@ func merge(request git2go.MergeCommand) (string, error) { return "", fmt.Errorf("create commit buffer: %w", err) } - signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) + var signature string + if cmd.signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } } commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") diff --git a/cmd/gitaly-git2go/resolve_conflicts.go b/cmd/gitaly-git2go/resolve_conflicts.go index 52a99d8c01..a356b1cf71 100644 --- a/cmd/gitaly-git2go/resolve_conflicts.go +++ b/cmd/gitaly-git2go/resolve_conflicts.go @@ -18,10 +18,14 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type resolveSubcommand struct{} +type resolveSubcommand struct { + signingKeyPath string +} func (cmd *resolveSubcommand) Flags() *flag.FlagSet { - return flag.NewFlagSet("resolve", flag.ExitOnError) + fs := flag.NewFlagSet("resolve", flag.ExitOnError) + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") + return fs } func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -201,9 +205,12 @@ func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encode return fmt.Errorf("could not create resolve conflict commit: %w", err) } - signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) - if err != nil { - return fmt.Errorf("read openpgp key: %w", err) + var signature string + if cmd.signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) + if err != nil { + return fmt.Errorf("read openpgp key: %w", err) + } } commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") diff --git a/cmd/gitaly-git2go/revert.go b/cmd/gitaly-git2go/revert.go index 030f1d7cf3..a3f1002a74 100644 --- a/cmd/gitaly-git2go/revert.go +++ b/cmd/gitaly-git2go/revert.go @@ -14,10 +14,14 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type revertSubcommand struct{} +type revertSubcommand struct { + signingKeyPath string +} func (cmd *revertSubcommand) Flags() *flag.FlagSet { - return flag.NewFlagSet("revert", flag.ExitOnError) + fs := flag.NewFlagSet("revert", flag.ExitOnError) + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") + return fs } func (cmd *revertSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -104,9 +108,12 @@ func (cmd *revertSubcommand) revert(ctx context.Context, request *git2go.RevertC return "", fmt.Errorf("create revert commit: %w", err) } - signature, err := git2goutil.ReadKeyAndSign(string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) + var signature string + if cmd.signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) + if err != nil { + return "", fmt.Errorf("read openpgp key: %w", err) + } } commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") diff --git a/internal/gitaly/config/config.go b/internal/gitaly/config/config.go index bba1e7d40f..701245cdba 100644 --- a/internal/gitaly/config/config.go +++ b/internal/gitaly/config/config.go @@ -92,7 +92,7 @@ type Hooks struct { CustomHooksDir string `toml:"custom_hooks_dir" json:"custom_hooks_dir"` } -//nolint: revive,stylecheck // This is unintentionally missing documentation. +// nolint: revive,stylecheck // This is unintentionally missing documentation. type HTTPSettings struct { ReadTimeout int `toml:"read_timeout" json:"read_timeout"` User string `toml:"user" json:"user"` @@ -108,6 +108,7 @@ type Git struct { CatfileCacheSize int `toml:"catfile_cache_size"` Config []GitConfig `toml:"config"` IgnoreGitconfig bool `toml:"ignore_gitconfig"` + WebSigningKey string `toml:"web_signing_key"` } // GitConfig contains a key-value pair which is to be passed to git as configuration. @@ -174,7 +175,8 @@ type StreamCacheConfig struct { } // Load initializes the Config variable from file and the environment. -// Environment variables take precedence over the file. +// +// Environment variables take precedence over the file. func Load(file io.Reader) (Cfg, error) { cfg := Cfg{ Prometheus: prometheus.DefaultConfig(), -- GitLab From 6318220be2331a1ce56e36ec92c2ef6aab584817 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 11 Aug 2022 01:55:54 +0300 Subject: [PATCH 04/20] fix(gitaly-git2go): fix existing tests --- cmd/gitaly-git2go/cherry_pick.go | 4 ++-- cmd/gitaly-git2go/commit/commit.go | 4 ++++ cmd/gitaly-git2go/merge.go | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/gitaly-git2go/cherry_pick.go b/cmd/gitaly-git2go/cherry_pick.go index a34f2c89a8..79fa90556d 100644 --- a/cmd/gitaly-git2go/cherry_pick.go +++ b/cmd/gitaly-git2go/cherry_pick.go @@ -123,7 +123,7 @@ func (cmd *cherryPickSubcommand) cherryPick(ctx context.Context, r *git2go.Cherr commitBytes, err := repo.CreateCommitBuffer(pick.Author(), &committer, git.MessageEncodingUTF8, r.Message, tree, ours) if err != nil { - return "", fmt.Errorf("could not create cherry-pick commit: %w", err) + return "", fmt.Errorf("could not create cherry-pick commit buffer: %w", err) } var signature string @@ -136,7 +136,7 @@ func (cmd *cherryPickSubcommand) cherryPick(ctx context.Context, r *git2go.Cherr commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") if err != nil { - return "", fmt.Errorf("create commit: %w", err) + return "", fmt.Errorf("create not create cherry-pick commit: %w", err) } return commitID.String(), nil diff --git a/cmd/gitaly-git2go/commit/commit.go b/cmd/gitaly-git2go/commit/commit.go index 77a64f263b..4ba4eb22d6 100644 --- a/cmd/gitaly-git2go/commit/commit.go +++ b/cmd/gitaly-git2go/commit/commit.go @@ -85,6 +85,10 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { committer := git.Signature(params.Committer) commitBytes, err := repo.CreateCommitBuffer(&author, &committer, git.MessageEncodingUTF8, params.Message, tree, parents...) if err != nil { + if git.IsErrorClass(err, git.ErrorClassInvalid) { + return "", git2go.InvalidArgumentError(err.Error()) + } + return "", fmt.Errorf("create commit buffer: %w", err) } diff --git a/cmd/gitaly-git2go/merge.go b/cmd/gitaly-git2go/merge.go index f1139b5573..f97407e7b5 100644 --- a/cmd/gitaly-git2go/merge.go +++ b/cmd/gitaly-git2go/merge.go @@ -113,7 +113,7 @@ func (cmd *mergeSubcommand) merge(request git2go.MergeCommand) (string, error) { commitBytes, err := repo.CreateCommitBuffer(&author, &committer, git.MessageEncodingUTF8, request.Message, tree, parents...) if err != nil { - return "", fmt.Errorf("create commit buffer: %w", err) + return "", fmt.Errorf("could not create merge commit buffer: %w", err) } var signature string @@ -126,7 +126,7 @@ func (cmd *mergeSubcommand) merge(request git2go.MergeCommand) (string, error) { commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") if err != nil { - return "", fmt.Errorf("create commit: %w", err) + return "", fmt.Errorf("could not create merge commit: %w", err) } return commitID.String(), nil -- GitLab From e85449e8bc9551dbe0b0ef149102d835d921ec41 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 11 Aug 2022 04:03:56 +0300 Subject: [PATCH 05/20] feat(gitaly-git2go): sign commits with OpenPGP key, part 3 --- cmd/gitaly-git2go/commit.go | 1 + cmd/gitaly-git2go/conflicts.go | 2 +- cmd/gitaly-git2go/submodule.go | 28 ++++++++++++++---- internal/git2go/apply.go | 7 ++++- internal/git2go/cherry_pick.go | 9 ++++-- internal/git2go/commit.go | 7 ++++- internal/git2go/executor.go | 6 ++-- internal/git2go/merge.go | 7 ++++- internal/git2go/resolve_conflicts.go | 7 ++++- internal/git2go/revert.go | 7 ++++- internal/git2go/submodule.go | 9 ++++-- internal/gitaly/config/config.go | 2 +- .../testdata/home/{key.der => signingKey.gpg} | Bin 13 files changed, 74 insertions(+), 18 deletions(-) rename internal/testhelper/testdata/home/{key.der => signingKey.gpg} (100%) diff --git a/cmd/gitaly-git2go/commit.go b/cmd/gitaly-git2go/commit.go index 36e62aecfa..8b0671fbad 100644 --- a/cmd/gitaly-git2go/commit.go +++ b/cmd/gitaly-git2go/commit.go @@ -10,6 +10,7 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/cmd/gitaly-git2go/commit" ) +// SigningKeyPathKey is a key for a value in context type SigningKeyPathKey struct{} type commitSubcommand struct { diff --git a/cmd/gitaly-git2go/conflicts.go b/cmd/gitaly-git2go/conflicts.go index 1e2fbb4e0e..954483cad9 100644 --- a/cmd/gitaly-git2go/conflicts.go +++ b/cmd/gitaly-git2go/conflicts.go @@ -32,7 +32,7 @@ func (cmd *conflictsSubcommand) Run(_ context.Context, decoder *gob.Decoder, enc return encoder.Encode(res) } -func (conflictsSubcommand) conflicts(request git2go.ConflictsCommand) git2go.ConflictsResult { +func (*conflictsSubcommand) conflicts(request git2go.ConflictsCommand) git2go.ConflictsResult { repo, err := git2goutil.OpenRepository(request.Repository) if err != nil { return conflictError(codes.Internal, fmt.Errorf("could not open repository: %w", err).Error()) diff --git a/cmd/gitaly-git2go/submodule.go b/cmd/gitaly-git2go/submodule.go index 0e52ee3f46..f18cba7a85 100644 --- a/cmd/gitaly-git2go/submodule.go +++ b/cmd/gitaly-git2go/submodule.go @@ -14,10 +14,14 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type submoduleSubcommand struct{} +type submoduleSubcommand struct { + signingKeyPath string +} func (cmd *submoduleSubcommand) Flags() *flag.FlagSet { - return flag.NewFlagSet("submodule", flag.ExitOnError) + fs := flag.NewFlagSet("submodule", flag.ExitOnError) + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") + return fs } func (cmd *submoduleSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -84,7 +88,7 @@ func (cmd *submoduleSubcommand) run(request git2go.SubmoduleCommand) (*git2go.Su } if smEntry.Id.Cmp(smCommitOID) == 0 { - //nolint + // nolint return nil, fmt.Errorf( "The submodule %s is already at %s", request.Submodule, request.CommitSHA, @@ -121,10 +125,11 @@ func (cmd *submoduleSubcommand) run(request git2go.SubmoduleCommand) (*git2go.Su request.AuthorDate, ), ) - newCommitOID, err := repo.CreateCommit( - "", // caller should update branch with hooks + commitBytes, err := repo.CreateCommitBuffer( + // caller should update branch with hooks &committer, &committer, + git.MessageEncodingUTF8, request.Message, newTree, startCommit, @@ -136,6 +141,19 @@ func (cmd *submoduleSubcommand) run(request git2go.SubmoduleCommand) (*git2go.Su ) } + var signature string + if cmd.signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) + if err != nil { + return nil, fmt.Errorf("read openpgp key: %w", err) + } + } + + newCommitOID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + if err != nil { + return nil, fmt.Errorf("create not create cherry-pick commit: %w", err) + } + return &git2go.SubmoduleResult{ CommitID: newCommitOID.String(), }, nil diff --git a/internal/git2go/apply.go b/internal/git2go/apply.go index 2bee128570..5c2b70da20 100644 --- a/internal/git2go/apply.go +++ b/internal/git2go/apply.go @@ -104,8 +104,13 @@ func (b *Executor) Apply(ctx context.Context, repo repository.GitRepo, params Ap execEnv := b.gitCmdFactory.GetExecutionEnvironment(ctx) + args := []string{"-git-binary-path", execEnv.BinaryPath} + if b.signingKey != "" { + args = append(args, "-signing-key", b.signingKey) + } + var result Result - output, err := b.run(ctx, repo, reader, "apply", "-git-binary-path", execEnv.BinaryPath) + output, err := b.run(ctx, repo, reader, "apply", args...) if err != nil { return "", fmt.Errorf("run: %w", err) } diff --git a/internal/git2go/cherry_pick.go b/internal/git2go/cherry_pick.go index 6724d082a5..eab9346225 100644 --- a/internal/git2go/cherry_pick.go +++ b/internal/git2go/cherry_pick.go @@ -28,7 +28,12 @@ type CherryPickCommand struct { Mainline uint } -// CherryPick performs a cherry pick via gitaly-git2go. +// CherryPick performs a cherry-pick via gitaly-git2go. func (b *Executor) CherryPick(ctx context.Context, repo repository.GitRepo, m CherryPickCommand) (git.ObjectID, error) { - return b.runWithGob(ctx, repo, "cherry-pick", m) + var args []string + if b.signingKey != "" { + args = []string{"-signing-key", b.signingKey} + } + + return b.runWithGob(ctx, repo, "cherry-pick", m, args...) } diff --git a/internal/git2go/commit.go b/internal/git2go/commit.go index 13edb4faa0..c7b89861e7 100644 --- a/internal/git2go/commit.go +++ b/internal/git2go/commit.go @@ -66,7 +66,12 @@ func (b *Executor) Commit(ctx context.Context, repo repository.GitRepo, params C return "", err } - output, err := b.run(ctx, repo, input, "commit") + var args []string + if b.signingKey != "" { + args = []string{"-signing-key", b.signingKey} + } + + output, err := b.run(ctx, repo, input, "commit", args...) if err != nil { return "", err } diff --git a/internal/git2go/executor.go b/internal/git2go/executor.go index 30c8ff0a3d..362595b809 100644 --- a/internal/git2go/executor.go +++ b/internal/git2go/executor.go @@ -31,6 +31,7 @@ var ( // Executor executes gitaly-git2go. type Executor struct { binaryPath string + signingKey string gitCmdFactory git.CommandFactory locator storage.Locator logFormat, logLevel string @@ -41,6 +42,7 @@ type Executor struct { func NewExecutor(cfg config.Cfg, gitCmdFactory git.CommandFactory, locator storage.Locator) *Executor { return &Executor{ binaryPath: cfg.BinaryPath(BinaryName), + signingKey: cfg.Git.SigningKey, gitCmdFactory: gitCmdFactory, locator: locator, logFormat: cfg.Logging.Format, @@ -103,13 +105,13 @@ func (b *Executor) run(ctx context.Context, repo repository.GitRepo, stdin io.Re // runWithGob runs the specified gitaly-git2go cmd with the request gob-encoded // as input and returns the commit ID as string or an error. -func (b *Executor) runWithGob(ctx context.Context, repo repository.GitRepo, cmd string, request interface{}) (git.ObjectID, error) { +func (b *Executor) runWithGob(ctx context.Context, repo repository.GitRepo, cmd string, request interface{}, args ...string) (git.ObjectID, error) { input := &bytes.Buffer{} if err := gob.NewEncoder(input).Encode(request); err != nil { return "", fmt.Errorf("%s: %w", cmd, err) } - output, err := b.run(ctx, repo, input, cmd) + output, err := b.run(ctx, repo, input, cmd, args...) if err != nil { return "", fmt.Errorf("%s: %w", cmd, err) } diff --git a/internal/git2go/merge.go b/internal/git2go/merge.go index 7086cfa768..c6074bc1fc 100644 --- a/internal/git2go/merge.go +++ b/internal/git2go/merge.go @@ -61,7 +61,12 @@ func (b *Executor) Merge(ctx context.Context, repo repository.GitRepo, m MergeCo return MergeResult{}, fmt.Errorf("merge: %w: %s", ErrInvalidArgument, err.Error()) } - commitID, err := b.runWithGob(ctx, repo, "merge", m) + var args []string + if b.signingKey != "" { + args = []string{"-signing-key", b.signingKey} + } + + commitID, err := b.runWithGob(ctx, repo, "merge", m, args...) if err != nil { return MergeResult{}, err } diff --git a/internal/git2go/resolve_conflicts.go b/internal/git2go/resolve_conflicts.go index 69d8ed14f9..5f3b16f6f5 100644 --- a/internal/git2go/resolve_conflicts.go +++ b/internal/git2go/resolve_conflicts.go @@ -37,7 +37,12 @@ func (b *Executor) Resolve(ctx context.Context, repo repository.GitRepo, r Resol return ResolveResult{}, fmt.Errorf("resolve: %w", err) } - stdout, err := b.run(ctx, repo, input, "resolve") + var args []string + if b.signingKey != "" { + args = []string{"-signing-key", b.signingKey} + } + + stdout, err := b.run(ctx, repo, input, "resolve", args...) if err != nil { return ResolveResult{}, err } diff --git a/internal/git2go/revert.go b/internal/git2go/revert.go index 7442e1566b..e2c5922e26 100644 --- a/internal/git2go/revert.go +++ b/internal/git2go/revert.go @@ -30,5 +30,10 @@ type RevertCommand struct { // Revert reverts a commit via gitaly-git2go. func (b *Executor) Revert(ctx context.Context, repo repository.GitRepo, r RevertCommand) (git.ObjectID, error) { - return b.runWithGob(ctx, repo, "revert", r) + var args []string + if b.signingKey != "" { + args = []string{"-signing-key", b.signingKey} + } + + return b.runWithGob(ctx, repo, "revert", r, args...) } diff --git a/internal/git2go/submodule.go b/internal/git2go/submodule.go index e420ad5c50..27e442ca28 100644 --- a/internal/git2go/submodule.go +++ b/internal/git2go/submodule.go @@ -57,10 +57,15 @@ func (b *Executor) Submodule(ctx context.Context, repo repository.GitRepo, s Sub return SubmoduleResult{}, fmt.Errorf("%s: %w", cmd, err) } + var args []string + if b.signingKey != "" { + args = []string{"-signing-key", b.signingKey} + } + // Ideally we would use `b.runWithGob` here to avoid the gob encoding - // boilerplate but it is not possible here because `runWithGob` adds error + // boilerplate, but it is not possible here because `runWithGob` adds error // prefixes and the `LegacyErrPrefix*` errors must match exactly. - stdout, err := b.run(ctx, repo, input, cmd) + stdout, err := b.run(ctx, repo, input, cmd, args...) if err != nil { return SubmoduleResult{}, err } diff --git a/internal/gitaly/config/config.go b/internal/gitaly/config/config.go index 701245cdba..21b47884cc 100644 --- a/internal/gitaly/config/config.go +++ b/internal/gitaly/config/config.go @@ -108,7 +108,7 @@ type Git struct { CatfileCacheSize int `toml:"catfile_cache_size"` Config []GitConfig `toml:"config"` IgnoreGitconfig bool `toml:"ignore_gitconfig"` - WebSigningKey string `toml:"web_signing_key"` + SigningKey string `toml:"signing_key"` } // GitConfig contains a key-value pair which is to be passed to git as configuration. diff --git a/internal/testhelper/testdata/home/key.der b/internal/testhelper/testdata/home/signingKey.gpg similarity index 100% rename from internal/testhelper/testdata/home/key.der rename to internal/testhelper/testdata/home/signingKey.gpg -- GitLab From 9c9142377bcd41f0d79d0bd567b6f7dca9ebcd6d Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 11 Aug 2022 13:56:18 +0300 Subject: [PATCH 06/20] fix(gitaly-git2go): go from x/crypto/opengpg to ProtonMail/go-crypto/openpgp --- cmd/gitaly-git2go/git2goutil/commit.go | 1 + cmd/gitaly-git2go/git2goutil/sign.go | 4 ++-- go.mod | 4 +++- go.sum | 5 +++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cmd/gitaly-git2go/git2goutil/commit.go b/cmd/gitaly-git2go/git2goutil/commit.go index fafcb21dda..3aa77b4218 100644 --- a/cmd/gitaly-git2go/git2goutil/commit.go +++ b/cmd/gitaly-git2go/git2goutil/commit.go @@ -1,3 +1,4 @@ package git2goutil +// SigningKeyPathKey is the key for a context value. type SigningKeyPathKey struct{} diff --git a/cmd/gitaly-git2go/git2goutil/sign.go b/cmd/gitaly-git2go/git2goutil/sign.go index 4fecdae25b..39db8a4c74 100644 --- a/cmd/gitaly-git2go/git2goutil/sign.go +++ b/cmd/gitaly-git2go/git2goutil/sign.go @@ -6,8 +6,8 @@ import ( "os" "strings" - "golang.org/x/crypto/openpgp" - "golang.org/x/crypto/openpgp/packet" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/packet" ) // ReadSigningKeyAndSign reads OpenPGP key and produces PKCS#7 detached signature. diff --git a/go.mod b/go.mod index bfa2bba278..1bdff14add 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module gitlab.com/gitlab-org/gitaly/v15 go 1.17 require ( + github.com/ProtonMail/go-crypto v0.0.0-20220810064516-de89276ce0f3 github.com/beevik/ntp v0.3.0 github.com/cloudflare/tableflip v1.2.3 github.com/containerd/cgroups v1.0.4 @@ -35,7 +36,6 @@ require ( gitlab.com/gitlab-org/labkit v1.16.0 go.uber.org/goleak v1.1.12 gocloud.dev v0.25.0 - golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 golang.org/x/time v0.0.0-20220609170525-579cf78fd858 @@ -88,6 +88,7 @@ require ( github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/client9/reopen v1.0.0 // indirect + github.com/cloudflare/circl v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-minhash v0.0.0-20170608043002-7fe510aff544 // indirect @@ -161,6 +162,7 @@ require ( github.com/xanzy/ssh-agent v0.3.0 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.9.0 // indirect + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect diff --git a/go.sum b/go.sum index 0f4534fb3c..a6f30f80b3 100644 --- a/go.sum +++ b/go.sum @@ -169,6 +169,8 @@ github.com/Microsoft/go-winio v0.4.19/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOp github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ProtonMail/go-crypto v0.0.0-20220810064516-de89276ce0f3 h1:JBPdE3yq6D8k8UxTzyCN2uhpHfGKsJEurKLHLU6YBdM= +github.com/ProtonMail/go-crypto v0.0.0-20220810064516-de89276ce0f3/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -260,6 +262,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -281,6 +284,8 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/reopen v1.0.0 h1:8tpLVR74DLpLObrn2KvsyxJY++2iORGR17WLUdSzUws= github.com/client9/reopen v1.0.0/go.mod h1:caXVCEr+lUtoN1FlsRiOWdfQtdRHIYfcb0ai8qKWtkQ= +github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/tableflip v0.0.0-20190329062924-8392f1641731/go.mod h1:erh4dYezoMVbIa52pi7i1Du7+cXOgqNuTamt10qvMoA= github.com/cloudflare/tableflip v1.2.2/go.mod h1:P4gRehmV6Z2bY5ao5ml9Pd8u6kuEnlB37pUFMmv7j2E= github.com/cloudflare/tableflip v1.2.3 h1:8I+B99QnnEWPHOY3fWipwVKxS70LGgUsslG7CSfmHMw= -- GitLab From d60590962c7448619ae6baebb2ec9d3c0146ec26 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 11 Aug 2022 14:13:42 +0300 Subject: [PATCH 07/20] fix: ProtonMail/go-crypto/openpgp license added to NOTICE --- NOTICE | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/NOTICE b/NOTICE index f6b450f8bc..eb4c801ed8 100644 --- a/NOTICE +++ b/NOTICE @@ -2710,6 +2710,36 @@ LICENSE - github.com/Azure/go-autorest/tracing See the License for the specific language governing permissions and limitations under the License. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LICENSE - github.com/ProtonMail/go-crypto +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LICENSE.txt - github.com/aws/aws-sdk-go @@ -6754,6 +6784,66 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LICENSE - github.com/cloudflare/circl +Copyright (c) 2019 Cloudflare. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Cloudflare nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LICENSE - github.com/cloudflare/tableflip Copyright (c) 2017-2018, Cloudflare. All rights reserved. -- GitLab From 467eb29c8ba656efc3ce271165125e31bbf30189 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 11 Aug 2022 14:52:54 +0300 Subject: [PATCH 08/20] fix(gitaly-git2go): context key fix --- cmd/gitaly-git2go/commit.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmd/gitaly-git2go/commit.go b/cmd/gitaly-git2go/commit.go index 8b0671fbad..4ecefde909 100644 --- a/cmd/gitaly-git2go/commit.go +++ b/cmd/gitaly-git2go/commit.go @@ -8,11 +8,9 @@ import ( "flag" "gitlab.com/gitlab-org/gitaly/v15/cmd/gitaly-git2go/commit" + "gitlab.com/gitlab-org/gitaly/v15/cmd/gitaly-git2go/git2goutil" ) -// SigningKeyPathKey is a key for a value in context -type SigningKeyPathKey struct{} - type commitSubcommand struct { signingKeyPath string } @@ -24,6 +22,6 @@ func (cmd *commitSubcommand) Flags() *flag.FlagSet { } func (cmd *commitSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { - ctx = context.WithValue(ctx, SigningKeyPathKey{}, cmd.signingKeyPath) + ctx = context.WithValue(ctx, git2goutil.SigningKeyPathKey{}, cmd.signingKeyPath) return commit.Run(ctx, decoder, encoder) } -- GitLab From 916723c34605182286ff713975e0157682ec1e99 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 11 Aug 2022 16:49:57 +0300 Subject: [PATCH 09/20] fix(gitaly-git2go): nolintlint fix --- cmd/gitaly-git2go/resolve_conflicts.go | 4 ++-- cmd/gitaly-git2go/submodule.go | 2 +- internal/backup/storage_service_sink.go | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/gitaly-git2go/resolve_conflicts.go b/cmd/gitaly-git2go/resolve_conflicts.go index a356b1cf71..1a78a0e30f 100644 --- a/cmd/gitaly-git2go/resolve_conflicts.go +++ b/cmd/gitaly-git2go/resolve_conflicts.go @@ -122,7 +122,7 @@ func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encode } if r.Content != "" && bytes.Equal([]byte(r.Content), mfr.Contents) { - return fmt.Errorf("Resolved content has no changes for file %s", r.NewPath) // nolint + return fmt.Errorf("Resolved content has no changes for file %s", r.NewPath) //nolint } conflictFile, err := conflict.Parse( @@ -181,7 +181,7 @@ func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encode conflictPaths = append(conflictPaths, conflictingPath) } - return fmt.Errorf("Missing resolutions for the following files: %s", strings.Join(conflictPaths, ", ")) // nolint + return fmt.Errorf("Missing resolutions for the following files: %s", strings.Join(conflictPaths, ", ")) //nolint } treeOID, err := index.WriteTreeTo(repo) diff --git a/cmd/gitaly-git2go/submodule.go b/cmd/gitaly-git2go/submodule.go index f18cba7a85..050bc21d7f 100644 --- a/cmd/gitaly-git2go/submodule.go +++ b/cmd/gitaly-git2go/submodule.go @@ -88,7 +88,7 @@ func (cmd *submoduleSubcommand) run(request git2go.SubmoduleCommand) (*git2go.Su } if smEntry.Id.Cmp(smCommitOID) == 0 { - // nolint + //nolint return nil, fmt.Errorf( "The submodule %s is already at %s", request.Submodule, request.CommitSHA, diff --git a/internal/backup/storage_service_sink.go b/internal/backup/storage_service_sink.go index 217fb322b9..ef484624c8 100644 --- a/internal/backup/storage_service_sink.go +++ b/internal/backup/storage_service_sink.go @@ -6,9 +6,9 @@ import ( "io" "gocloud.dev/blob" - _ "gocloud.dev/blob/azureblob" // nolint:nolintlint,golint,gci - _ "gocloud.dev/blob/gcsblob" // nolint:nolintlint,golint,gci - _ "gocloud.dev/blob/s3blob" // nolint:nolintlint,golint,gci + _ "gocloud.dev/blob/azureblob" //nolint:nolintlint,golint,gci + _ "gocloud.dev/blob/gcsblob" //nolint:nolintlint,golint,gci + _ "gocloud.dev/blob/s3blob" //nolint:nolintlint,golint,gci "gocloud.dev/gcerrors" ) -- GitLab From 15c3783548ec5a5a4dcb6d026e1cc1083a5378c2 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 11 Aug 2022 18:07:05 +0300 Subject: [PATCH 10/20] feat(gitaly-git2go): rebase signing support --- cmd/gitaly-git2go/rebase.go | 29 +++++++++++++++++++++++++++-- internal/git2go/rebase.go | 7 ++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/cmd/gitaly-git2go/rebase.go b/cmd/gitaly-git2go/rebase.go index b0638c72e4..59fc75961c 100644 --- a/cmd/gitaly-git2go/rebase.go +++ b/cmd/gitaly-git2go/rebase.go @@ -14,10 +14,14 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type rebaseSubcommand struct{} +type rebaseSubcommand struct { + signingKeyPath string +} func (cmd *rebaseSubcommand) Flags() *flag.FlagSet { - return flag.NewFlagSet("rebase", flag.ExitOnError) + fs := flag.NewFlagSet("rebase", flag.ExitOnError) + fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") + return fs } func (cmd *rebaseSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -73,6 +77,27 @@ func (cmd *rebaseSubcommand) rebase(ctx context.Context, request *git2go.RebaseC return "", fmt.Errorf("get rebase options: %w", err) } opts.InMemory = 1 + opts.CommitCreateCallback = func(author, committer *git.Signature, messageEncoding git.MessageEncoding, message string, tree *git.Tree, parents ...*git.Commit) (oid *git.Oid, err error) { + commitBytes, err := repo.CreateCommitBuffer(author, committer, messageEncoding, message, tree, parents...) + if err != nil { + return nil, fmt.Errorf("create commit buffer: %w", err) + } + + var signature string + if cmd.signingKeyPath != "" { + signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) + if err != nil { + return nil, fmt.Errorf("read openpgp key: %w", err) + } + } + + commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + if err != nil { + return nil, fmt.Errorf("create commit: %w", err) + } + + return commitID, nil + } var commit *git.AnnotatedCommit if request.BranchName != "" { diff --git a/internal/git2go/rebase.go b/internal/git2go/rebase.go index 9cd4ec814f..5d3b4d7a89 100644 --- a/internal/git2go/rebase.go +++ b/internal/git2go/rebase.go @@ -34,5 +34,10 @@ type RebaseCommand struct { // Rebase performs the rebase via gitaly-git2go func (b *Executor) Rebase(ctx context.Context, repo repository.GitRepo, r RebaseCommand) (git.ObjectID, error) { - return b.runWithGob(ctx, repo, "rebase", r) + var args []string + if b.signingKey != "" { + args = []string{"-signing-key", b.signingKey} + } + + return b.runWithGob(ctx, repo, "rebase", r, args...) } -- GitLab From bf32e009061eb59e772f81c0e82698f4cf5f9532 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Wed, 17 Aug 2022 20:42:32 +0300 Subject: [PATCH 11/20] fix: small refactoring and code-style tweaks --- cmd/gitaly-git2go/apply.go | 16 ++------- cmd/gitaly-git2go/cherry_pick.go | 24 +++---------- cmd/gitaly-git2go/commit/commit.go | 17 ++------- cmd/gitaly-git2go/git2goutil/commit.go | 49 ++++++++++++++++++++++++++ cmd/gitaly-git2go/merge.go | 24 +++---------- cmd/gitaly-git2go/rebase.go | 24 +++---------- cmd/gitaly-git2go/resolve_conflicts.go | 16 ++------- cmd/gitaly-git2go/revert.go | 24 +++---------- cmd/gitaly-git2go/submodule.go | 32 ++++++----------- internal/git2go/cherry_pick.go | 9 +++-- internal/git2go/executor.go | 4 +-- internal/git2go/merge.go | 10 +++--- internal/git2go/rebase.go | 9 +++-- internal/git2go/revert.go | 9 +++-- 14 files changed, 99 insertions(+), 168 deletions(-) diff --git a/cmd/gitaly-git2go/apply.go b/cmd/gitaly-git2go/apply.go index 0f620c0096..e5cc1339a8 100644 --- a/cmd/gitaly-git2go/apply.go +++ b/cmd/gitaly-git2go/apply.go @@ -138,20 +138,8 @@ func (cmd *applySubcommand) applyPatch( } author := git.Signature(patch.Author) - commitBytes, err := repo.CreateCommitBuffer(&author, committer, git.MessageEncodingUTF8, patch.Message, patchedTree, parentCommit) - if err != nil { - return nil, fmt.Errorf("create commit buffer: %w", err) - } - - var signature string - if cmd.signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) - if err != nil { - return nil, fmt.Errorf("read openpgp key: %w", err) - } - } - - patchedCommitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + patchedCommitID, err := git2goutil.NewCommitSubmitter(repo, cmd.signingKeyPath). + Commit(&author, committer, git.MessageEncodingUTF8, patch.Message, patchedTree, parentCommit) if err != nil { return nil, fmt.Errorf("create commit: %w", err) } diff --git a/cmd/gitaly-git2go/cherry_pick.go b/cmd/gitaly-git2go/cherry_pick.go index 79fa90556d..1a185a7e25 100644 --- a/cmd/gitaly-git2go/cherry_pick.go +++ b/cmd/gitaly-git2go/cherry_pick.go @@ -14,14 +14,10 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type cherryPickSubcommand struct { - signingKeyPath string -} +type cherryPickSubcommand struct{} func (cmd *cherryPickSubcommand) Flags() *flag.FlagSet { - fs := flag.NewFlagSet("cherry-pick", flag.ExitOnError) - fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") - return fs + return flag.NewFlagSet("cherry-pick", flag.ExitOnError) } func (cmd *cherryPickSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -121,20 +117,8 @@ func (cmd *cherryPickSubcommand) cherryPick(ctx context.Context, r *git2go.Cherr committer := git.Signature(git2go.NewSignature(r.CommitterName, r.CommitterMail, r.CommitterDate)) - commitBytes, err := repo.CreateCommitBuffer(pick.Author(), &committer, git.MessageEncodingUTF8, r.Message, tree, ours) - if err != nil { - return "", fmt.Errorf("could not create cherry-pick commit buffer: %w", err) - } - - var signature string - if cmd.signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) - } - } - - commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + commitID, err := git2goutil.NewCommitSubmitter(repo, r.SigningKey). + Commit(pick.Author(), &committer, git.MessageEncodingUTF8, r.Message, tree, ours) if err != nil { return "", fmt.Errorf("create not create cherry-pick commit: %w", err) } diff --git a/cmd/gitaly-git2go/commit/commit.go b/cmd/gitaly-git2go/commit/commit.go index 4ba4eb22d6..3bfaa48383 100644 --- a/cmd/gitaly-git2go/commit/commit.go +++ b/cmd/gitaly-git2go/commit/commit.go @@ -83,26 +83,13 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { author := git.Signature(params.Author) committer := git.Signature(params.Committer) - commitBytes, err := repo.CreateCommitBuffer(&author, &committer, git.MessageEncodingUTF8, params.Message, tree, parents...) + commitID, err := git2goutil.NewCommitSubmitter(repo, signingKeyPathFromContext(ctx)). + Commit(&author, &committer, git.MessageEncodingUTF8, params.Message, tree, parents...) if err != nil { if git.IsErrorClass(err, git.ErrorClassInvalid) { return "", git2go.InvalidArgumentError(err.Error()) } - return "", fmt.Errorf("create commit buffer: %w", err) - } - - var signature string - signingKeyPath := signingKeyPathFromContext(ctx) - if signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(signingKeyPath, string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) - } - } - - commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") - if err != nil { return "", fmt.Errorf("create commit: %w", err) } diff --git a/cmd/gitaly-git2go/git2goutil/commit.go b/cmd/gitaly-git2go/git2goutil/commit.go index 3aa77b4218..821d049aa8 100644 --- a/cmd/gitaly-git2go/git2goutil/commit.go +++ b/cmd/gitaly-git2go/git2goutil/commit.go @@ -1,4 +1,53 @@ package git2goutil +import ( + "fmt" + + git "github.com/libgit2/git2go/v33" +) + // SigningKeyPathKey is the key for a context value. type SigningKeyPathKey struct{} + +// CommitSubmitter is the helper struct to make signed Commits conveniently. +type CommitSubmitter struct { + Repo *git.Repository + SigningKeyPath string +} + +// NewCommitSubmitter creates a new CommitSubmitter. +func NewCommitSubmitter(repo *git.Repository, signingKeyPath string) *CommitSubmitter { + return &CommitSubmitter{ + Repo: repo, + SigningKeyPath: signingKeyPath, + } +} + +// Commit commits a commit with or without OpenPGP signature depends on SigningKeyPath value. +func (cs *CommitSubmitter) Commit( + author, committer *git.Signature, + messageEncoding git.MessageEncoding, + message string, + tree *git.Tree, + parents ...*git.Commit, +) (*git.Oid, error) { + commitBytes, err := cs.Repo.CreateCommitBuffer(author, committer, messageEncoding, message, tree, parents...) + if err != nil { + return nil, err + } + + var signature string + if cs.SigningKeyPath != "" { + signature, err = ReadSigningKeyAndSign(cs.SigningKeyPath, string(commitBytes)) + if err != nil { + return nil, fmt.Errorf("read openpgp key: %w", err) + } + } + + commitID, err := cs.Repo.CreateCommitWithSignature(string(commitBytes), signature, "") + if err != nil { + return nil, err + } + + return commitID, nil +} diff --git a/cmd/gitaly-git2go/merge.go b/cmd/gitaly-git2go/merge.go index f97407e7b5..21922b24aa 100644 --- a/cmd/gitaly-git2go/merge.go +++ b/cmd/gitaly-git2go/merge.go @@ -15,14 +15,10 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type mergeSubcommand struct { - signingKeyPath string -} +type mergeSubcommand struct{} func (cmd *mergeSubcommand) Flags() *flag.FlagSet { - fs := flag.NewFlagSet("merge", flag.ExitOnError) - fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") - return fs + return flag.NewFlagSet("merge", flag.ExitOnError) } func (cmd *mergeSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -111,20 +107,8 @@ func (cmd *mergeSubcommand) merge(request git2go.MergeCommand) (string, error) { parents = []*git.Commit{ours, theirs} } - commitBytes, err := repo.CreateCommitBuffer(&author, &committer, git.MessageEncodingUTF8, request.Message, tree, parents...) - if err != nil { - return "", fmt.Errorf("could not create merge commit buffer: %w", err) - } - - var signature string - if cmd.signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) - } - } - - commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + commitID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). + Commit(&author, &committer, git.MessageEncodingUTF8, request.Message, tree, parents...) if err != nil { return "", fmt.Errorf("could not create merge commit: %w", err) } diff --git a/cmd/gitaly-git2go/rebase.go b/cmd/gitaly-git2go/rebase.go index 59fc75961c..1447b2a95c 100644 --- a/cmd/gitaly-git2go/rebase.go +++ b/cmd/gitaly-git2go/rebase.go @@ -14,14 +14,10 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type rebaseSubcommand struct { - signingKeyPath string -} +type rebaseSubcommand struct{} func (cmd *rebaseSubcommand) Flags() *flag.FlagSet { - fs := flag.NewFlagSet("rebase", flag.ExitOnError) - fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") - return fs + return flag.NewFlagSet("rebase", flag.ExitOnError) } func (cmd *rebaseSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -78,20 +74,8 @@ func (cmd *rebaseSubcommand) rebase(ctx context.Context, request *git2go.RebaseC } opts.InMemory = 1 opts.CommitCreateCallback = func(author, committer *git.Signature, messageEncoding git.MessageEncoding, message string, tree *git.Tree, parents ...*git.Commit) (oid *git.Oid, err error) { - commitBytes, err := repo.CreateCommitBuffer(author, committer, messageEncoding, message, tree, parents...) - if err != nil { - return nil, fmt.Errorf("create commit buffer: %w", err) - } - - var signature string - if cmd.signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) - if err != nil { - return nil, fmt.Errorf("read openpgp key: %w", err) - } - } - - commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + commitID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). + Commit(author, committer, messageEncoding, message, tree, parents...) if err != nil { return nil, fmt.Errorf("create commit: %w", err) } diff --git a/cmd/gitaly-git2go/resolve_conflicts.go b/cmd/gitaly-git2go/resolve_conflicts.go index 1a78a0e30f..b9f601ad1c 100644 --- a/cmd/gitaly-git2go/resolve_conflicts.go +++ b/cmd/gitaly-git2go/resolve_conflicts.go @@ -200,20 +200,8 @@ func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encode When: request.AuthorDate, } - commitBytes, err := repo.CreateCommitBuffer(committer, committer, git.MessageEncodingUTF8, request.Message, tree, ours, theirs) - if err != nil { - return fmt.Errorf("could not create resolve conflict commit: %w", err) - } - - var signature string - if cmd.signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) - if err != nil { - return fmt.Errorf("read openpgp key: %w", err) - } - } - - commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + commitID, err := git2goutil.NewCommitSubmitter(repo, cmd.signingKeyPath). + Commit(committer, committer, git.MessageEncodingUTF8, request.Message, tree, ours, theirs) if err != nil { return fmt.Errorf("create commit: %w", err) } diff --git a/cmd/gitaly-git2go/revert.go b/cmd/gitaly-git2go/revert.go index a3f1002a74..725502289a 100644 --- a/cmd/gitaly-git2go/revert.go +++ b/cmd/gitaly-git2go/revert.go @@ -14,14 +14,10 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type revertSubcommand struct { - signingKeyPath string -} +type revertSubcommand struct{} func (cmd *revertSubcommand) Flags() *flag.FlagSet { - fs := flag.NewFlagSet("revert", flag.ExitOnError) - fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") - return fs + return flag.NewFlagSet("revert", flag.ExitOnError) } func (cmd *revertSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -103,20 +99,8 @@ func (cmd *revertSubcommand) revert(ctx context.Context, request *git2go.RevertC } committer := git.Signature(git2go.NewSignature(request.AuthorName, request.AuthorMail, request.AuthorDate)) - commitBytes, err := repo.CreateCommitBuffer(&committer, &committer, git.MessageEncodingUTF8, request.Message, tree, ours) - if err != nil { - return "", fmt.Errorf("create revert commit: %w", err) - } - - var signature string - if cmd.signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) - if err != nil { - return "", fmt.Errorf("read openpgp key: %w", err) - } - } - - commitID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") + commitID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). + Commit(&committer, &committer, git.MessageEncodingUTF8, request.Message, tree, ours) if err != nil { return "", fmt.Errorf("create commit: %w", err) } diff --git a/cmd/gitaly-git2go/submodule.go b/cmd/gitaly-git2go/submodule.go index 050bc21d7f..7f255f03fd 100644 --- a/cmd/gitaly-git2go/submodule.go +++ b/cmd/gitaly-git2go/submodule.go @@ -125,15 +125,16 @@ func (cmd *submoduleSubcommand) run(request git2go.SubmoduleCommand) (*git2go.Su request.AuthorDate, ), ) - commitBytes, err := repo.CreateCommitBuffer( - // caller should update branch with hooks - &committer, - &committer, - git.MessageEncodingUTF8, - request.Message, - newTree, - startCommit, - ) + + newCommitOID, err := git2goutil.NewCommitSubmitter(repo, cmd.signingKeyPath). + Commit( + &committer, + &committer, + git.MessageEncodingUTF8, + request.Message, + newTree, + startCommit, + ) if err != nil { return nil, fmt.Errorf( "%s: %w", @@ -141,19 +142,6 @@ func (cmd *submoduleSubcommand) run(request git2go.SubmoduleCommand) (*git2go.Su ) } - var signature string - if cmd.signingKeyPath != "" { - signature, err = git2goutil.ReadSigningKeyAndSign(cmd.signingKeyPath, string(commitBytes)) - if err != nil { - return nil, fmt.Errorf("read openpgp key: %w", err) - } - } - - newCommitOID, err := repo.CreateCommitWithSignature(string(commitBytes), signature, "") - if err != nil { - return nil, fmt.Errorf("create not create cherry-pick commit: %w", err) - } - return &git2go.SubmoduleResult{ CommitID: newCommitOID.String(), }, nil diff --git a/internal/git2go/cherry_pick.go b/internal/git2go/cherry_pick.go index eab9346225..a3754e4d38 100644 --- a/internal/git2go/cherry_pick.go +++ b/internal/git2go/cherry_pick.go @@ -26,14 +26,13 @@ type CherryPickCommand struct { Commit string // Mainline is the parent to be considered the mainline Mainline uint + // SigningKey is a path to the key to sign commit using OpenPGP + SigningKey string } // CherryPick performs a cherry-pick via gitaly-git2go. func (b *Executor) CherryPick(ctx context.Context, repo repository.GitRepo, m CherryPickCommand) (git.ObjectID, error) { - var args []string - if b.signingKey != "" { - args = []string{"-signing-key", b.signingKey} - } + m.SigningKey = b.signingKey - return b.runWithGob(ctx, repo, "cherry-pick", m, args...) + return b.runWithGob(ctx, repo, "cherry-pick", m) } diff --git a/internal/git2go/executor.go b/internal/git2go/executor.go index 362595b809..b97a9f3b0a 100644 --- a/internal/git2go/executor.go +++ b/internal/git2go/executor.go @@ -105,13 +105,13 @@ func (b *Executor) run(ctx context.Context, repo repository.GitRepo, stdin io.Re // runWithGob runs the specified gitaly-git2go cmd with the request gob-encoded // as input and returns the commit ID as string or an error. -func (b *Executor) runWithGob(ctx context.Context, repo repository.GitRepo, cmd string, request interface{}, args ...string) (git.ObjectID, error) { +func (b *Executor) runWithGob(ctx context.Context, repo repository.GitRepo, cmd string, request interface{}) (git.ObjectID, error) { input := &bytes.Buffer{} if err := gob.NewEncoder(input).Encode(request); err != nil { return "", fmt.Errorf("%s: %w", cmd, err) } - output, err := b.run(ctx, repo, input, cmd, args...) + output, err := b.run(ctx, repo, input, cmd) if err != nil { return "", fmt.Errorf("%s: %w", cmd, err) } diff --git a/internal/git2go/merge.go b/internal/git2go/merge.go index c6074bc1fc..8669a18eb4 100644 --- a/internal/git2go/merge.go +++ b/internal/git2go/merge.go @@ -47,6 +47,8 @@ type MergeCommand struct { // If set to `true`, then the resulting commit will have `Ours` as its only parent. // Otherwise, a merge commit will be created with `Ours` and `Theirs` as its parents. Squash bool + // SigningKey is a path to the key to sign commit using OpenPGP + SigningKey string } // MergeResult contains results from a merge. @@ -60,13 +62,9 @@ func (b *Executor) Merge(ctx context.Context, repo repository.GitRepo, m MergeCo if err := m.verify(); err != nil { return MergeResult{}, fmt.Errorf("merge: %w: %s", ErrInvalidArgument, err.Error()) } + m.SigningKey = b.signingKey - var args []string - if b.signingKey != "" { - args = []string{"-signing-key", b.signingKey} - } - - commitID, err := b.runWithGob(ctx, repo, "merge", m, args...) + commitID, err := b.runWithGob(ctx, repo, "merge", m) if err != nil { return MergeResult{}, err } diff --git a/internal/git2go/rebase.go b/internal/git2go/rebase.go index 5d3b4d7a89..8b041dadb7 100644 --- a/internal/git2go/rebase.go +++ b/internal/git2go/rebase.go @@ -30,14 +30,13 @@ type RebaseCommand struct { // and which are thus empty to be skipped. If unset, empty commits will cause the rebase to // fail. SkipEmptyCommits bool + // SigningKey is a path to the key to sign commit using OpenPGP + SigningKey string } // Rebase performs the rebase via gitaly-git2go func (b *Executor) Rebase(ctx context.Context, repo repository.GitRepo, r RebaseCommand) (git.ObjectID, error) { - var args []string - if b.signingKey != "" { - args = []string{"-signing-key", b.signingKey} - } + r.SigningKey = b.signingKey - return b.runWithGob(ctx, repo, "rebase", r, args...) + return b.runWithGob(ctx, repo, "rebase", r) } diff --git a/internal/git2go/revert.go b/internal/git2go/revert.go index e2c5922e26..4c42e706d6 100644 --- a/internal/git2go/revert.go +++ b/internal/git2go/revert.go @@ -26,14 +26,13 @@ type RevertCommand struct { Revert string // Mainline is the parent to be considered the mainline Mainline uint + // SigningKey is a path to the key to sign commit using OpenPGP + SigningKey string } // Revert reverts a commit via gitaly-git2go. func (b *Executor) Revert(ctx context.Context, repo repository.GitRepo, r RevertCommand) (git.ObjectID, error) { - var args []string - if b.signingKey != "" { - args = []string{"-signing-key", b.signingKey} - } + r.SigningKey = b.signingKey - return b.runWithGob(ctx, repo, "revert", r, args...) + return b.runWithGob(ctx, repo, "revert", r) } -- GitLab From 2264f0a9a62e909860c35488f402be410452df94 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Wed, 17 Aug 2022 22:23:08 +0300 Subject: [PATCH 12/20] feat(git2go): test commit signing --- internal/git2go/commit_test.go | 60 ++++++++++++++++++ internal/git2go/testdata/publicKey.gpg | Bin 0 -> 260 bytes internal/git2go/testdata/signingKey.gpg | Bin 0 -> 297 bytes .../testhelper/testdata/home/signingKey.gpg | Bin 3679 -> 0 bytes 4 files changed, 60 insertions(+) create mode 100644 internal/git2go/testdata/publicKey.gpg create mode 100644 internal/git2go/testdata/signingKey.gpg delete mode 100644 internal/testhelper/testdata/home/signingKey.gpg diff --git a/internal/git2go/commit_test.go b/internal/git2go/commit_test.go index 0fef583107..f56eb6e4c2 100644 --- a/internal/git2go/commit_test.go +++ b/internal/git2go/commit_test.go @@ -7,11 +7,14 @@ import ( "context" "errors" "fmt" + "os" "strconv" "strings" "testing" "time" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v15/internal/git" "gitlab.com/gitlab-org/gitaly/v15/internal/git/gittest" @@ -30,6 +33,7 @@ type commit struct { Author Signature Committer Signature Message string + GPGSig string } func TestExecutor_Commit(t *testing.T) { @@ -65,6 +69,7 @@ func TestExecutor_Commit(t *testing.T) { for _, tc := range []struct { desc string steps []step + sign bool }{ { desc: "create directory", @@ -455,10 +460,30 @@ func TestExecutor_Commit(t *testing.T) { }, }, }, + { + desc: "update created file, sign commit and verify signature", + steps: []step{ + { + actions: []Action{ + CreateFile{Path: "file", OID: originalFile.String()}, + UpdateFile{Path: "file", OID: updatedFile.String()}, + }, + treeEntries: []gittest.TreeEntry{ + {Mode: DefaultMode, Path: "file", Content: "updated"}, + }, + }, + }, + sign: true, + }, } { t.Run(tc.desc, func(t *testing.T) { author := NewSignature("Author Name", "author.email@example.com", time.Now()) committer := NewSignature("Committer Name", "committer.email@example.com", time.Now()) + + if tc.sign { + executor.signingKey = "testdata/signingKey.gpg" + } + var parentCommit git.ObjectID for i, step := range tc.steps { message := fmt.Sprintf("commit %d", i+1) @@ -498,18 +523,34 @@ func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git data, err := repo.ReadObject(ctx, oid) require.NoError(tb, err) + var ( + gpgsig, dataWithoutGpgSig string + gpgsigStarted bool + ) + var commit commit lines := strings.Split(string(data), "\n") for i, line := range lines { if line == "" { + dataWithoutGpgSig += "\n" + strings.Join(lines[i+1:], "\n") commit.Message = strings.Join(lines[i+1:], "\n") break } + if gpgsigStarted && strings.HasPrefix(line, " ") { + gpgsig += strings.TrimSpace(line) + "\n" + continue + } + split := strings.SplitN(line, " ", 2) require.Len(tb, split, 2, "invalid commit: %q", data) field, value := split[0], split[1] + + if field != "gpgsig" { + dataWithoutGpgSig += line + "\n" + } + switch field { case "parent": require.Empty(tb, commit.Parent, "multi parent parsing not implemented") @@ -520,10 +561,29 @@ func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git case "committer": require.Empty(tb, commit.Committer, "commit contained multiple committers") commit.Committer = unmarshalSignature(tb, value) + case "gpgsig": + gpgsig = value + "\n" + gpgsigStarted = true default: } } + if gpgsig != "" { + file, err := os.Open("testdata/publicKey.gpg") + require.NoError(tb, err) + + keyring, err := openpgp.ReadKeyRing(file) + require.NoError(tb, err) + + _, err = openpgp.CheckArmoredDetachedSignature( + keyring, + strings.NewReader(dataWithoutGpgSig), + strings.NewReader(gpgsig), + &packet.Config{}, + ) + require.NoError(tb, err) + } + return commit } diff --git a/internal/git2go/testdata/publicKey.gpg b/internal/git2go/testdata/publicKey.gpg new file mode 100644 index 0000000000000000000000000000000000000000..98d02a71e99de392918d06f9d529429154e81dbe GIT binary patch literal 260 zcmbPX%#!p~)=rF5n~jl$@s>M3BO|-R&Xx84nN}yZ3rrTd5Pdnkr*dw}&F6C8=6Ubp zWz1@}6Pn53ZLoS&PUS)x#!nVy%Km#$EfT3n)#omyFtm|3K$V3VF%l9QO^ z0HO4f^KdNt&6Jo0Ef` ziAjlxO_Yn1gPVy(jER|%NsgUKyn%s>Qvjx3ii6>=af_o$d+fzgE-L^? C$6!GK literal 0 HcmV?d00001 diff --git a/internal/git2go/testdata/signingKey.gpg b/internal/git2go/testdata/signingKey.gpg new file mode 100644 index 0000000000000000000000000000000000000000..841fbc76ab026439b6527dfc1f961c2da49b7439 GIT binary patch literal 297 zcmbOd!IJb<)=rF5n~jl$@s>M3BO|-R&Xx84nN}yZ3rrTd5Pdnkr*dw}&F6C8=6Ubp zWz1@ltJ zq@dxPpPQRmqEMWfo|l=Iu27O%T%wSjT3L{oS){38lb%_UlbGZHq4bjTbL~1Nvj~fE zF<6T!vaFpOT{vm({e>yvzO9F6C#AdDyeed60=bw;nwgcGlY^a!Nr{O~l#7#tn~6n? ziJ6f}j-5%ofq{!t0H$7wgW<2_=6G@QGgBUH+VSzvKJCk1bwWQji}kV@Kbr8eZr`g} pN{kGbT8q|auX^)Avmnjtu-LuGmS@+TzE>wzFFwP+vEYI(D*(o^aMu6; literal 0 HcmV?d00001 diff --git a/internal/testhelper/testdata/home/signingKey.gpg b/internal/testhelper/testdata/home/signingKey.gpg deleted file mode 100644 index c60b2dc15b0fef96e1d687b41eb6d9bc29c18f6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3679 zcmbQr8o`qE>HJnk9)<-rKaFl2m_M6K;sVFyN=AvDk9OOd9E?o3e9+{cEq7Djjtwt& zIkZH4?qoWCWQxms?uLNWtg8t-c_b`%3AQcQoc`U^nT_MqTHS*I?=@em#O?lk;PAgR zmH113?hD`lUZ8OE_fNC5-bpR-!yax|yB`H5u%R1r9_WS+pE7LFSQ#v29K>GSFpAOY6PXb|%eU1e<6YUt~o(7!0axVLTF zoysH6oL@fJb0Ee=A_l@zS`_Dk9PRQs0+|NqxG1jMpYC$WjH9Rk-JSCuEno&33MhFP=Kh{r3Hr?9n6lMHh?uUyZZP{joU7&hv5j zl8|2-d=H-d;628by*c{&e7mT(+#f=}nN6CunZ4I%Yj*xM&vcR9CF?Gqt-G^)&+I4P zHCi`?x+=PV{ou=Xb=SY(V;|lATOFOXsm^lk<->U!1E*Dfgd!VmsbG1)z#l`o{uIj)_>f9Q?FsjJ%Crq5xzHCekihU3hHBL%X!SnA^ZAvawW4d zTy=bI@hN%h!Kf~`-&SpR4yrMEJjmR;*=kaTy%T4!sJ~-g?1A}7;@Tp7kDf$|Zjt{q z@BX4D{;&zv0{IJnvQ3(GCa0UZz0|POYMN>4RLjfFuTQh47~VR4yEUepJ1BEPpT5(t?SviNbjiBPoC0$>kCy?{gmD_hpG4-=Cg`Eb;(eWr=U9J{U@%6&aD4KS$BlS z9X(Xl6kMidyv!SWtu_2z*1zQ9!qn;e+*(zUj< zoQv*~(s-yC!&jyLCw{`!r%bi?g+453JgLh)ttxbn&BpbUEoF8DZG}q54o#BfQJh;g>yf9DsD{QuKfh_-uRn)v+s5#F zcJk~?wcpbi)$$7F^Ep_yA6j5(b;`oBPefd( z&lP870+q{5(#)*foE+>-Y@%G89NbJSVoc18Omd7&;tdR3oB}Y#2c@|GhXu-{s$Ps+ z(;I61Kk{()^Hm4^)^_w>Y@PhixBtQ+Go=vGO&rIi)QV*`18^8XS zAav^nC+F19I=;)Q%Y81(uGE#kaq_jOh^(Nz`jQZl`f{ZlZSSd@=Fg4ZF@qr`ZeMC* zVeYPNkFM)CXqv{A&o;kyNH&wJd!7VC^`SMhHJi@n*RR<-_rAo=OaG?6N6NKAh_X`jAk>zsq;{W-4XW99Sn&%T4o zo|)|FI@eDG8^rhd|AX0`Jy4=J}R zKKZP7*)q18=#5+(&z5ENtv;soEa_>}oO?U(+T^x8U2J49 zv#L~k@7L=}y5}y|g)?tXRy}(|(AM|FqucyH_Q)`*$()>vs7fCsP6|HMBzw=iw}-)P zw$cO^`L@zO*DXK)u$0Z(zpG)Av9ClluUSQC>jV4VSbf`kq3v^%6g(rvkA{RSxaBgf z#d_s$p;u)O)-8McV7k=NEq?C3-?*BNYa5>3Fi+peeO9wo-?|=$&;H`t&r=Stmhr{x z%G*=AnuX<`uEga7OWMqIS+2g4`&iEGbMeFv_VcfUn|_!k_RGIr!LD%EN=&WkrN!I4 zg$FAlgx8A|BrvWql*lqac-CbMuq zLmz9ehtoNu>yu3Q7QX(qr&KMYYt_6Tix=6(Po4Ln#^?RBC9f8W-aGx{w$qf!uerl` zx|c>>6y1HptXJUp|MGY2J6G?P)j5`JS>mU|Jfm?|{IYKMuj10tA0->L=Qh{X$FDtR zBV2ygS#MR`vZK$YI<76Xf5cpJ`{(NIPNLAN^snG0H!1s?g0-_lW)m~ny_#`8Bb;*geK;DNE;&yKH zW5ch7Q#!T)_ zk3Q+lo3cD2y-k~;Y}LL>Y5Nl216}hawO6R`J-kXkYVx$Sd2gH-^8DVii}fI1@%iKb zEpi@C?OvnAC&D4Qao(ZLWjm)I(D)dZz_@u^ugiUHN$pwck4m>IC>!kB+q=NI{7c}j z$(!3`JT3;6Pt|(p={?8s%exceo?E_lGB{1XWa!CbHh=%7>YK-3ZoarXZf;-c?>j>8 zlCuuS*_;qupt{lZ+HPi3&yxvv4gaLKEncF`_ULy1BZITEmT!parw?h8I{ z_;!lL=fxbJbtd0^J}CW+h;d|Nc;)bVeLZK?42Fc&g-9?ECJA1yn6Y8!irMAO(|Gv){Ak`f!OY*9y;1&z)3qK8iwzy6J8w)BihN+B zBxLo_N4>NBqHx|U$+pNVa|3c4IDDh;FT8Wf#c2EcL$VVRrrpTuoSlC9Z?Nmee7)k` zUhC{yHy0Ed9N|*C#Cu#mKb&{P>DH&Fx;t&3t!dbO^;N=t&acbLF2);K{=dh^QM6E+ zXYJ4ZIbYLHr({o>by^}RQV+JsWqFg{a#-<+kKAg(xvl$>3()*Tz4}zY0`^rU9Zmy9Cq9IHCptzS93w_ z6X8jT%F2bF(Q!4_F*b)&wC=7s6WlGk+J8kY{ z`MY3!&>PnqUeTX+EeXBStYkZ3Qb*Xub4tHgT;4x@*>R1%0^Uq)O1oLliq3!LVi>g} z@bGMJ{@A9r+ZpGsvN1H;Oo%EIYqOtvC6bSSa@D;3Pl79@7qf)kNY-q%*j>$L(&xF# zJGO!A%=2@LHRGmUeiXvVqV(y^TD?Y(W#^x<+h_K>#}ocwl62Wkl!D1>;zBO z_vd!;vp&4wo>3|EsLngCeu=)O=9z8Us+0R?&k57(ti8c5ZC7+_`NhS_+ZRkQlzSy2 zmh#(r!J`t}oo8>K`L*LtA5(E_b7AQILVd~Iy4#Lynly>`^pY3RU5fmL&x7xObhUlh zbMWK3%D}FqeRs_}8Mm=WFmf;`5U4A8kn6;J3GQFa=`7b8v)pH$%9JT}s5zw(ytZ;? z{l6v)cHb|oZ|~>9n%J%O>&kh5yqY=j^*QcfQ4%t5qkDo26Y0 zoyAe`_3{Iqch0Bf-77qw9Lc_UEK2mz*_=l!w1p0_ERH&07H~^oi~Z-{myefB-J|+j zKlI{~cVD$)L*r*w%#Tk9*2_wY+x=W(O080R+ojAvcAm^d9XU}QTB^-oa-IEuEmFZ zTsF&DB<~mFIg=EZRcW(*(j!l0i%Gsuy}GNf^S7vo^XFgHyt5dJ)ug`|JdQl4aQWvA Y9;TwFd_S{&s(c Date: Thu, 18 Aug 2022 00:55:25 +0300 Subject: [PATCH 13/20] fix(git2go): from args to command params --- cmd/gitaly-git2go/commit.go | 10 +---- cmd/gitaly-git2go/commit/commit.go | 28 +++++-------- cmd/gitaly-git2go/git2goutil/commit.go | 3 -- cmd/gitaly-git2go/resolve_conflicts.go | 10 ++--- cmd/gitaly-git2go/submodule.go | 10 ++--- internal/git/command_factory.go | 2 +- internal/git2go/apply_test.go | 14 +++---- internal/git2go/cherry_pick.go | 4 +- internal/git2go/commit.go | 41 ++++--------------- internal/git2go/commit_test.go | 18 ++++---- internal/git2go/resolve_conflicts.go | 9 ++-- internal/git2go/submodule.go | 12 +++--- .../service/operations/apply_patch_test.go | 6 +-- .../gitaly/service/operations/commit_files.go | 2 +- .../remote/update_remote_mirror_test.go | 2 +- 15 files changed, 58 insertions(+), 113 deletions(-) diff --git a/cmd/gitaly-git2go/commit.go b/cmd/gitaly-git2go/commit.go index 4ecefde909..0dbf90d249 100644 --- a/cmd/gitaly-git2go/commit.go +++ b/cmd/gitaly-git2go/commit.go @@ -8,20 +8,14 @@ import ( "flag" "gitlab.com/gitlab-org/gitaly/v15/cmd/gitaly-git2go/commit" - "gitlab.com/gitlab-org/gitaly/v15/cmd/gitaly-git2go/git2goutil" ) -type commitSubcommand struct { - signingKeyPath string -} +type commitSubcommand struct{} func (cmd *commitSubcommand) Flags() *flag.FlagSet { - fs := flag.NewFlagSet("commit", flag.ExitOnError) - fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") - return fs + return flag.NewFlagSet("commit", flag.ExitOnError) } func (cmd *commitSubcommand) Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { - ctx = context.WithValue(ctx, git2goutil.SigningKeyPathKey{}, cmd.signingKeyPath) return commit.Run(ctx, decoder, encoder) } diff --git a/cmd/gitaly-git2go/commit/commit.go b/cmd/gitaly-git2go/commit/commit.go index 3bfaa48383..e26acd5598 100644 --- a/cmd/gitaly-git2go/commit/commit.go +++ b/cmd/gitaly-git2go/commit/commit.go @@ -15,7 +15,7 @@ import ( // Run runs the commit subcommand. func Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { - var params git2go.CommitParams + var params git2go.CommitCommand if err := decoder.Decode(¶ms); err != nil { return err } @@ -27,8 +27,8 @@ func Run(ctx context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error }) } -func commit(ctx context.Context, params git2go.CommitParams) (string, error) { - repo, err := git2goutil.OpenRepository(params.Repository) +func commit(ctx context.Context, request git2go.CommitCommand) (string, error) { + repo, err := git2goutil.OpenRepository(request.Repository) if err != nil { return "", fmt.Errorf("open repository: %w", err) } @@ -39,8 +39,8 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { } var parents []*git.Commit - if params.Parent != "" { - parentOID, err := git.NewOid(params.Parent) + if request.Parent != "" { + parentOID, err := git.NewOid(request.Parent) if err != nil { return "", fmt.Errorf("parse base commit oid: %w", err) } @@ -62,7 +62,7 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { } } - for _, action := range params.Actions { + for _, action := range request.Actions { if err := apply(action, repo, index); err != nil { if git.IsErrorClass(err, git.ErrorClassIndex) { err = git2go.IndexError(err.Error()) @@ -81,10 +81,10 @@ func commit(ctx context.Context, params git2go.CommitParams) (string, error) { return "", fmt.Errorf("lookup tree: %w", err) } - author := git.Signature(params.Author) - committer := git.Signature(params.Committer) - commitID, err := git2goutil.NewCommitSubmitter(repo, signingKeyPathFromContext(ctx)). - Commit(&author, &committer, git.MessageEncodingUTF8, params.Message, tree, parents...) + author := git.Signature(request.Author) + committer := git.Signature(request.Committer) + commitID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). + Commit(&author, &committer, git.MessageEncodingUTF8, request.Message, tree, parents...) if err != nil { if git.IsErrorClass(err, git.ErrorClassInvalid) { return "", git2go.InvalidArgumentError(err.Error()) @@ -114,11 +114,3 @@ func apply(action git2go.Action, repo *git.Repository, index *git.Index) error { return errors.New("unsupported action") } } - -func signingKeyPathFromContext(ctx context.Context) string { - signingKeyPath, ok := ctx.Value(git2goutil.SigningKeyPathKey{}).(string) - if !ok { - return "" - } - return signingKeyPath -} diff --git a/cmd/gitaly-git2go/git2goutil/commit.go b/cmd/gitaly-git2go/git2goutil/commit.go index 821d049aa8..3f3a1e9ca0 100644 --- a/cmd/gitaly-git2go/git2goutil/commit.go +++ b/cmd/gitaly-git2go/git2goutil/commit.go @@ -6,9 +6,6 @@ import ( git "github.com/libgit2/git2go/v33" ) -// SigningKeyPathKey is the key for a context value. -type SigningKeyPathKey struct{} - // CommitSubmitter is the helper struct to make signed Commits conveniently. type CommitSubmitter struct { Repo *git.Repository diff --git a/cmd/gitaly-git2go/resolve_conflicts.go b/cmd/gitaly-git2go/resolve_conflicts.go index b9f601ad1c..6d05f59c70 100644 --- a/cmd/gitaly-git2go/resolve_conflicts.go +++ b/cmd/gitaly-git2go/resolve_conflicts.go @@ -18,14 +18,10 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type resolveSubcommand struct { - signingKeyPath string -} +type resolveSubcommand struct{} func (cmd *resolveSubcommand) Flags() *flag.FlagSet { - fs := flag.NewFlagSet("resolve", flag.ExitOnError) - fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") - return fs + return flag.NewFlagSet("resolve", flag.ExitOnError) } func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -200,7 +196,7 @@ func (cmd resolveSubcommand) Run(_ context.Context, decoder *gob.Decoder, encode When: request.AuthorDate, } - commitID, err := git2goutil.NewCommitSubmitter(repo, cmd.signingKeyPath). + commitID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). Commit(committer, committer, git.MessageEncodingUTF8, request.Message, tree, ours, theirs) if err != nil { return fmt.Errorf("create commit: %w", err) diff --git a/cmd/gitaly-git2go/submodule.go b/cmd/gitaly-git2go/submodule.go index 7f255f03fd..4596a5ff96 100644 --- a/cmd/gitaly-git2go/submodule.go +++ b/cmd/gitaly-git2go/submodule.go @@ -14,14 +14,10 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git2go" ) -type submoduleSubcommand struct { - signingKeyPath string -} +type submoduleSubcommand struct{} func (cmd *submoduleSubcommand) Flags() *flag.FlagSet { - fs := flag.NewFlagSet("submodule", flag.ExitOnError) - fs.StringVar(&cmd.signingKeyPath, "signing-key", "", "Path to the OpenPGP signing key.") - return fs + return flag.NewFlagSet("submodule", flag.ExitOnError) } func (cmd *submoduleSubcommand) Run(_ context.Context, decoder *gob.Decoder, encoder *gob.Encoder) error { @@ -126,7 +122,7 @@ func (cmd *submoduleSubcommand) run(request git2go.SubmoduleCommand) (*git2go.Su ), ) - newCommitOID, err := git2goutil.NewCommitSubmitter(repo, cmd.signingKeyPath). + newCommitOID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). Commit( &committer, &committer, diff --git a/internal/git/command_factory.go b/internal/git/command_factory.go index 77ff1976c0..e8bb7acb0e 100644 --- a/internal/git/command_factory.go +++ b/internal/git/command_factory.go @@ -257,7 +257,7 @@ func (cf *ExecCommandFactory) GetExecutionEnvironment(ctx context.Context) Execu } // If none is enabled though, we simply use the first execution environment, which is also - // the one with highest priority. This can for example happen in case we only were able to + // the one with the highest priority. This can for example happen in case we only were able to // construct a single execution environment that is currently feature flagged. return cf.execEnvs[0] } diff --git a/internal/git2go/apply_test.go b/internal/git2go/apply_test.go index 2888dab8b8..af99a58e9e 100644 --- a/internal/git2go/apply_test.go +++ b/internal/git2go/apply_test.go @@ -41,7 +41,7 @@ func TestExecutor_Apply(t *testing.T) { author := NewSignature("Test Author", "test.author@example.com", time.Now()) committer := NewSignature("Test Committer", "test.committer@example.com", time.Now()) - parentCommitSHA, err := executor.Commit(ctx, repo, CommitParams{ + parentCommitSHA, err := executor.Commit(ctx, repo, CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -50,7 +50,7 @@ func TestExecutor_Apply(t *testing.T) { }) require.NoError(t, err) - noCommonAncestor, err := executor.Commit(ctx, repo, CommitParams{ + noCommonAncestor, err := executor.Commit(ctx, repo, CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -59,7 +59,7 @@ func TestExecutor_Apply(t *testing.T) { }) require.NoError(t, err) - updateToA, err := executor.Commit(ctx, repo, CommitParams{ + updateToA, err := executor.Commit(ctx, repo, CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -69,7 +69,7 @@ func TestExecutor_Apply(t *testing.T) { }) require.NoError(t, err) - updateToB, err := executor.Commit(ctx, repo, CommitParams{ + updateToB, err := executor.Commit(ctx, repo, CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -79,7 +79,7 @@ func TestExecutor_Apply(t *testing.T) { }) require.NoError(t, err) - updateFromAToB, err := executor.Commit(ctx, repo, CommitParams{ + updateFromAToB, err := executor.Commit(ctx, repo, CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -89,7 +89,7 @@ func TestExecutor_Apply(t *testing.T) { }) require.NoError(t, err) - otherFile, err := executor.Commit(ctx, repo, CommitParams{ + otherFile, err := executor.Commit(ctx, repo, CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -214,7 +214,7 @@ func TestExecutor_Apply(t *testing.T) { Author: author, Committer: committer, Message: tc.patches[len(tc.patches)-1].Message, - }, getCommit(t, ctx, repo, commitID)) + }, getCommit(t, ctx, repo, commitID, false)) gittest.RequireTree(t, cfg, repoPath, commitID.String(), tc.tree) }) } diff --git a/internal/git2go/cherry_pick.go b/internal/git2go/cherry_pick.go index a3754e4d38..7e954f50ed 100644 --- a/internal/git2go/cherry_pick.go +++ b/internal/git2go/cherry_pick.go @@ -8,9 +8,9 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git/repository" ) -// CherryPickCommand contains parameters to perform a cherry pick. +// CherryPickCommand contains parameters to perform a cherry-pick. type CherryPickCommand struct { - // Repository is the path where to execute the cherry pick. + // Repository is the path where to execute the cherry-pick. Repository string // CommitterName is the committer name for the resulting commit. CommitterName string diff --git a/internal/git2go/commit.go b/internal/git2go/commit.go index c7b89861e7..7197e5a37b 100644 --- a/internal/git2go/commit.go +++ b/internal/git2go/commit.go @@ -1,9 +1,7 @@ package git2go import ( - "bytes" "context" - "encoding/gob" "fmt" "gitlab.com/gitlab-org/gitaly/v15/internal/git" @@ -42,8 +40,8 @@ func (err DirectoryExistsError) Error() string { return fmt.Sprintf("directory exists: %q", string(err)) } -// CommitParams contains the information and the steps to build a commit. -type CommitParams struct { +// CommitCommand contains the information and the steps to build a commit. +type CommitCommand struct { // Repository is the path of the repository to operate on. Repository string // Author is the author of the commit. @@ -56,39 +54,14 @@ type CommitParams struct { Parent string // Actions are the steps to build the commit. Actions []Action + // SigningKey is a path to the key to sign commit using OpenPGP + SigningKey string } // Commit builds a commit from the actions, writes it to the object database and // returns its object id. -func (b *Executor) Commit(ctx context.Context, repo repository.GitRepo, params CommitParams) (git.ObjectID, error) { - input := &bytes.Buffer{} - if err := gob.NewEncoder(input).Encode(params); err != nil { - return "", err - } +func (b *Executor) Commit(ctx context.Context, repo repository.GitRepo, c CommitCommand) (git.ObjectID, error) { + c.SigningKey = b.signingKey - var args []string - if b.signingKey != "" { - args = []string{"-signing-key", b.signingKey} - } - - output, err := b.run(ctx, repo, input, "commit", args...) - if err != nil { - return "", err - } - - var result Result - if err := gob.NewDecoder(output).Decode(&result); err != nil { - return "", err - } - - if result.Err != nil { - return "", result.Err - } - - commitID, err := git.ObjectHashSHA1.FromHex(result.CommitID) - if err != nil { - return "", fmt.Errorf("could not parse commit ID: %w", err) - } - - return commitID, nil + return b.runWithGob(ctx, repo, "commit", c) } diff --git a/internal/git2go/commit_test.go b/internal/git2go/commit_test.go index f56eb6e4c2..c96464ca88 100644 --- a/internal/git2go/commit_test.go +++ b/internal/git2go/commit_test.go @@ -67,9 +67,9 @@ func TestExecutor_Commit(t *testing.T) { executor := NewExecutor(cfg, gittest.NewCommandFactory(t, cfg), config.NewLocator(cfg)) for _, tc := range []struct { - desc string - steps []step - sign bool + desc string + steps []step + signAndVerify bool }{ { desc: "create directory", @@ -473,21 +473,21 @@ func TestExecutor_Commit(t *testing.T) { }, }, }, - sign: true, + signAndVerify: true, }, } { t.Run(tc.desc, func(t *testing.T) { author := NewSignature("Author Name", "author.email@example.com", time.Now()) committer := NewSignature("Committer Name", "committer.email@example.com", time.Now()) - if tc.sign { + if tc.signAndVerify { executor.signingKey = "testdata/signingKey.gpg" } var parentCommit git.ObjectID for i, step := range tc.steps { message := fmt.Sprintf("commit %d", i+1) - commitID, err := executor.Commit(ctx, repo, CommitParams{ + commitID, err := executor.Commit(ctx, repo, CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -508,7 +508,7 @@ func TestExecutor_Commit(t *testing.T) { Author: author, Committer: committer, Message: message, - }, getCommit(t, ctx, repo, commitID)) + }, getCommit(t, ctx, repo, commitID, tc.signAndVerify)) gittest.RequireTree(t, cfg, repoPath, commitID.String(), step.treeEntries) parentCommit = commitID @@ -517,7 +517,7 @@ func TestExecutor_Commit(t *testing.T) { } } -func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git.ObjectID) commit { +func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git.ObjectID, verify bool) commit { tb.Helper() data, err := repo.ReadObject(ctx, oid) @@ -568,7 +568,7 @@ func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git } } - if gpgsig != "" { + if gpgsig != "" || verify { file, err := os.Open("testdata/publicKey.gpg") require.NoError(tb, err) diff --git a/internal/git2go/resolve_conflicts.go b/internal/git2go/resolve_conflicts.go index 5f3b16f6f5..cd1ad0d031 100644 --- a/internal/git2go/resolve_conflicts.go +++ b/internal/git2go/resolve_conflicts.go @@ -28,6 +28,8 @@ type ResolveResult struct { // Resolve will attempt merging and resolving conflicts for the provided request func (b *Executor) Resolve(ctx context.Context, repo repository.GitRepo, r ResolveCommand) (ResolveResult, error) { + r.SigningKey = b.signingKey + if err := r.verify(); err != nil { return ResolveResult{}, fmt.Errorf("resolve: %w: %s", ErrInvalidArgument, err.Error()) } @@ -37,12 +39,7 @@ func (b *Executor) Resolve(ctx context.Context, repo repository.GitRepo, r Resol return ResolveResult{}, fmt.Errorf("resolve: %w", err) } - var args []string - if b.signingKey != "" { - args = []string{"-signing-key", b.signingKey} - } - - stdout, err := b.run(ctx, repo, input, "resolve", args...) + stdout, err := b.run(ctx, repo, input, "resolve") if err != nil { return ResolveResult{}, err } diff --git a/internal/git2go/submodule.go b/internal/git2go/submodule.go index 27e442ca28..ce4aad37f9 100644 --- a/internal/git2go/submodule.go +++ b/internal/git2go/submodule.go @@ -37,6 +37,9 @@ type SubmoduleCommand struct { Submodule string // Branch where to commit submodule update Branch string + + // SigningKey is a path to the key to sign commit using OpenPGP + SigningKey string } // SubmoduleResult contains results from a committing a submodule update @@ -47,6 +50,8 @@ type SubmoduleResult struct { // Submodule attempts to commit the request submodule change func (b *Executor) Submodule(ctx context.Context, repo repository.GitRepo, s SubmoduleCommand) (SubmoduleResult, error) { + s.SigningKey = b.signingKey + if err := s.verify(); err != nil { return SubmoduleResult{}, fmt.Errorf("submodule: %w", err) } @@ -57,15 +62,10 @@ func (b *Executor) Submodule(ctx context.Context, repo repository.GitRepo, s Sub return SubmoduleResult{}, fmt.Errorf("%s: %w", cmd, err) } - var args []string - if b.signingKey != "" { - args = []string{"-signing-key", b.signingKey} - } - // Ideally we would use `b.runWithGob` here to avoid the gob encoding // boilerplate, but it is not possible here because `runWithGob` adds error // prefixes and the `LegacyErrPrefix*` errors must match exactly. - stdout, err := b.run(ctx, repo, input, cmd, args...) + stdout, err := b.run(ctx, repo, input, cmd) if err != nil { return SubmoduleResult{}, err } diff --git a/internal/gitaly/service/operations/apply_patch_test.go b/internal/gitaly/service/operations/apply_patch_test.go index 2859774853..e1a38ab824 100644 --- a/internal/gitaly/service/operations/apply_patch_test.go +++ b/internal/gitaly/service/operations/apply_patch_test.go @@ -293,7 +293,7 @@ To restore the original branch and stop patching, run "git am --abort". var baseCommit git.ObjectID for _, action := range tc.baseCommit { var err error - baseCommit, err = executor.Commit(ctx, rewrittenRepo, git2go.CommitParams{ + baseCommit, err = executor.Commit(ctx, rewrittenRepo, git2go.CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -309,7 +309,7 @@ To restore the original branch and stop patching, run "git am --abort". } if tc.extraBranches != nil { - emptyCommit, err := executor.Commit(ctx, rewrittenRepo, git2go.CommitParams{ + emptyCommit, err := executor.Commit(ctx, rewrittenRepo, git2go.CommitCommand{ Repository: repoPath, Author: author, Committer: committer, @@ -329,7 +329,7 @@ To restore the original branch and stop patching, run "git am --abort". commit := baseCommit for _, action := range commitActions { var err error - commit, err = executor.Commit(ctx, rewrittenRepo, git2go.CommitParams{ + commit, err = executor.Commit(ctx, rewrittenRepo, git2go.CommitCommand{ Repository: repoPath, Author: author, Committer: committer, diff --git a/internal/gitaly/service/operations/commit_files.go b/internal/gitaly/service/operations/commit_files.go index 16df353e44..0637ee0215 100644 --- a/internal/gitaly/service/operations/commit_files.go +++ b/internal/gitaly/service/operations/commit_files.go @@ -291,7 +291,7 @@ func (s *Server) userCommitFiles(ctx context.Context, header *gitalypb.UserCommi author = git2go.NewSignature(string(header.CommitAuthorName), string(header.CommitAuthorEmail), now) } - commitID, err := s.git2goExecutor.Commit(ctx, quarantineRepo, git2go.CommitParams{ + commitID, err := s.git2goExecutor.Commit(ctx, quarantineRepo, git2go.CommitCommand{ Repository: repoPath, Author: author, Committer: committer, diff --git a/internal/gitaly/service/remote/update_remote_mirror_test.go b/internal/gitaly/service/remote/update_remote_mirror_test.go index 8b74dd8588..18f0717871 100644 --- a/internal/gitaly/service/remote/update_remote_mirror_test.go +++ b/internal/gitaly/service/remote/update_remote_mirror_test.go @@ -560,7 +560,7 @@ func TestUpdateRemoteMirror(t *testing.T) { for _, commit := range commits { var err error commitOID, err = executor.Commit(ctx, gittest.RewrittenRepository(ctx, t, cfg, c.repoProto), - git2go.CommitParams{ + git2go.CommitCommand{ Repository: c.repoPath, Author: commitSignature, Committer: commitSignature, -- GitLab From 8ab65544388f33eea95f1f04e7f1b47a0de3171e Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 18 Aug 2022 13:40:40 +0300 Subject: [PATCH 14/20] fix(gitaly-git2go): style improvements --- cmd/gitaly-git2go/git2goutil/commit.go | 4 ++-- cmd/gitaly-git2go/git2goutil/sign.go | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/gitaly-git2go/git2goutil/commit.go b/cmd/gitaly-git2go/git2goutil/commit.go index 3f3a1e9ca0..456f6a9d64 100644 --- a/cmd/gitaly-git2go/git2goutil/commit.go +++ b/cmd/gitaly-git2go/git2goutil/commit.go @@ -35,9 +35,9 @@ func (cs *CommitSubmitter) Commit( var signature string if cs.SigningKeyPath != "" { - signature, err = ReadSigningKeyAndSign(cs.SigningKeyPath, string(commitBytes)) + signature, err = CreateCommitSignature(cs.SigningKeyPath, string(commitBytes)) if err != nil { - return nil, fmt.Errorf("read openpgp key: %w", err) + return nil, fmt.Errorf("create commit signature: %w", err) } } diff --git a/cmd/gitaly-git2go/git2goutil/sign.go b/cmd/gitaly-git2go/git2goutil/sign.go index 39db8a4c74..0d8f380da6 100644 --- a/cmd/gitaly-git2go/git2goutil/sign.go +++ b/cmd/gitaly-git2go/git2goutil/sign.go @@ -10,8 +10,9 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/packet" ) -// ReadSigningKeyAndSign reads OpenPGP key and produces PKCS#7 detached signature. -func ReadSigningKeyAndSign(signingKeyPath, contentToSign string) (string, error) { +// CreateCommitSignature reads the given signing key and produces PKCS#7 detached signature. +// When the path to the signing key is not present, an empty signature is returned. +func CreateCommitSignature(signingKeyPath, contentToSign string) (string, error) { file, err := os.Open(signingKeyPath) if err != nil { return "", fmt.Errorf("open file: %w", err) -- GitLab From fb7b108e50bfc8e1d5dd6c4daf83dde2dabc10e9 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 18 Aug 2022 13:44:59 +0300 Subject: [PATCH 15/20] fix(gitaly-git2go): CommitCreateCallback style fix --- cmd/gitaly-git2go/rebase.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/cmd/gitaly-git2go/rebase.go b/cmd/gitaly-git2go/rebase.go index 1447b2a95c..1fa23984ee 100644 --- a/cmd/gitaly-git2go/rebase.go +++ b/cmd/gitaly-git2go/rebase.go @@ -73,15 +73,7 @@ func (cmd *rebaseSubcommand) rebase(ctx context.Context, request *git2go.RebaseC return "", fmt.Errorf("get rebase options: %w", err) } opts.InMemory = 1 - opts.CommitCreateCallback = func(author, committer *git.Signature, messageEncoding git.MessageEncoding, message string, tree *git.Tree, parents ...*git.Commit) (oid *git.Oid, err error) { - commitID, err := git2goutil.NewCommitSubmitter(repo, request.SigningKey). - Commit(author, committer, messageEncoding, message, tree, parents...) - if err != nil { - return nil, fmt.Errorf("create commit: %w", err) - } - - return commitID, nil - } + opts.CommitCreateCallback = git2goutil.NewCommitSubmitter(repo, request.SigningKey).Commit var commit *git.AnnotatedCommit if request.BranchName != "" { -- GitLab From 15b82a3a6ff812e0a4eb65eba79ede4fc47053b5 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 18 Aug 2022 13:48:21 +0300 Subject: [PATCH 16/20] fix(git2go): remove GPGSig field --- internal/git2go/commit_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/git2go/commit_test.go b/internal/git2go/commit_test.go index c96464ca88..787d07c02c 100644 --- a/internal/git2go/commit_test.go +++ b/internal/git2go/commit_test.go @@ -33,7 +33,6 @@ type commit struct { Author Signature Committer Signature Message string - GPGSig string } func TestExecutor_Commit(t *testing.T) { -- GitLab From 4d11cd582e995d5481408c5a9117372731202240 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 18 Aug 2022 13:58:51 +0300 Subject: [PATCH 17/20] fix(gitaly-git2go): move check from Commit to CreateCommitSignature --- cmd/gitaly-git2go/git2goutil/commit.go | 9 +++------ cmd/gitaly-git2go/git2goutil/sign.go | 4 ++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmd/gitaly-git2go/git2goutil/commit.go b/cmd/gitaly-git2go/git2goutil/commit.go index 456f6a9d64..7f45640add 100644 --- a/cmd/gitaly-git2go/git2goutil/commit.go +++ b/cmd/gitaly-git2go/git2goutil/commit.go @@ -33,12 +33,9 @@ func (cs *CommitSubmitter) Commit( return nil, err } - var signature string - if cs.SigningKeyPath != "" { - signature, err = CreateCommitSignature(cs.SigningKeyPath, string(commitBytes)) - if err != nil { - return nil, fmt.Errorf("create commit signature: %w", err) - } + signature, err := CreateCommitSignature(cs.SigningKeyPath, string(commitBytes)) + if err != nil { + return nil, fmt.Errorf("create commit signature: %w", err) } commitID, err := cs.Repo.CreateCommitWithSignature(string(commitBytes), signature, "") diff --git a/cmd/gitaly-git2go/git2goutil/sign.go b/cmd/gitaly-git2go/git2goutil/sign.go index 0d8f380da6..a4c1771b8e 100644 --- a/cmd/gitaly-git2go/git2goutil/sign.go +++ b/cmd/gitaly-git2go/git2goutil/sign.go @@ -13,6 +13,10 @@ import ( // CreateCommitSignature reads the given signing key and produces PKCS#7 detached signature. // When the path to the signing key is not present, an empty signature is returned. func CreateCommitSignature(signingKeyPath, contentToSign string) (string, error) { + if signingKeyPath == "" { + return "", nil + } + file, err := os.Open(signingKeyPath) if err != nil { return "", fmt.Errorf("open file: %w", err) -- GitLab From 456e8791d1b36122d77d5cd2525dee5933dcfc32 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Thu, 18 Aug 2022 14:16:37 +0300 Subject: [PATCH 18/20] fix(git2go tests): various style fixes --- internal/git2go/commit_test.go | 8 ++++---- internal/testhelper/testhelper.go | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/git2go/commit_test.go b/internal/git2go/commit_test.go index 787d07c02c..48deee8153 100644 --- a/internal/git2go/commit_test.go +++ b/internal/git2go/commit_test.go @@ -480,7 +480,7 @@ func TestExecutor_Commit(t *testing.T) { committer := NewSignature("Committer Name", "committer.email@example.com", time.Now()) if tc.signAndVerify { - executor.signingKey = "testdata/signingKey.gpg" + executor.signingKey = testhelper.SigningKeyPath } var parentCommit git.ObjectID @@ -516,7 +516,7 @@ func TestExecutor_Commit(t *testing.T) { } } -func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git.ObjectID, verify bool) commit { +func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git.ObjectID, verifySignature bool) commit { tb.Helper() data, err := repo.ReadObject(ctx, oid) @@ -531,8 +531,8 @@ func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git lines := strings.Split(string(data), "\n") for i, line := range lines { if line == "" { - dataWithoutGpgSig += "\n" + strings.Join(lines[i+1:], "\n") commit.Message = strings.Join(lines[i+1:], "\n") + dataWithoutGpgSig += "\n" + commit.Message break } @@ -567,7 +567,7 @@ func getCommit(tb testing.TB, ctx context.Context, repo *localrepo.Repo, oid git } } - if gpgsig != "" || verify { + if gpgsig != "" || verifySignature { file, err := os.Open("testdata/publicKey.gpg") require.NoError(tb, err) diff --git a/internal/testhelper/testhelper.go b/internal/testhelper/testhelper.go index f1db352f50..2599eed26d 100644 --- a/internal/testhelper/testhelper.go +++ b/internal/testhelper/testhelper.go @@ -34,6 +34,8 @@ const ( RepositoryAuthToken = "the-secret-token" // DefaultStorageName is the default name of the Gitaly storage. DefaultStorageName = "default" + // SigningKeyPath is the default path to test commit signing. + SigningKeyPath = "testdata/signingKey.gpg" ) // IsPraefectEnabled returns whether this testing run is done with Praefect in front of the Gitaly. -- GitLab From 86cecdb58a51fcf6281ea706fe9b3ad18403a7f1 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Sat, 20 Aug 2022 06:11:03 +0300 Subject: [PATCH 19/20] feat(git2go): test with the same signature --- Makefile | 2 +- cmd/gitaly-git2go/git2goutil/sign.go | 2 + cmd/gitaly-git2go/git2goutil/test_sign.go | 49 +++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 cmd/gitaly-git2go/git2goutil/test_sign.go diff --git a/Makefile b/Makefile index b62d3a4940..23718301a1 100644 --- a/Makefile +++ b/Makefile @@ -267,7 +267,7 @@ find_go_sources = $(shell find ${SOURCE_DIR} -type d \( -name ruby # TEST_PACKAGES: packages which shall be tested run_go_tests = PATH='${SOURCE_DIR}/internal/testhelper/testdata/home/bin:${PATH}' \ TEST_TMP_DIR='${TEST_TMP_DIR}' \ - ${GOTESTSUM} --format ${TEST_FORMAT} --junitfile ${TEST_REPORT} --jsonfile ${TEST_FULL_OUTPUT} -- -ldflags '${GO_LDFLAGS}' -tags '${SERVER_BUILD_TAGS},${GIT2GO_BUILD_TAGS}' ${TEST_OPTIONS} ${TEST_PACKAGES} + ${GOTESTSUM} --format ${TEST_FORMAT} --junitfile ${TEST_REPORT} --jsonfile ${TEST_FULL_OUTPUT} -- -ldflags '${GO_LDFLAGS}' -tags '${SERVER_BUILD_TAGS},${GIT2GO_BUILD_TAGS},gitaly_test_signing' ${TEST_OPTIONS} ${TEST_PACKAGES} ## Test options passed to `dlv test`. DEBUG_OPTIONS ?= $(patsubst -%,-test.%,${TEST_OPTIONS}) diff --git a/cmd/gitaly-git2go/git2goutil/sign.go b/cmd/gitaly-git2go/git2goutil/sign.go index a4c1771b8e..b8437d9ad4 100644 --- a/cmd/gitaly-git2go/git2goutil/sign.go +++ b/cmd/gitaly-git2go/git2goutil/sign.go @@ -1,3 +1,5 @@ +//go:build !gitaly_test_signing + package git2goutil import ( diff --git a/cmd/gitaly-git2go/git2goutil/test_sign.go b/cmd/gitaly-git2go/git2goutil/test_sign.go new file mode 100644 index 0000000000..9903449102 --- /dev/null +++ b/cmd/gitaly-git2go/git2goutil/test_sign.go @@ -0,0 +1,49 @@ +//go:build gitaly_test_signing + +package git2goutil + +import ( + "bytes" + "fmt" + "os" + "strings" + "time" + + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/packet" +) + +// CreateCommitSignature reads the given signing key and produces PKCS#7 detached signature. +// When the path to the signing key is not present, an empty signature is returned. +// Test version creates deterministic signature which is the same with the same data every run. +func CreateCommitSignature(signingKeyPath, contentToSign string) (string, error) { + if signingKeyPath == "" { + return "", nil + } + + file, err := os.Open(signingKeyPath) + if err != nil { + return "", fmt.Errorf("open file: %w", err) + } + + entity, err := openpgp.ReadEntity(packet.NewReader(file)) + if err != nil { + return "", fmt.Errorf("read entity: %w", err) + } + + sigBuf := new(bytes.Buffer) + if err := openpgp.ArmoredDetachSignText( + sigBuf, + entity, + strings.NewReader(contentToSign), + &packet.Config{ + Time: func() time.Time { + return time.Date(2022, 8, 20, 11, 22, 33, 0, time.UTC) + }, + }, + ); err != nil { + return "", fmt.Errorf("sign commit: %w", err) + } + + return sigBuf.String(), nil +} -- GitLab From 8e2d41e5b8a5baa1598c8b1033fa3b13ce13fd17 Mon Sep 17 00:00:00 2001 From: Savely Krasovsky Date: Mon, 22 Aug 2022 18:42:48 +0300 Subject: [PATCH 20/20] fix: go.mod update --- go.sum | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/go.sum b/go.sum index 50ebd8ac02..5cbd3509ab 100644 --- a/go.sum +++ b/go.sum @@ -140,6 +140,8 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ProtonMail/go-crypto v0.0.0-20220810064516-de89276ce0f3 h1:JBPdE3yq6D8k8UxTzyCN2uhpHfGKsJEurKLHLU6YBdM= +github.com/ProtonMail/go-crypto v0.0.0-20220810064516-de89276ce0f3/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= @@ -216,6 +218,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -232,6 +235,8 @@ github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/reopen v1.0.0 h1:8tpLVR74DLpLObrn2KvsyxJY++2iORGR17WLUdSzUws= github.com/client9/reopen v1.0.0/go.mod h1:caXVCEr+lUtoN1FlsRiOWdfQtdRHIYfcb0ai8qKWtkQ= +github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/tableflip v1.2.3 h1:8I+B99QnnEWPHOY3fWipwVKxS70LGgUsslG7CSfmHMw= github.com/cloudflare/tableflip v1.2.3/go.mod h1:P4gRehmV6Z2bY5ao5ml9Pd8u6kuEnlB37pUFMmv7j2E= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -- GitLab