@@ -32,6 +32,7 @@ import (
3232 webhook_module "code.gitea.io/gitea/modules/webhook"
3333 actions_service "code.gitea.io/gitea/services/actions"
3434 notify_service "code.gitea.io/gitea/services/notify"
35+ pull_service "code.gitea.io/gitea/services/pull"
3536 release_service "code.gitea.io/gitea/services/release"
3637
3738 "xorm.io/builder"
@@ -546,10 +547,58 @@ func UpdateBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m
546547 return & git.ErrPushOutOfDate {Err : errors .New ("non fast-forward update requires force" ), StdErr : "non-fast-forward" , StdOut : "" }
547548 }
548549
550+ pushEnv := repo_module .PushingEnvironment (doer , repo )
551+
552+ protectedBranch , err := git_model .GetFirstMatchProtectedBranchRule (ctx , repo .ID , branchName )
553+ if err != nil {
554+ return fmt .Errorf ("GetFirstMatchProtectedBranchRule: %w" , err )
555+ }
556+ if protectedBranch != nil {
557+ protectedBranch .Repo = repo
558+ globsProtected := protectedBranch .GetProtectedFilePatterns ()
559+ if len (globsProtected ) > 0 {
560+ changedProtectedFiles , protectErr := pull_service .CheckFileProtection (gitRepo , branchName , currentCommitID , newCommit .ID .String (), globsProtected , 1 , pushEnv )
561+ if protectErr != nil {
562+ if ! pull_service .IsErrFilePathProtected (protectErr ) {
563+ return fmt .Errorf ("CheckFileProtection: %w" , protectErr )
564+ }
565+ protectedPath := ""
566+ if len (changedProtectedFiles ) > 0 {
567+ protectedPath = changedProtectedFiles [0 ]
568+ } else if pathErr , ok := protectErr .(pull_service.ErrFilePathProtected ); ok {
569+ protectedPath = pathErr .Path
570+ }
571+ if protectedPath == "" {
572+ protectedPath = branchName
573+ }
574+ return & git.ErrPushRejected {Message : fmt .Sprintf ("branch %s is protected from changing file %s" , branchName , protectedPath )}
575+ }
576+ }
577+
578+ if isForcePush {
579+ if ! protectedBranch .CanUserForcePush (ctx , doer ) {
580+ return & git.ErrPushRejected {Message : "Not allowed to force-push to protected branch " + branchName }
581+ }
582+ } else if ! protectedBranch .CanUserPush (ctx , doer ) {
583+ globsUnprotected := protectedBranch .GetUnprotectedFilePatterns ()
584+ if len (globsUnprotected ) > 0 {
585+ unprotectedOnly , unprotectedErr := pull_service .CheckUnprotectedFiles (gitRepo , branchName , currentCommitID , newCommit .ID .String (), globsUnprotected , pushEnv )
586+ if unprotectedErr != nil {
587+ return fmt .Errorf ("CheckUnprotectedFiles: %w" , unprotectedErr )
588+ }
589+ if ! unprotectedOnly {
590+ return & git.ErrPushRejected {Message : "Not allowed to push to protected branch " + branchName }
591+ }
592+ } else {
593+ return & git.ErrPushRejected {Message : "Not allowed to push to protected branch " + branchName }
594+ }
595+ }
596+ }
597+
549598 pushOpts := git.PushOptions {
550599 Remote : repo .RepoPath (),
551600 Branch : fmt .Sprintf ("%s:%s%s" , newCommit .ID .String (), git .BranchPrefix , branchName ),
552- Env : repo_module . PushingEnvironment ( doer , repo ) ,
601+ Env : pushEnv ,
553602 }
554603
555604 if expectedOldCommitID != "" {
0 commit comments