mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Branch protection: Possibility to not use whitelist but allow anyone with write access (#9055)
* Possibility to not use whitelist but allow anyone with write access * fix existing test * rename migration function * Try to give a better name for migration step * Clear settings if higher level setting is not set * Move official reviews to db instead of counting approvals each time * migration * fix * fix migration * fix migration * Remove NOT NULL from EnableWhitelist as migration isn't possible * Fix migration, reviews are connected to issues. * Fix SQL query issues in GetReviewersByPullID. * Simplify function GetReviewersByIssueID * Handle reviewers that has been deleted * Ensure reviews for test is in a well defined order * Only clear and set official reviews when it is an approve or reject.
This commit is contained in:
		
				
					committed by
					
						
						techknowlogick
					
				
			
			
				
	
			
			
			
						parent
						
							6460284085
						
					
				
				
					commit
					bac4b78e09
				
			@@ -39,6 +39,7 @@ type ProtectedBranch struct {
 | 
			
		||||
	MergeWhitelistTeamIDs     []int64            `xorm:"JSON TEXT"`
 | 
			
		||||
	EnableStatusCheck         bool               `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	StatusCheckContexts       []string           `xorm:"JSON TEXT"`
 | 
			
		||||
	EnableApprovalsWhitelist  bool               `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	ApprovalsWhitelistUserIDs []int64            `xorm:"JSON TEXT"`
 | 
			
		||||
	ApprovalsWhitelistTeamIDs []int64            `xorm:"JSON TEXT"`
 | 
			
		||||
	RequiredApprovals         int64              `xorm:"NOT NULL DEFAULT 0"`
 | 
			
		||||
@@ -53,10 +54,25 @@ func (protectBranch *ProtectedBranch) IsProtected() bool {
 | 
			
		||||
 | 
			
		||||
// CanUserPush returns if some user could push to this protected branch
 | 
			
		||||
func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
 | 
			
		||||
	if !protectBranch.EnableWhitelist {
 | 
			
		||||
	if !protectBranch.CanPush {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !protectBranch.EnableWhitelist {
 | 
			
		||||
		if user, err := GetUserByID(userID); err != nil {
 | 
			
		||||
			log.Error("GetUserByID: %v", err)
 | 
			
		||||
			return false
 | 
			
		||||
		} else if repo, err := GetRepositoryByID(protectBranch.RepoID); err != nil {
 | 
			
		||||
			log.Error("GetRepositoryByID: %v", err)
 | 
			
		||||
			return false
 | 
			
		||||
		} else if writeAccess, err := HasAccessUnit(user, repo, UnitTypeCode, AccessModeWrite); err != nil {
 | 
			
		||||
			log.Error("HasAccessUnit: %v", err)
 | 
			
		||||
			return false
 | 
			
		||||
		} else {
 | 
			
		||||
			return writeAccess
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if base.Int64sContains(protectBranch.WhitelistUserIDs, userID) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
@@ -95,6 +111,38 @@ func (protectBranch *ProtectedBranch) CanUserMerge(userID int64) bool {
 | 
			
		||||
	return in
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUserOfficialReviewer check if user is official reviewer for the branch (counts towards required approvals)
 | 
			
		||||
func (protectBranch *ProtectedBranch) IsUserOfficialReviewer(user *User) (bool, error) {
 | 
			
		||||
	return protectBranch.isUserOfficialReviewer(x, user)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (protectBranch *ProtectedBranch) isUserOfficialReviewer(e Engine, user *User) (bool, error) {
 | 
			
		||||
	repo, err := getRepositoryByID(e, protectBranch.RepoID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !protectBranch.EnableApprovalsWhitelist {
 | 
			
		||||
		// Anyone with write access is considered official reviewer
 | 
			
		||||
		writeAccess, err := hasAccessUnit(e, user, repo, UnitTypeCode, AccessModeWrite)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
		return writeAccess, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if base.Int64sContains(protectBranch.ApprovalsWhitelistUserIDs, user.ID) {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inTeam, err := isUserInTeams(e, user.ID, protectBranch.ApprovalsWhitelistTeamIDs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return inTeam, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HasEnoughApprovals returns true if pr has enough granted approvals.
 | 
			
		||||
func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
 | 
			
		||||
	if protectBranch.RequiredApprovals == 0 {
 | 
			
		||||
@@ -105,30 +153,16 @@ func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
 | 
			
		||||
 | 
			
		||||
// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
 | 
			
		||||
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
 | 
			
		||||
	reviews, err := GetReviewersByPullID(pr.IssueID)
 | 
			
		||||
	approvals, err := x.Where("issue_id = ?", pr.Issue.ID).
 | 
			
		||||
		And("type = ?", ReviewTypeApprove).
 | 
			
		||||
		And("official = ?", true).
 | 
			
		||||
		Count(new(Review))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("GetReviewersByPullID: %v", err)
 | 
			
		||||
		log.Error("GetGrantedApprovalsCount: %v", err)
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	approvals := int64(0)
 | 
			
		||||
	userIDs := make([]int64, 0)
 | 
			
		||||
	for _, review := range reviews {
 | 
			
		||||
		if review.Type != ReviewTypeApprove {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if base.Int64sContains(protectBranch.ApprovalsWhitelistUserIDs, review.ID) {
 | 
			
		||||
			approvals++
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		userIDs = append(userIDs, review.ID)
 | 
			
		||||
	}
 | 
			
		||||
	approvalTeamCount, err := UsersInTeamsCount(userIDs, protectBranch.ApprovalsWhitelistTeamIDs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("UsersInTeamsCount: %v", err)
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return approvalTeamCount + approvals
 | 
			
		||||
	return approvals
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetProtectedBranchByRepoID getting protected branch by repo ID
 | 
			
		||||
@@ -139,8 +173,12 @@ func GetProtectedBranchByRepoID(repoID int64) ([]*ProtectedBranch, error) {
 | 
			
		||||
 | 
			
		||||
// GetProtectedBranchBy getting protected branch by ID/Name
 | 
			
		||||
func GetProtectedBranchBy(repoID int64, branchName string) (*ProtectedBranch, error) {
 | 
			
		||||
	return getProtectedBranchBy(x, repoID, branchName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getProtectedBranchBy(e Engine, repoID int64, branchName string) (*ProtectedBranch, error) {
 | 
			
		||||
	rel := &ProtectedBranch{RepoID: repoID, BranchName: branchName}
 | 
			
		||||
	has, err := x.Get(rel)
 | 
			
		||||
	has, err := e.Get(rel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user