summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2019-10-16 14:42:42 +0100
committerGitHub <noreply@github.com>2019-10-16 14:42:42 +0100
commitfcb535c5c3b6b782d9242028fed4cd8c027c4e41 (patch)
tree49c49fd1f040b9dcd600ec8e381df80532bc2701 /services
parent1b72690cb82302b24f41d2beaa5df5592709f4d3 (diff)
downloadgitea-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.go64
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,