]> source.dussan.org Git - gitea.git/commitdiff
Allow Protected Branches to Whitelist Deploy Keys (#8483)
authorzeripath <art27@cantab.net>
Mon, 21 Oct 2019 08:21:45 +0000 (09:21 +0100)
committerGitHub <noreply@github.com>
Mon, 21 Oct 2019 08:21:45 +0000 (09:21 +0100)
Add an option to protected branches to add writing deploy keys to the whitelist for pushing.

Please note this is technically a breaking change: previously if the owner of a repository was on the whitelist then any writing deploy key was effectively on the whitelist. This option will now need to be set if that is desired.

Closes #8472

Details:
* Allow Protected Branches to Whitelist Deploy Keys
* Add migration
* Ensure that IsDeployKey is set to false on the http pushes
* add not null default false

13 files changed:
cmd/hook.go
cmd/serv.go
models/branches.go
models/migrations/migrations.go
models/migrations/v103.go [new file with mode: 0644]
models/update.go
modules/auth/repo_form.go
modules/private/hook.go
options/locale/locale_en-US.ini
routers/private/hook.go
routers/repo/http.go
routers/repo/setting_protected_branch.go
templates/repo/settings/protected_branch.tmpl

index f5b7962aabd42e98831f6b23ed226bd6dd8444a9..f07568dd8b20d3347f3697bdd0ce671ef10b5eb7 100644 (file)
@@ -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:
index 6533b0371c999a4aa1f7f44d9a323ab19b013810..1ac6b21e53c1364abeba54b5d7babd08d68b830f 100644 (file)
@@ -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 {
index fa8beb866c9b163ecde5b868ba2289f62bb5ce4f..c5f227f1e5a1ef8460de69403a8489e289e1043b 100644 (file)
@@ -34,6 +34,7 @@ type ProtectedBranch struct {
        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"`
index 8064eccfc17e2a3ed68e50f53b7b52a2639cbff3..8b1329ea68a7f3f3f3faf4103e2125847832f34e 100644 (file)
@@ -260,6 +260,8 @@ var migrations = []Migration{
        NewMigration("change length of some external login users columns", changeSomeColumnsLengthOfExternalLoginUser),
        // v102 -> v103
        NewMigration("update migration repositories' service type", dropColumnHeadUserNameOnPullRequest),
+       // v103 -> v104
+       NewMigration("Add WhitelistDeployKeys to protected branch", addWhitelistDeployKeysToBranches),
 }
 
 // Migrate database to current version
diff --git a/models/migrations/v103.go b/models/migrations/v103.go
new file mode 100644 (file)
index 0000000..fed025c
--- /dev/null
@@ -0,0 +1,18 @@
+// 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 (
+       "xorm.io/xorm"
+)
+
+func addWhitelistDeployKeysToBranches(x *xorm.Engine) error {
+       type ProtectedBranch struct {
+               ID                  int64
+               WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
+       }
+
+       return x.Sync2(new(ProtectedBranch))
+}
index c6ea1a845e6cc628270a4d1dedb4592aed4fba2a..5e941c22c465cbc5493590fb32f301e92feabc94 100644 (file)
@@ -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.
index 5a8ac5934f6d305148480eea41653b0534c1706c..2280666114d52c7086e656c0ae549378a4b135db 100644 (file)
@@ -152,6 +152,7 @@ type ProtectBranchForm struct {
        EnableWhitelist         bool
        WhitelistUsers          string
        WhitelistTeams          string
+       WhitelistDeployKeys     bool
        EnableMergeWhitelist    bool
        MergeWhitelistUsers     string
        MergeWhitelistTeams     string
index 67496b5132aae574ae1d7035d78a33ace0f7fd64..cc9703cc77ecfe938346f29f0278a16118ead745 100644 (file)
@@ -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()
index 7b65de6addea48570192747f95474a4576d5de39..eb38a777c82f0b02ec4e33fd8a185450af58fc92 100644 (file)
@@ -1334,6 +1334,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:
index 1f6ab2f67320603817b22bab1b3894bc0c065c0f..074e3aef1919b4dd1d4742fa8590548557819940 100644 (file)
@@ -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 {
index 09dd8205852cf9b655c370624a06e1312c695b80..d41c63ba3560c734528cedc1231ab9b297a0c10a 100644 (file)
@@ -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 {
index 2a8502e6f4584b074c202d95339e9e005d5b3572..bc4d7c3a9e9eec823a8276a8ae44063904cfdf39 100644 (file)
@@ -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) != "" {
index 067d1d97613ec085e3dbb4fab7660e54fa7333c3..a50765c4b4794f470c5db21a5b9008be6251884a 100644 (file)
                                                                </div>
                                                        </div>
                                                {{end}}
+                                               <br>
+                                               <div class="whitelist field">
+                                                       <div class="ui checkbox">
+                                                               <input type="checkbox" name="whitelist_deploy_keys" {{if .Branch.WhitelistDeployKeys}}checked{{end}}>
+                                                               <label for="whitelist_deploy_keys">{{.i18n.Tr "repo.settings.protect_whitelist_deploy_keys"}}</label>
+                                                       </div>
+                                               </div>
                                        </div>
 
                                        <div class="field">