diff options
author | zeripath <art27@cantab.net> | 2019-10-16 14:42:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-16 14:42:42 +0100 |
commit | fcb535c5c3b6b782d9242028fed4cd8c027c4e41 (patch) | |
tree | 49c49fd1f040b9dcd600ec8e381df80532bc2701 /services | |
parent | 1b72690cb82302b24f41d2beaa5df5592709f4d3 (diff) | |
download | gitea-fcb535c5c3b6b782d9242028fed4cd8c027c4e41.tar.gz gitea-fcb535c5c3b6b782d9242028fed4cd8c027c4e41.zip |
Sign merges, CRUD, Wiki and Repository initialisation with gpg key (#7631)
This PR fixes #7598 by providing a configurable way of signing commits across the Gitea instance. Per repository configurability and import/generation of trusted secure keys is not provided by this PR - from a security PoV that's probably impossible to do properly. Similarly web-signing, that is asking the user to sign something, is not implemented - this could be done at a later stage however.
## Features
- [x] If commit.gpgsign is set in .gitconfig sign commits and files created through repofiles. (merges should already have been signed.)
- [x] Verify commits signed with the default gpg as valid
- [x] Signer, Committer and Author can all be different
- [x] Allow signer to be arbitrarily different - We still require the key to have an activated email on Gitea. A more complete implementation would be to use a keyserver and mark external-or-unactivated with an "unknown" trust level icon.
- [x] Add a signing-key.gpg endpoint to get the default gpg pub key if available
- Rather than add a fake web-flow user I've added this as an endpoint on /api/v1/signing-key.gpg
- [x] Try to match the default key with a user on gitea - this is done at verification time
- [x] Make things configurable?
- app.ini configuration done
- [x] when checking commits are signed need to check if they're actually verifiable too
- [x] Add documentation
I have decided that adjusting the docker to create a default gpg key is not the correct thing to do and therefore have not implemented this.
Diffstat (limited to 'services')
-rw-r--r-- | services/pull/merge.go | 64 |
1 files changed, 55 insertions, 9 deletions
diff --git a/services/pull/merge.go b/services/pull/merge.go index 355d6dd911..0d762dbc30 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -13,6 +13,7 @@ import ( "os" "path/filepath" "strings" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/cache" @@ -28,6 +29,11 @@ import ( // Merge merges pull request to base repository. // FIXME: add repoWorkingPull make sure two merges does not happen at same time. func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repository, mergeStyle models.MergeStyle, message string) (err error) { + binVersion, err := git.BinVersion() + if err != nil { + return fmt.Errorf("Unable to get git version: %v", err) + } + if err = pr.GetHeadRepo(); err != nil { return fmt.Errorf("GetHeadRepo: %v", err) } else if err = pr.GetBaseRepo(); err != nil { @@ -176,6 +182,30 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor return fmt.Errorf("git read-tree HEAD: %s", errbuf.String()) } + // Determine if we should sign + signArg := "" + if version.Compare(binVersion, "1.7.9", ">=") { + sign, keyID := pr.BaseRepo.SignMerge(doer, tmpBasePath, "HEAD", trackingBranch) + if sign { + signArg = "-S" + keyID + } else if version.Compare(binVersion, "2.0.0", ">=") { + signArg = "--no-gpg-sign" + } + } + + sig := doer.NewGitSig() + commitTimeStr := time.Now().Format(time.RFC3339) + + // Because this may call hooks we should pass in the environment + env := append(os.Environ(), + "GIT_AUTHOR_NAME="+sig.Name, + "GIT_AUTHOR_EMAIL="+sig.Email, + "GIT_AUTHOR_DATE="+commitTimeStr, + "GIT_COMMITTER_NAME="+sig.Name, + "GIT_COMMITTER_EMAIL="+sig.Email, + "GIT_COMMITTER_DATE="+commitTimeStr, + ) + // Merge commits. switch mergeStyle { case models.MergeStyleMerge: @@ -183,9 +213,14 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) } - sig := doer.NewGitSig() - if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + if signArg == "" { + if err := git.NewCommand("commit", "-m", message).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } + } else { + if err := git.NewCommand("commit", signArg, "-m", message).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } } case models.MergeStyleRebase: // Checkout head branch @@ -223,9 +258,14 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor } // Set custom message and author and create merge commit - sig := doer.NewGitSig() - if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + if signArg == "" { + if err := git.NewCommand("commit", "-m", message).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } + } else { + if err := git.NewCommand("commit", signArg, "-m", message).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } } case models.MergeStyleSquash: @@ -234,8 +274,14 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor return fmt.Errorf("git merge --squash [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) } sig := pr.Issue.Poster.NewGitSig() - if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { - return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + if signArg == "" { + if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } + } else { + if err := git.NewCommand("commit", signArg, fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, errbuf.String()) + } } default: return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle} @@ -270,7 +316,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor headUser = doer } - env := models.FullPushingEnvironment( + env = models.FullPushingEnvironment( headUser, doer, pr.BaseRepo, |