Skip to content

Commit 3563650

Browse files
zeripathlunny
authored andcommitted
#6946 Run hooks on merge/edit and cope with protected branches (#6961)
* Fix #6946 by checking PullRequest ID on pushing * Ensure we have the owner name, the pr attributes and the the issue * Fix TestSearchRepo by waiting till indexing is done * Update integrations/repo_search_test.go * changes as per @mrsdizzie * missing comma * Spelling mistake * Fix full pushing environment
1 parent e5a4d78 commit 3563650

File tree

8 files changed

+54
-13
lines changed

8 files changed

+54
-13
lines changed

cmd/hook.go

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ func runHookPreReceive(c *cli.Context) error {
6565
username := os.Getenv(models.EnvRepoUsername)
6666
reponame := os.Getenv(models.EnvRepoName)
6767
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
68+
prID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchPRID), 10, 64)
6869

6970
buf := bytes.NewBuffer(nil)
7071
scanner := bufio.NewScanner(os.Stdin)
@@ -95,6 +96,7 @@ func runHookPreReceive(c *cli.Context) error {
9596
UserID: userID,
9697
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
9798
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
99+
ProtectedBranchID: prID,
98100
})
99101
switch statusCode {
100102
case http.StatusInternalServerError:

cmd/serv.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ func runServ(c *cli.Context) error {
191191
os.Setenv(models.EnvPusherName, results.UserName)
192192
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
193193
os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10))
194+
os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0))
194195

195196
//LFS token authentication
196197
if verb == lfsAuthenticateVerb {
@@ -239,8 +240,6 @@ func runServ(c *cli.Context) error {
239240
gitcmd = exec.Command(verb, repoPath)
240241
}
241242

242-
os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", results.RepoID))
243-
244243
gitcmd.Dir = setting.RepoRootPath
245244
gitcmd.Stdout = os.Stdout
246245
gitcmd.Stdin = os.Stdin

models/branches.go

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
const (
2020
// ProtectedBranchRepoID protected Repo ID
2121
ProtectedBranchRepoID = "GITEA_REPO_ID"
22+
// ProtectedBranchPRID protected Repo PR ID
23+
ProtectedBranchPRID = "GITEA_PR_ID"
2224
)
2325

2426
// ProtectedBranch struct

models/helper_environment.go

+15-7
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,34 @@ import (
1212

1313
// PushingEnvironment returns an os environment to allow hooks to work on push
1414
func PushingEnvironment(doer *User, repo *Repository) []string {
15+
return FullPushingEnvironment(doer, doer, repo, 0)
16+
}
17+
18+
// FullPushingEnvironment returns an os environment to allow hooks to work on push
19+
func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string {
1520
isWiki := "false"
1621
if strings.HasSuffix(repo.Name, ".wiki") {
1722
isWiki = "true"
1823
}
1924

20-
sig := doer.NewGitSig()
25+
authorSig := author.NewGitSig()
26+
committerSig := committer.NewGitSig()
2127

2228
// We should add "SSH_ORIGINAL_COMMAND=gitea-internal",
2329
// once we have hook and pushing infrastructure working correctly
2430
return append(os.Environ(),
25-
"GIT_AUTHOR_NAME="+sig.Name,
26-
"GIT_AUTHOR_EMAIL="+sig.Email,
27-
"GIT_COMMITTER_NAME="+sig.Name,
28-
"GIT_COMMITTER_EMAIL="+sig.Email,
31+
"GIT_AUTHOR_NAME="+authorSig.Name,
32+
"GIT_AUTHOR_EMAIL="+authorSig.Email,
33+
"GIT_COMMITTER_NAME="+committerSig.Name,
34+
"GIT_COMMITTER_EMAIL="+committerSig.Email,
2935
EnvRepoName+"="+repo.Name,
3036
EnvRepoUsername+"="+repo.MustOwnerName(),
3137
EnvRepoIsWiki+"="+isWiki,
32-
EnvPusherName+"="+doer.Name,
33-
EnvPusherID+"="+fmt.Sprintf("%d", doer.ID),
38+
EnvPusherName+"="+committer.Name,
39+
EnvPusherID+"="+fmt.Sprintf("%d", committer.ID),
3440
ProtectedBranchRepoID+"="+fmt.Sprintf("%d", repo.ID),
41+
ProtectedBranchPRID+"="+fmt.Sprintf("%d", prID),
42+
"SSH_ORIGINAL_COMMAND=gitea-internal",
3543
)
3644

3745
}

models/pull.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ func (pr *PullRequest) UpdatePatch() (err error) {
876876
if err = pr.GetHeadRepo(); err != nil {
877877
return fmt.Errorf("GetHeadRepo: %v", err)
878878
} else if pr.HeadRepo == nil {
879-
log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID)
879+
log.Trace("PullRequest[%d].UpdatePatch: ignored corrupted data", pr.ID)
880880
return nil
881881
}
882882

modules/private/hook.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ type HookOptions struct {
2929
UserName string
3030
GitObjectDirectory string
3131
GitAlternativeObjectDirectories string
32+
ProtectedBranchID int64
3233
}
3334

3435
// HookPreReceive check whether the provided commits are allowed
3536
func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) {
36-
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s",
37+
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&prID=%d",
3738
url.PathEscape(ownerName),
3839
url.PathEscape(repoName),
3940
url.QueryEscape(opts.OldCommitID),
@@ -42,6 +43,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string)
4243
opts.UserID,
4344
url.QueryEscape(opts.GitObjectDirectory),
4445
url.QueryEscape(opts.GitAlternativeObjectDirectories),
46+
opts.ProtectedBranchID,
4547
)
4648

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

