From 4cf51c5b7202bc132dc0cb7a4998ea16bbb30f8a Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sat, 12 Oct 2019 18:07:44 +0100 Subject: [PATCH 1/5] Allow Protected Branches to Whitelist Deploy Keys --- cmd/hook.go | 2 ++ cmd/serv.go | 2 ++ models/branches.go | 7 ++++--- models/update.go | 2 ++ modules/auth/repo_form.go | 1 + modules/private/hook.go | 4 +++- options/locale/locale_en-US.ini | 1 + routers/private/hook.go | 8 +++++++- routers/repo/setting_protected_branch.go | 1 + templates/repo/settings/protected_branch.tmpl | 7 +++++++ 10 files changed, 30 insertions(+), 5 deletions(-) diff --git a/cmd/hook.go b/cmd/hook.go index f5b7962aabd4..f07568dd8b20 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -66,6 +66,7 @@ func runHookPreReceive(c *cli.Context) error { reponame := os.Getenv(models.EnvRepoName) userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64) prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64) + isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey)) buf := bytes.NewBuffer(nil) scanner := bufio.NewScanner(os.Stdin) @@ -98,6 +99,7 @@ func runHookPreReceive(c *cli.Context) error { GitObjectDirectory: os.Getenv(private.GitObjectDirectory), GitQuarantinePath: os.Getenv(private.GitQuarantinePath), ProtectedBranchID: prID, + IsDeployKey: isDeployKey, }) switch statusCode { case http.StatusInternalServerError: diff --git a/cmd/serv.go b/cmd/serv.go index 6533b0371c99..1ac6b21e53c1 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -191,6 +191,8 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10)) os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10)) os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) + os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey)) + os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) //LFS token authentication if verb == lfsAuthenticateVerb { diff --git a/models/branches.go b/models/branches.go index fa8beb866c9b..aceff0d8468f 100644 --- a/models/branches.go +++ b/models/branches.go @@ -31,9 +31,10 @@ type ProtectedBranch struct { BranchName string `xorm:"UNIQUE(s)"` CanPush bool `xorm:"NOT NULL DEFAULT false"` EnableWhitelist bool - WhitelistUserIDs []int64 `xorm:"JSON TEXT"` - WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` - EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` + WhitelistUserIDs []int64 `xorm:"JSON TEXT"` + WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` + EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` + WhitelistDeployKeys bool MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"` MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"` diff --git a/models/update.go b/models/update.go index c6ea1a845e6c..5e941c22c465 100644 --- a/models/update.go +++ b/models/update.go @@ -22,6 +22,8 @@ const ( EnvPusherName = "GITEA_PUSHER_NAME" EnvPusherEmail = "GITEA_PUSHER_EMAIL" EnvPusherID = "GITEA_PUSHER_ID" + EnvKeyID = "GITEA_KEY_ID" + EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" ) // CommitToPushCommit transforms a git.Commit to PushCommit type. diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 8d10fc1570d3..80ad86909b9b 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -152,6 +152,7 @@ type ProtectBranchForm struct { EnableWhitelist bool WhitelistUsers string WhitelistTeams string + WhitelistDeployKeys bool EnableMergeWhitelist bool MergeWhitelistUsers string MergeWhitelistTeams string diff --git a/modules/private/hook.go b/modules/private/hook.go index 67496b5132aa..cc9703cc77ec 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -31,11 +31,12 @@ type HookOptions struct { GitAlternativeObjectDirectories string GitQuarantinePath string ProtectedBranchID int64 + IsDeployKey bool } // HookPreReceive check whether the provided commits are allowed func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) { - reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&gitQuarantinePath=%s&prID=%d", + reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&gitQuarantinePath=%s&prID=%d&isDeployKey=%t", url.PathEscape(ownerName), url.PathEscape(repoName), url.QueryEscape(opts.OldCommitID), @@ -46,6 +47,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) url.QueryEscape(opts.GitAlternativeObjectDirectories), url.QueryEscape(opts.GitQuarantinePath), opts.ProtectedBranchID, + opts.IsDeployKey, ) resp, err := newInternalRequest(reqURL, "GET").Response() diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ca09b6120d71..41fe924180ec 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1320,6 +1320,7 @@ settings.protect_this_branch = Enable Branch Protection settings.protect_this_branch_desc = Prevent deletion and disable any Git pushing to the branch. settings.protect_whitelist_committers = Enable Push Whitelist settings.protect_whitelist_committers_desc = Allow whitelisted users or teams to push to this branch (but not force push). +settings.protect_whitelist_deploy_keys = Whitelist deploy keys with write access to push settings.protect_whitelist_users = Whitelisted users for pushing: settings.protect_whitelist_search_users = Search users… settings.protect_whitelist_teams = Whitelisted teams for pushing: diff --git a/routers/private/hook.go b/routers/private/hook.go index 1f6ab2f67320..074e3aef1919 100644 --- a/routers/private/hook.go +++ b/routers/private/hook.go @@ -33,6 +33,7 @@ func HookPreReceive(ctx *macaron.Context) { gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories") gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath") prID := ctx.QueryInt64("prID") + isDeployKey := ctx.QueryBool("isDeployKey") branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) @@ -95,7 +96,12 @@ func HookPreReceive(ctx *macaron.Context) { } } - canPush := protectBranch.CanUserPush(userID) + canPush := false + if isDeployKey { + canPush = protectBranch.WhitelistDeployKeys + } else { + canPush = protectBranch.CanUserPush(userID) + } if !canPush && prID > 0 { pr, err := models.GetPullRequestByID(prID) if err != nil { diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go index 2a8502e6f458..bc4d7c3a9e9e 100644 --- a/routers/repo/setting_protected_branch.go +++ b/routers/repo/setting_protected_branch.go @@ -213,6 +213,7 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm) protectBranch.EnableStatusCheck = f.EnableStatusCheck protectBranch.StatusCheckContexts = f.StatusCheckContexts + protectBranch.WhitelistDeployKeys = f.WhitelistDeployKeys protectBranch.RequiredApprovals = f.RequiredApprovals if strings.TrimSpace(f.ApprovalsWhitelistUsers) != "" { diff --git a/templates/repo/settings/protected_branch.tmpl b/templates/repo/settings/protected_branch.tmpl index 067d1d97613e..a50765c4b479 100644 --- a/templates/repo/settings/protected_branch.tmpl +++ b/templates/repo/settings/protected_branch.tmpl @@ -59,6 +59,13 @@ {{end}} +
+
+
+ + +
+
From c1d3115b8084b549c464c44c2cb074387e28267e Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Mon, 14 Oct 2019 10:00:20 +0100 Subject: [PATCH 2/5] Add migration --- models/migrations/migrations.go | 2 ++ models/migrations/v99.go | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 models/migrations/v99.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index e14437a04b35..c43b77187bf5 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -252,6 +252,8 @@ var migrations = []Migration{ NewMigration("add repo_admin_change_team_access to user", addRepoAdminChangeTeamAccessColumnForUser), // v98 -> v99 NewMigration("add original author name and id on migrated release", addOriginalAuthorOnMigratedReleases), + // v99 -> v100 + NewMigration("Add WhitelistDeployKeys to protected branch", addWhitelistDeployKeysToBranches), } // Migrate database to current version diff --git a/models/migrations/v99.go b/models/migrations/v99.go new file mode 100644 index 000000000000..5cc632f7a3e8 --- /dev/null +++ b/models/migrations/v99.go @@ -0,0 +1,16 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import "github.com/go-xorm/xorm" + +func addWhitelistDeployKeysToBranches(x *xorm.Engine) error { + type ProtectedBranch struct { + ID int64 + WhitelistDeployKeys bool + } + + return x.Sync2(new(ProtectedBranch)) +} From 59c4b4ee00be572e1400858db7f69e5c06715058 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Mon, 14 Oct 2019 10:06:09 +0100 Subject: [PATCH 3/5] Ensure that IsDeployKey is set to false on the http pushes --- routers/repo/http.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/repo/http.go b/routers/repo/http.go index 09dd8205852c..d41c63ba3560 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -263,6 +263,7 @@ func HTTP(ctx *context.Context) { models.EnvPusherName + "=" + authUser.Name, models.EnvPusherID + fmt.Sprintf("=%d", authUser.ID), models.ProtectedBranchRepoID + fmt.Sprintf("=%d", repo.ID), + models.EnvIsDeployKey + "=false", } if !authUser.KeepEmailPrivate { From 2509de5ce11c481861124979c334bd5329916bb8 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Mon, 14 Oct 2019 15:53:52 +0100 Subject: [PATCH 4/5] add not null default false --- models/branches.go | 8 ++++---- models/migrations/v101.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/models/branches.go b/models/branches.go index aceff0d8468f..c5f227f1e5a1 100644 --- a/models/branches.go +++ b/models/branches.go @@ -31,10 +31,10 @@ type ProtectedBranch struct { BranchName string `xorm:"UNIQUE(s)"` CanPush bool `xorm:"NOT NULL DEFAULT false"` EnableWhitelist bool - WhitelistUserIDs []int64 `xorm:"JSON TEXT"` - WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` - EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` - WhitelistDeployKeys bool + WhitelistUserIDs []int64 `xorm:"JSON TEXT"` + WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` + EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` + WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"` MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"` MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"` diff --git a/models/migrations/v101.go b/models/migrations/v101.go index 5cc632f7a3e8..897fca07c852 100644 --- a/models/migrations/v101.go +++ b/models/migrations/v101.go @@ -9,7 +9,7 @@ import "github.com/go-xorm/xorm" func addWhitelistDeployKeysToBranches(x *xorm.Engine) error { type ProtectedBranch struct { ID int64 - WhitelistDeployKeys bool + WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"` } return x.Sync2(new(ProtectedBranch)) From 2da86839ac0fc761f28985ed5e3699cf2187ebce Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 20 Oct 2019 23:03:14 +0100 Subject: [PATCH 5/5] Update models/migrations/v103.go --- models/migrations/v103.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v103.go b/models/migrations/v103.go index 0215b0296a8d..fed025c5cdf0 100644 --- a/models/migrations/v103.go +++ b/models/migrations/v103.go @@ -15,4 +15,4 @@ func addWhitelistDeployKeysToBranches(x *xorm.Engine) error { } return x.Sync2(new(ProtectedBranch)) -} \ No newline at end of file +}