summaryrefslogtreecommitdiffstats
path: root/routers/private/hook.go
diff options
context:
space:
mode:
authorLauris BH <lauris@nix.lv>2020-03-27 00:26:34 +0200
committerGitHub <noreply@github.com>2020-03-27 00:26:34 +0200
commitbbd910ed1b4f52ee66a5cdd8d11f856598161bef (patch)
tree8392e0f8208b5b7d8e6df8335677518aa07f194f /routers/private/hook.go
parent52cfd2743c0e85b36081cf80a850e6a5901f1865 (diff)
downloadgitea-bbd910ed1b4f52ee66a5cdd8d11f856598161bef.tar.gz
gitea-bbd910ed1b4f52ee66a5cdd8d11f856598161bef.zip
Allow to set protected file patterns that can not be changed under no conditions (#10806)
Co-Authored-By: zeripath <art27@cantab.net>
Diffstat (limited to 'routers/private/hook.go')
-rw-r--r--routers/private/hook.go69
1 files changed, 68 insertions, 1 deletions
diff --git a/routers/private/hook.go b/routers/private/hook.go
index 38b37fa7b4..846d9b6070 100644
--- a/routers/private/hook.go
+++ b/routers/private/hook.go
@@ -22,9 +22,10 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
pull_service "code.gitea.io/gitea/services/pull"
- "github.com/go-git/go-git/v5/plumbing"
"gitea.com/macaron/macaron"
+ "github.com/go-git/go-git/v5/plumbing"
+ "github.com/gobwas/glob"
)
func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []string) error {
@@ -57,6 +58,52 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
return err
}
+func checkFileProtection(oldCommitID, newCommitID string, patterns []glob.Glob, repo *git.Repository, env []string) error {
+
+ stdoutReader, stdoutWriter, err := os.Pipe()
+ if err != nil {
+ log.Error("Unable to create os.Pipe for %s", repo.Path)
+ return err
+ }
+ defer func() {
+ _ = stdoutReader.Close()
+ _ = stdoutWriter.Close()
+ }()
+
+ err = git.NewCommand("diff", "--name-only", oldCommitID+"..."+newCommitID).
+ RunInDirTimeoutEnvFullPipelineFunc(env, -1, repo.Path,
+ stdoutWriter, nil, nil,
+ func(ctx context.Context, cancel context.CancelFunc) error {
+ _ = stdoutWriter.Close()
+
+ scanner := bufio.NewScanner(stdoutReader)
+ for scanner.Scan() {
+ path := strings.TrimSpace(scanner.Text())
+ if len(path) == 0 {
+ continue
+ }
+ lpath := strings.ToLower(path)
+ for _, pat := range patterns {
+ if pat.Match(lpath) {
+ cancel()
+ return models.ErrFilePathProtected{
+ Path: path,
+ }
+ }
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return err
+ }
+ _ = stdoutReader.Close()
+ return err
+ })
+ if err != nil && !models.IsErrFilePathProtected(err) {
+ log.Error("Unable to check file protection for commits from %s to %s in %s: %v", oldCommitID, newCommitID, repo.Path, err)
+ }
+ return err
+}
+
func readAndVerifyCommitsFromShaReader(input io.ReadCloser, repo *git.Repository, env []string) error {
scanner := bufio.NewScanner(input)
for scanner.Scan() {
@@ -216,6 +263,26 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) {
}
}
+ globs := protectBranch.GetProtectedFilePatterns()
+ if len(globs) > 0 {
+ err := checkFileProtection(oldCommitID, newCommitID, globs, gitRepo, env)
+ if err != nil {
+ if !models.IsErrFilePathProtected(err) {
+ log.Error("Unable to check file protection for commits from %s to %s in %-v: %v", oldCommitID, newCommitID, repo, err)
+ ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
+ "err": fmt.Sprintf("Unable to check file protection for commits from %s to %s: %v", oldCommitID, newCommitID, err),
+ })
+ return
+ }
+ protectedFilePath := err.(models.ErrFilePathProtected).Path
+ log.Warn("Forbidden: Branch: %s in %-v is protected from changing file %s", branchName, repo, protectedFilePath)
+ ctx.JSON(http.StatusForbidden, map[string]interface{}{
+ "err": fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
+ })
+ return
+ }
+ }
+
canPush := false
if opts.IsDeployKey {
canPush = protectBranch.CanPush && (!protectBranch.EnableWhitelist || protectBranch.WhitelistDeployKeys)