diff options
author | Lauris BH <lauris@nix.lv> | 2020-03-27 00:26:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-27 00:26:34 +0200 |
commit | bbd910ed1b4f52ee66a5cdd8d11f856598161bef (patch) | |
tree | 8392e0f8208b5b7d8e6df8335677518aa07f194f /routers/private/hook.go | |
parent | 52cfd2743c0e85b36081cf80a850e6a5901f1865 (diff) | |
download | gitea-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.go | 69 |
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) |