Skip to content

Commit 0bfe5eb

Browse files
authored
Allow Protected Branches to Whitelist Deploy Keys (#8483)
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
1 parent b1c1e15 commit 0bfe5eb

File tree

13 files changed

+48
-2
lines changed

13 files changed

+48
-2
lines changed

cmd/hook.go

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ func runHookPreReceive(c *cli.Context) error {
6666
reponame := os.Getenv(models.EnvRepoName)
6767
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
6868
prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64)
69+
isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey))
6970

7071
buf := bytes.NewBuffer(nil)
7172
scanner := bufio.NewScanner(os.Stdin)
@@ -98,6 +99,7 @@ func runHookPreReceive(c *cli.Context) error {
9899
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
99100
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
100101
ProtectedBranchID: prID,
102+
IsDeployKey: isDeployKey,
101103
})
102104
switch statusCode {
103105
case http.StatusInternalServerError:

cmd/serv.go

+2
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ func runServ(c *cli.Context) error {
191191
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
192192
os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10))
193193
os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0))
194+
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey))
195+
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
194196

195197
//LFS token authentication
196198
if verb == lfsAuthenticateVerb {

models/branches.go

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type ProtectedBranch struct {
3434
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
3535
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
3636
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"`
37+
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
3738
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
3839
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
3940
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`

models/migrations/migrations.go

+2
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ var migrations = []Migration{
260260
NewMigration("change length of some external login users columns", changeSomeColumnsLengthOfExternalLoginUser),
261261
// v102 -> v103
262262
NewMigration("update migration repositories' service type", dropColumnHeadUserNameOnPullRequest),
263+
// v103 -> v104
264+
NewMigration("Add WhitelistDeployKeys to protected branch", addWhitelistDeployKeysToBranches),
263265
}
264266

265267
// Migrate database to current version

models/migrations/v103.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package migrations
6+
7+
import (
8+
"xorm.io/xorm"
9+
)
10+
11+
func addWhitelistDeployKeysToBranches(x *xorm.Engine) error {
12+
type ProtectedBranch struct {
13+
ID int64
14+
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
15+
}
16+
17+
return x.Sync2(new(ProtectedBranch))
18+
}

models/update.go

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const (
2222
EnvPusherName = "GITEA_PUSHER_NAME"
2323
EnvPusherEmail = "GITEA_PUSHER_EMAIL"
2424
EnvPusherID = "GITEA_PUSHER_ID"
25+
EnvKeyID = "GITEA_KEY_ID"
26+
EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY"
2527
)
2628

2729
// CommitToPushCommit transforms a git.Commit to PushCommit type.

modules/auth/repo_form.go

+1
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ type ProtectBranchForm struct {
152152
EnableWhitelist bool
153153
WhitelistUsers string
154154
WhitelistTeams string
155+
WhitelistDeployKeys bool
155156
EnableMergeWhitelist bool
156157
MergeWhitelistUsers string
157158
MergeWhitelistTeams string

modules/private/hook.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ type HookOptions struct {
3131
GitAlternativeObjectDirectories string
3232
GitQuarantinePath string
3333
ProtectedBranchID int64
34+
IsDeployKey bool
3435
}
3536

3637
// HookPreReceive check whether the provided commits are allowed
3738
func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) {
38-
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",
39+
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",
3940
url.PathEscape(ownerName),
4041
url.PathEscape(repoName),
4142
url.QueryEscape(opts.OldCommitID),
@@ -46,6 +47,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string)
4647
url.QueryEscape(opts.GitAlternativeObjectDirectories),
4748
url.QueryEscape(opts.GitQuarantinePath),
4849
opts.ProtectedBranchID,
50+
opts.IsDeployKey,
4951
)
5052

5153
resp, err := newInternalRequest(reqURL, "GET").Response()

options/locale/locale_en-US.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,7 @@ settings.protect_this_branch = Enable Branch Protection
13341334
settings.protect_this_branch_desc = Prevent deletion and disable any Git pushing to the branch.
13351335
settings.protect_whitelist_committers = Enable Push Whitelist
13361336
settings.protect_whitelist_committers_desc = Allow whitelisted users or teams to push to this branch (but not force push).
1337+
settings.protect_whitelist_deploy_keys = Whitelist deploy keys with write access to push
13371338
settings.protect_whitelist_users = Whitelisted users for pushing:
13381339
settings.protect_whitelist_search_users = Search users…
13391340
settings.protect_whitelist_teams = Whitelisted teams for pushing:

routers/private/hook.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func HookPreReceive(ctx *macaron.Context) {
3333
gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
3434
gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath")
3535
prID := ctx.QueryInt64("prID")
36+
isDeployKey := ctx.QueryBool("isDeployKey")
3637

3738
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
3839
repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName)
@@ -95,7 +96,12 @@ func HookPreReceive(ctx *macaron.Context) {
9596
}
9697
}
9798

98-
canPush := protectBranch.CanUserPush(userID)
99+
canPush := false
100+
if isDeployKey {
101+
canPush = protectBranch.WhitelistDeployKeys
102+
} else {
103+
canPush = protectBranch.CanUserPush(userID)
104+
}
99105
if !canPush && prID > 0 {
100106
pr, err := models.GetPullRequestByID(prID)
101107
if err != nil {

routers/repo/http.go

+1
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ func HTTP(ctx *context.Context) {
263263
models.EnvPusherName + "=" + authUser.Name,
264264
models.EnvPusherID + fmt.Sprintf("=%d", authUser.ID),
265265
models.ProtectedBranchRepoID + fmt.Sprintf("=%d", repo.ID),
266+
models.EnvIsDeployKey + "=false",
266267
}
267268

268269
if !authUser.KeepEmailPrivate {

routers/repo/setting_protected_branch.go

+1
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm)
213213

214214
protectBranch.EnableStatusCheck = f.EnableStatusCheck
215215
protectBranch.StatusCheckContexts = f.StatusCheckContexts
216+
protectBranch.WhitelistDeployKeys = f.WhitelistDeployKeys
216217

217218
protectBranch.RequiredApprovals = f.RequiredApprovals
218219
if strings.TrimSpace(f.ApprovalsWhitelistUsers) != "" {

templates/repo/settings/protected_branch.tmpl

+7
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959
</div>
6060
</div>
6161
{{end}}
62+
<br>
63+
<div class="whitelist field">
64+
<div class="ui checkbox">
65+
<input type="checkbox" name="whitelist_deploy_keys" {{if .Branch.WhitelistDeployKeys}}checked{{end}}>
66+
<label for="whitelist_deploy_keys">{{.i18n.Tr "repo.settings.protect_whitelist_deploy_keys"}}</label>
67+
</div>
68+
</div>
6269
</div>
6370

6471
<div class="field">

0 commit comments

Comments
 (0)