modules/pull/merge.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,17 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
231231
}
232232
}
233233

234-
env := models.PushingEnvironment(doer, pr.BaseRepo)
234+
headUser, err := models.GetUserByName(pr.HeadUserName)
235+
if err != nil {
236+
if !models.IsErrUserNotExist(err) {
237+
log.Error("Can't find user: %s for head repository - %v", pr.HeadUserName, err)
238+
return err
239+
}
240+
log.Error("Can't find user: %s for head repository - defaulting to doer: %s - %v", pr.HeadUserName, doer.Name, err)
241+
headUser = doer
242+
}
243+
244+
env := models.FullPushingEnvironment(headUser, doer, pr.BaseRepo, pr.ID)
235245

236246
// Push back to upstream.
237247
if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {

routers/private/hook.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func HookPreReceive(ctx *macaron.Context) {
3131
userID := ctx.QueryInt64("userID")
3232
gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
3333
gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
34+
prID := ctx.QueryInt64("prID")
3435

3536
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
3637
repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName)
@@ -85,7 +86,24 @@ func HookPreReceive(ctx *macaron.Context) {
8586
}
8687
}
8788

88-
if !protectBranch.CanUserPush(userID) {
89+
canPush := protectBranch.CanUserPush(userID)
90+
if !canPush && prID > 0 {
91+
pr, err := models.GetPullRequestByID(prID)
92+
if err != nil {
93+
log.Error("Unable to get PullRequest %d Error: %v", prID, err)
94+
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
95+
"err": fmt.Sprintf("Unable to get PullRequest %d Error: %v", prID, err),
96+
})
97+
return
98+
}
99+
if !protectBranch.HasEnoughApprovals(pr) {
100+
log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v and pr #%d does not have enough approvals", userID, branchName, repo, pr.Index)
101+
ctx.JSON(http.StatusForbidden, map[string]interface{}{
102+
"err": fmt.Sprintf("protected branch %s can not be pushed to and pr #%d does not have enough approvals", branchName, prID),
103+
})
104+
return
105+
}
106+
} else if !canPush {
89107
log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v", userID, branchName, repo)
90108
ctx.JSON(http.StatusForbidden, map[string]interface{}{
91109
"err": fmt.Sprintf("protected branch %s can not be pushed to", branchName),

0 commit comments

Comments
 (0)