mirror of
https://github.com/go-gitea/gitea
synced 2024-11-11 04:34:25 +00:00
Allow force pushes to protected branches
This commit is contained in:
parent
6c7744370f
commit
50819b0424
@ -38,10 +38,15 @@ type ProtectedBranch struct {
|
|||||||
isPlainName bool `xorm:"-"`
|
isPlainName bool `xorm:"-"`
|
||||||
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
EnableWhitelist bool
|
EnableWhitelist bool
|
||||||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||||
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||||
|
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
|
CanForcePush bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
|
EnableForcePushWhitelist bool
|
||||||
|
ForcePushWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||||
|
ForcePushWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||||
|
ForcePushWhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"`
|
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
|
|
||||||
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||||
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||||
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`
|
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`
|
||||||
@ -142,6 +147,33 @@ func (protectBranch *ProtectedBranch) CanUserPush(ctx context.Context, user *use
|
|||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CanUserForcePush returns if some user could force push to this protected branch
|
||||||
|
// Since force-push extends normal push, we also check if user has regular push access
|
||||||
|
func (protectBranch *ProtectedBranch) CanUserForcePush(ctx context.Context, user *user_model.User) bool {
|
||||||
|
if !protectBranch.CanForcePush {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !protectBranch.EnableForcePushWhitelist {
|
||||||
|
return protectBranch.CanUserPush(ctx, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
if base.Int64sContains(protectBranch.ForcePushWhitelistUserIDs, user.ID) {
|
||||||
|
return protectBranch.CanUserPush(ctx, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(protectBranch.ForcePushWhitelistTeamIDs) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
in, err := organization.IsUserInTeams(ctx, user.ID, protectBranch.ForcePushWhitelistTeamIDs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("IsUserInTeams: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return in && protectBranch.CanUserPush(ctx, user)
|
||||||
|
}
|
||||||
|
|
||||||
// IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch
|
// IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch
|
||||||
func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch, userID int64, permissionInRepo access_model.Permission) bool {
|
func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch, userID int64, permissionInRepo access_model.Permission) bool {
|
||||||
if !protectBranch.EnableMergeWhitelist {
|
if !protectBranch.EnableMergeWhitelist {
|
||||||
@ -303,6 +335,9 @@ type WhitelistOptions struct {
|
|||||||
UserIDs []int64
|
UserIDs []int64
|
||||||
TeamIDs []int64
|
TeamIDs []int64
|
||||||
|
|
||||||
|
ForcePushUserIDs []int64
|
||||||
|
ForcePushTeamIDs []int64
|
||||||
|
|
||||||
MergeUserIDs []int64
|
MergeUserIDs []int64
|
||||||
MergeTeamIDs []int64
|
MergeTeamIDs []int64
|
||||||
|
|
||||||
@ -330,6 +365,13 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote
|
|||||||
}
|
}
|
||||||
protectBranch.WhitelistUserIDs = whitelist
|
protectBranch.WhitelistUserIDs = whitelist
|
||||||
|
|
||||||
|
whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.ForcePushWhitelistUserIDs, opts.ForcePushUserIDs)
|
||||||
|
log.Info("%v", whitelist, err)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
protectBranch.ForcePushWhitelistUserIDs = whitelist
|
||||||
|
|
||||||
whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.MergeWhitelistUserIDs, opts.MergeUserIDs)
|
whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.MergeWhitelistUserIDs, opts.MergeUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -349,6 +391,12 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote
|
|||||||
}
|
}
|
||||||
protectBranch.WhitelistTeamIDs = whitelist
|
protectBranch.WhitelistTeamIDs = whitelist
|
||||||
|
|
||||||
|
whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.ForcePushWhitelistTeamIDs, opts.ForcePushTeamIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
protectBranch.ForcePushWhitelistTeamIDs = whitelist
|
||||||
|
|
||||||
whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.MergeWhitelistTeamIDs, opts.MergeTeamIDs)
|
whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.MergeWhitelistTeamIDs, opts.MergeTeamIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -474,13 +522,17 @@ func DeleteProtectedBranch(ctx context.Context, repo *repo_model.Repository, id
|
|||||||
func RemoveUserIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, userID int64) error {
|
func RemoveUserIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, userID int64) error {
|
||||||
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistUserIDs), len(p.ApprovalsWhitelistUserIDs), len(p.MergeWhitelistUserIDs)
|
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistUserIDs), len(p.ApprovalsWhitelistUserIDs), len(p.MergeWhitelistUserIDs)
|
||||||
p.WhitelistUserIDs = util.SliceRemoveAll(p.WhitelistUserIDs, userID)
|
p.WhitelistUserIDs = util.SliceRemoveAll(p.WhitelistUserIDs, userID)
|
||||||
|
p.ForcePushWhitelistUserIDs = util.SliceRemoveAll(p.ForcePushWhitelistUserIDs, userID)
|
||||||
p.ApprovalsWhitelistUserIDs = util.SliceRemoveAll(p.ApprovalsWhitelistUserIDs, userID)
|
p.ApprovalsWhitelistUserIDs = util.SliceRemoveAll(p.ApprovalsWhitelistUserIDs, userID)
|
||||||
p.MergeWhitelistUserIDs = util.SliceRemoveAll(p.MergeWhitelistUserIDs, userID)
|
p.MergeWhitelistUserIDs = util.SliceRemoveAll(p.MergeWhitelistUserIDs, userID)
|
||||||
|
|
||||||
if lenIDs != len(p.WhitelistUserIDs) || lenApprovalIDs != len(p.ApprovalsWhitelistUserIDs) ||
|
if lenIDs != len(p.WhitelistUserIDs) ||
|
||||||
|
lenApprovalIDs != len(p.ForcePushWhitelistUserIDs) ||
|
||||||
|
lenApprovalIDs != len(p.ApprovalsWhitelistUserIDs) ||
|
||||||
lenMergeIDs != len(p.MergeWhitelistUserIDs) {
|
lenMergeIDs != len(p.MergeWhitelistUserIDs) {
|
||||||
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
|
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
|
||||||
"whitelist_user_i_ds",
|
"whitelist_user_i_ds",
|
||||||
|
"force_push_whitelist_user_i_ds",
|
||||||
"merge_whitelist_user_i_ds",
|
"merge_whitelist_user_i_ds",
|
||||||
"approvals_whitelist_user_i_ds",
|
"approvals_whitelist_user_i_ds",
|
||||||
).Update(p); err != nil {
|
).Update(p); err != nil {
|
||||||
@ -502,6 +554,7 @@ func RemoveTeamIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, te
|
|||||||
lenMergeIDs != len(p.MergeWhitelistTeamIDs) {
|
lenMergeIDs != len(p.MergeWhitelistTeamIDs) {
|
||||||
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
|
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
|
||||||
"whitelist_team_i_ds",
|
"whitelist_team_i_ds",
|
||||||
|
"force_push_whitelist_team_i_ds",
|
||||||
"merge_whitelist_team_i_ds",
|
"merge_whitelist_team_i_ds",
|
||||||
"approvals_whitelist_team_i_ds",
|
"approvals_whitelist_team_i_ds",
|
||||||
).Update(p); err != nil {
|
).Update(p); err != nil {
|
||||||
|
@ -30,6 +30,11 @@ type BranchProtection struct {
|
|||||||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
||||||
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
||||||
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"`
|
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"`
|
||||||
|
EnableForcePush bool `json:"enable_force_push"`
|
||||||
|
EnableForcePushWhitelist bool `json:"enable_force_push_whitelist"`
|
||||||
|
ForcePushWhitelistUsernames []string `json:"force_push_whitelist_usernames"`
|
||||||
|
ForcePushWhitelistTeams []string `json:"force_push_whitelist_teams"`
|
||||||
|
ForcePushWhitelistDeployKeys bool `json:"force_push_whitelist_deploy_keys"`
|
||||||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
|
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
|
||||||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
||||||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
||||||
@ -62,6 +67,11 @@ type CreateBranchProtectionOption struct {
|
|||||||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
||||||
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
||||||
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"`
|
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"`
|
||||||
|
EnableForcePush bool `json:"enable_force_push"`
|
||||||
|
EnableForcePushWhitelist bool `json:"enable_force_push_whitelist"`
|
||||||
|
ForcePushWhitelistUsernames []string `json:"force_push_whitelist_usernames"`
|
||||||
|
ForcePushWhitelistTeams []string `json:"force_push_whitelist_teams"`
|
||||||
|
ForcePushWhitelistDeployKeys bool `json:"force_push_whitelist_deploy_keys"`
|
||||||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
|
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
|
||||||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
||||||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
||||||
@ -87,6 +97,11 @@ type EditBranchProtectionOption struct {
|
|||||||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
||||||
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
||||||
PushWhitelistDeployKeys *bool `json:"push_whitelist_deploy_keys"`
|
PushWhitelistDeployKeys *bool `json:"push_whitelist_deploy_keys"`
|
||||||
|
EnableForcePush *bool `json:"enable_force_push"`
|
||||||
|
EnableForcePushWhitelist *bool `json:"enable_force_push_whitelist"`
|
||||||
|
ForcePushWhitelistUsernames []string `json:"force_push_whitelist_usernames"`
|
||||||
|
ForcePushWhitelistTeams []string `json:"force_push_whitelist_teams"`
|
||||||
|
ForcePushWhitelistDeployKeys *bool `json:"force_push_whitelist_deploy_keys"`
|
||||||
EnableMergeWhitelist *bool `json:"enable_merge_whitelist"`
|
EnableMergeWhitelist *bool `json:"enable_merge_whitelist"`
|
||||||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
||||||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
||||||
|
@ -2185,6 +2185,7 @@ settings.event_wiki_desc = Wiki page created, renamed, edited or deleted.
|
|||||||
settings.event_release = Release
|
settings.event_release = Release
|
||||||
settings.event_release_desc = Release published, updated or deleted in a repository.
|
settings.event_release_desc = Release published, updated or deleted in a repository.
|
||||||
settings.event_push = Push
|
settings.event_push = Push
|
||||||
|
settings.event_force_push = Force Push
|
||||||
settings.event_push_desc = Git push to a repository.
|
settings.event_push_desc = Git push to a repository.
|
||||||
settings.event_repository = Repository
|
settings.event_repository = Repository
|
||||||
settings.event_repository_desc = Repository created or deleted.
|
settings.event_repository_desc = Repository created or deleted.
|
||||||
@ -2278,8 +2279,14 @@ settings.protect_this_branch = Enable Branch Protection
|
|||||||
settings.protect_this_branch_desc = Prevents deletion and restricts Git pushing and merging to the branch.
|
settings.protect_this_branch_desc = Prevents deletion and restricts Git pushing and merging to the branch.
|
||||||
settings.protect_disable_push = Disable Push
|
settings.protect_disable_push = Disable Push
|
||||||
settings.protect_disable_push_desc = No pushing will be allowed to this branch.
|
settings.protect_disable_push_desc = No pushing will be allowed to this branch.
|
||||||
|
settings.protect_disable_force_push = Disable Force Push
|
||||||
|
settings.protect_disable_force_push_desc = No force pushing will be allowed to this branch.
|
||||||
settings.protect_enable_push = Enable Push
|
settings.protect_enable_push = Enable Push
|
||||||
settings.protect_enable_push_desc = Anyone with write access will be allowed to push to this branch (but not force push).
|
settings.protect_enable_push_desc = Anyone with write access will be allowed to push to this branch (but not force push).
|
||||||
|
settings.protect_enable_force_push_all = Everyone
|
||||||
|
settings.protect_enable_force_push_all_desc = Anyone with push access will be allowed to force push to this branch.
|
||||||
|
settings.protect_enable_force_push_whitelist = Whitelist Restricted Force Push
|
||||||
|
settings.protect_enable_force_push_whitelist_desc = Only whitelisted users or teams with push access will be allowed to force push to this branch.
|
||||||
settings.protect_enable_merge = Enable Merge
|
settings.protect_enable_merge = Enable Merge
|
||||||
settings.protect_enable_merge_desc = Anyone with write access will be allowed to merge the pull requests into this branch.
|
settings.protect_enable_merge_desc = Anyone with write access will be allowed to merge the pull requests into this branch.
|
||||||
settings.protect_whitelist_committers = Whitelist Restricted Push
|
settings.protect_whitelist_committers = Whitelist Restricted Push
|
||||||
@ -2289,6 +2296,9 @@ settings.protect_whitelist_users = Whitelisted users for pushing:
|
|||||||
settings.protect_whitelist_search_users = Search users…
|
settings.protect_whitelist_search_users = Search users…
|
||||||
settings.protect_whitelist_teams = Whitelisted teams for pushing:
|
settings.protect_whitelist_teams = Whitelisted teams for pushing:
|
||||||
settings.protect_whitelist_search_teams = Search teams…
|
settings.protect_whitelist_search_teams = Search teams…
|
||||||
|
settings.protect_force_push_whitelist_users = Whitelisted users for force pushing:
|
||||||
|
settings.protect_force_push_whitelist_teams = Whitelisted teams for force pushing:
|
||||||
|
settings.protect_force_push_whitelist_deploy_keys = Whitelist deploy keys with write access to push.
|
||||||
settings.protect_merge_whitelist_committers = Enable Merge Whitelist
|
settings.protect_merge_whitelist_committers = Enable Merge Whitelist
|
||||||
settings.protect_merge_whitelist_committers_desc = Allow only whitelisted users or teams to merge pull requests into this branch.
|
settings.protect_merge_whitelist_committers_desc = Allow only whitelisted users or teams to merge pull requests into this branch.
|
||||||
settings.protect_merge_whitelist_users = Whitelisted users for merging:
|
settings.protect_merge_whitelist_users = Whitelisted users for merging:
|
||||||
|
@ -552,6 +552,15 @@ func CreateBranchProtection(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
|
ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
forcePushWhitelistUsers, err := user_model.GetUserIDsByNames(ctx, form.ForcePushWhitelistUsernames, false)
|
||||||
|
if err != nil {
|
||||||
|
if user_model.IsErrUserNotExist(err) {
|
||||||
|
ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
mergeWhitelistUsers, err := user_model.GetUserIDsByNames(ctx, form.MergeWhitelistUsernames, false)
|
mergeWhitelistUsers, err := user_model.GetUserIDsByNames(ctx, form.MergeWhitelistUsernames, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) {
|
if user_model.IsErrUserNotExist(err) {
|
||||||
@ -570,7 +579,7 @@ func CreateBranchProtection(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
|
ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
|
var whitelistTeams, forcePushWhitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
|
||||||
if repo.Owner.IsOrganization() {
|
if repo.Owner.IsOrganization() {
|
||||||
whitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.PushWhitelistTeams, false)
|
whitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.PushWhitelistTeams, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -581,6 +590,15 @@ func CreateBranchProtection(ctx *context.APIContext) {
|
|||||||
ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
|
ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
forcePushWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.ForcePushWhitelistTeams, false)
|
||||||
|
if err != nil {
|
||||||
|
if organization.IsErrTeamNotExist(err) {
|
||||||
|
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
mergeWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.MergeWhitelistTeams, false)
|
mergeWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.MergeWhitelistTeams, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if organization.IsErrTeamNotExist(err) {
|
if organization.IsErrTeamNotExist(err) {
|
||||||
@ -606,8 +624,11 @@ func CreateBranchProtection(ctx *context.APIContext) {
|
|||||||
RuleName: ruleName,
|
RuleName: ruleName,
|
||||||
CanPush: form.EnablePush,
|
CanPush: form.EnablePush,
|
||||||
EnableWhitelist: form.EnablePush && form.EnablePushWhitelist,
|
EnableWhitelist: form.EnablePush && form.EnablePushWhitelist,
|
||||||
EnableMergeWhitelist: form.EnableMergeWhitelist,
|
|
||||||
WhitelistDeployKeys: form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistDeployKeys,
|
WhitelistDeployKeys: form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistDeployKeys,
|
||||||
|
CanForcePush: form.EnablePush && form.EnableForcePush,
|
||||||
|
EnableForcePushWhitelist: form.EnablePush && form.EnableForcePush && form.EnableForcePushWhitelist,
|
||||||
|
ForcePushWhitelistDeployKeys: form.EnablePush && form.EnableForcePush && form.EnableForcePushWhitelist && form.ForcePushWhitelistDeployKeys,
|
||||||
|
EnableMergeWhitelist: form.EnableMergeWhitelist,
|
||||||
EnableStatusCheck: form.EnableStatusCheck,
|
EnableStatusCheck: form.EnableStatusCheck,
|
||||||
StatusCheckContexts: form.StatusCheckContexts,
|
StatusCheckContexts: form.StatusCheckContexts,
|
||||||
EnableApprovalsWhitelist: form.EnableApprovalsWhitelist,
|
EnableApprovalsWhitelist: form.EnableApprovalsWhitelist,
|
||||||
@ -624,6 +645,8 @@ func CreateBranchProtection(ctx *context.APIContext) {
|
|||||||
err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{
|
err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{
|
||||||
UserIDs: whitelistUsers,
|
UserIDs: whitelistUsers,
|
||||||
TeamIDs: whitelistTeams,
|
TeamIDs: whitelistTeams,
|
||||||
|
ForcePushUserIDs: forcePushWhitelistUsers,
|
||||||
|
ForcePushTeamIDs: forcePushWhitelistTeams,
|
||||||
MergeUserIDs: mergeWhitelistUsers,
|
MergeUserIDs: mergeWhitelistUsers,
|
||||||
MergeTeamIDs: mergeWhitelistTeams,
|
MergeTeamIDs: mergeWhitelistTeams,
|
||||||
ApprovalsUserIDs: approvalsWhitelistUsers,
|
ApprovalsUserIDs: approvalsWhitelistUsers,
|
||||||
@ -754,6 +777,27 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if form.EnableForcePush != nil {
|
||||||
|
if !*form.EnableForcePush {
|
||||||
|
protectBranch.CanForcePush = false
|
||||||
|
protectBranch.EnableForcePushWhitelist = false
|
||||||
|
protectBranch.ForcePushWhitelistDeployKeys = false
|
||||||
|
} else {
|
||||||
|
protectBranch.CanForcePush = true
|
||||||
|
if form.EnableForcePushWhitelist != nil {
|
||||||
|
if !*form.EnableForcePushWhitelist {
|
||||||
|
protectBranch.EnableForcePushWhitelist = false
|
||||||
|
protectBranch.ForcePushWhitelistDeployKeys = false
|
||||||
|
} else {
|
||||||
|
protectBranch.EnableForcePushWhitelist = true
|
||||||
|
if form.ForcePushWhitelistDeployKeys != nil {
|
||||||
|
protectBranch.ForcePushWhitelistDeployKeys = *form.ForcePushWhitelistDeployKeys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if form.EnableMergeWhitelist != nil {
|
if form.EnableMergeWhitelist != nil {
|
||||||
protectBranch.EnableMergeWhitelist = *form.EnableMergeWhitelist
|
protectBranch.EnableMergeWhitelist = *form.EnableMergeWhitelist
|
||||||
}
|
}
|
||||||
@ -802,7 +846,7 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
protectBranch.BlockOnOutdatedBranch = *form.BlockOnOutdatedBranch
|
protectBranch.BlockOnOutdatedBranch = *form.BlockOnOutdatedBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
var whitelistUsers []int64
|
var whitelistUsers, forcePushWhitelistUsers, mergeWhitelistUsers, approvalsWhitelistUsers []int64
|
||||||
if form.PushWhitelistUsernames != nil {
|
if form.PushWhitelistUsernames != nil {
|
||||||
whitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.PushWhitelistUsernames, false)
|
whitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.PushWhitelistUsernames, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -816,7 +860,19 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
} else {
|
} else {
|
||||||
whitelistUsers = protectBranch.WhitelistUserIDs
|
whitelistUsers = protectBranch.WhitelistUserIDs
|
||||||
}
|
}
|
||||||
var mergeWhitelistUsers []int64
|
if form.ForcePushWhitelistUsernames != nil {
|
||||||
|
forcePushWhitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.ForcePushWhitelistUsernames, false)
|
||||||
|
if err != nil {
|
||||||
|
if user_model.IsErrUserNotExist(err) {
|
||||||
|
ctx.Error(http.StatusUnprocessableEntity, "User does not exist", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetUserIDsByNames", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forcePushWhitelistUsers = protectBranch.ForcePushWhitelistUserIDs
|
||||||
|
}
|
||||||
if form.MergeWhitelistUsernames != nil {
|
if form.MergeWhitelistUsernames != nil {
|
||||||
mergeWhitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.MergeWhitelistUsernames, false)
|
mergeWhitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.MergeWhitelistUsernames, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -830,7 +886,6 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
} else {
|
} else {
|
||||||
mergeWhitelistUsers = protectBranch.MergeWhitelistUserIDs
|
mergeWhitelistUsers = protectBranch.MergeWhitelistUserIDs
|
||||||
}
|
}
|
||||||
var approvalsWhitelistUsers []int64
|
|
||||||
if form.ApprovalsWhitelistUsernames != nil {
|
if form.ApprovalsWhitelistUsernames != nil {
|
||||||
approvalsWhitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.ApprovalsWhitelistUsernames, false)
|
approvalsWhitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.ApprovalsWhitelistUsernames, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -845,7 +900,7 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
approvalsWhitelistUsers = protectBranch.ApprovalsWhitelistUserIDs
|
approvalsWhitelistUsers = protectBranch.ApprovalsWhitelistUserIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
|
var whitelistTeams, forcePushWhitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64
|
||||||
if repo.Owner.IsOrganization() {
|
if repo.Owner.IsOrganization() {
|
||||||
if form.PushWhitelistTeams != nil {
|
if form.PushWhitelistTeams != nil {
|
||||||
whitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.PushWhitelistTeams, false)
|
whitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.PushWhitelistTeams, false)
|
||||||
@ -860,6 +915,19 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
} else {
|
} else {
|
||||||
whitelistTeams = protectBranch.WhitelistTeamIDs
|
whitelistTeams = protectBranch.WhitelistTeamIDs
|
||||||
}
|
}
|
||||||
|
if form.ForcePushWhitelistTeams != nil {
|
||||||
|
forcePushWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.ForcePushWhitelistTeams, false)
|
||||||
|
if err != nil {
|
||||||
|
if organization.IsErrTeamNotExist(err) {
|
||||||
|
ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forcePushWhitelistTeams = protectBranch.ForcePushWhitelistTeamIDs
|
||||||
|
}
|
||||||
if form.MergeWhitelistTeams != nil {
|
if form.MergeWhitelistTeams != nil {
|
||||||
mergeWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.MergeWhitelistTeams, false)
|
mergeWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.MergeWhitelistTeams, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -891,6 +959,8 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{
|
err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{
|
||||||
UserIDs: whitelistUsers,
|
UserIDs: whitelistUsers,
|
||||||
TeamIDs: whitelistTeams,
|
TeamIDs: whitelistTeams,
|
||||||
|
ForcePushUserIDs: forcePushWhitelistUsers,
|
||||||
|
ForcePushTeamIDs: forcePushWhitelistTeams,
|
||||||
MergeUserIDs: mergeWhitelistUsers,
|
MergeUserIDs: mergeWhitelistUsers,
|
||||||
MergeTeamIDs: mergeWhitelistTeams,
|
MergeTeamIDs: mergeWhitelistTeams,
|
||||||
ApprovalsUserIDs: approvalsWhitelistUsers,
|
ApprovalsUserIDs: approvalsWhitelistUsers,
|
||||||
|
@ -182,7 +182,9 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Disallow force pushes to protected branches
|
isForcePush := false
|
||||||
|
|
||||||
|
// 2. Disallow force pushes to protected branches if the option is unchecked
|
||||||
if git.EmptySHA != oldCommitID {
|
if git.EmptySHA != oldCommitID {
|
||||||
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env})
|
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -192,12 +194,15 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
} else if len(output) > 0 {
|
} else if len(output) > 0 {
|
||||||
log.Warn("Forbidden: Branch: %s in %-v is protected from force push", branchName, repo)
|
if protectBranch.CanForcePush {
|
||||||
ctx.JSON(http.StatusForbidden, private.Response{
|
isForcePush = true
|
||||||
UserMsg: fmt.Sprintf("branch %s is protected from force push", branchName),
|
} else {
|
||||||
})
|
log.Warn("Forbidden: Branch: %s in %-v is protected from force push", branchName, repo)
|
||||||
return
|
ctx.JSON(http.StatusForbidden, private.Response{
|
||||||
|
UserMsg: fmt.Sprintf("branch %s is protected from force push", branchName),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,10 +249,15 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Check if the doer is allowed to push
|
// 5. Check if the doer is allowed to push (and force-push if the incoming push is a force-push)
|
||||||
var canPush bool
|
var canPush bool
|
||||||
if ctx.opts.DeployKeyID != 0 {
|
if ctx.opts.DeployKeyID != 0 {
|
||||||
canPush = !changedProtectedfiles && protectBranch.CanPush && (!protectBranch.EnableWhitelist || protectBranch.WhitelistDeployKeys)
|
// This flag is only ever true if protectBranch.CanForcePush is true
|
||||||
|
if isForcePush {
|
||||||
|
canPush = !changedProtectedfiles && protectBranch.CanPush && (!protectBranch.EnableForcePushWhitelist || protectBranch.ForcePushWhitelistDeployKeys)
|
||||||
|
} else {
|
||||||
|
canPush = !changedProtectedfiles && protectBranch.CanPush && (!protectBranch.EnableWhitelist || protectBranch.WhitelistDeployKeys)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
user, err := user_model.GetUserByID(ctx, ctx.opts.UserID)
|
user, err := user_model.GetUserByID(ctx, ctx.opts.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -257,7 +267,11 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
canPush = !changedProtectedfiles && protectBranch.CanUserPush(ctx, user)
|
if isForcePush {
|
||||||
|
canPush = !changedProtectedfiles && protectBranch.CanUserForcePush(ctx, user)
|
||||||
|
} else {
|
||||||
|
canPush = !changedProtectedfiles && protectBranch.CanUserPush(ctx, user)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. If we're not allowed to push directly
|
// 6. If we're not allowed to push directly
|
||||||
@ -293,6 +307,13 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Or we're simply not able to push to this protected branch
|
// Or we're simply not able to push to this protected branch
|
||||||
|
if isForcePush {
|
||||||
|
log.Warn("Forbidden: User %d is not allowed to force-push to protected branch: %s in %-v", ctx.opts.UserID, branchName, repo)
|
||||||
|
ctx.JSON(http.StatusForbidden, private.Response{
|
||||||
|
UserMsg: fmt.Sprintf("Not allowued to force-push to protected branch %s", branchName),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v", ctx.opts.UserID, branchName, repo)
|
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v", ctx.opts.UserID, branchName, repo)
|
||||||
ctx.JSON(http.StatusForbidden, private.Response{
|
ctx.JSON(http.StatusForbidden, private.Response{
|
||||||
UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
|
UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
|
||||||
|
@ -77,6 +77,7 @@ func SettingsProtectedBranch(c *context.Context) {
|
|||||||
}
|
}
|
||||||
c.Data["Users"] = users
|
c.Data["Users"] = users
|
||||||
c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(rule.WhitelistUserIDs), ",")
|
c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(rule.WhitelistUserIDs), ",")
|
||||||
|
c.Data["force_push_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.ForcePushWhitelistUserIDs), ",")
|
||||||
c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.MergeWhitelistUserIDs), ",")
|
c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.MergeWhitelistUserIDs), ",")
|
||||||
c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.ApprovalsWhitelistUserIDs), ",")
|
c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.ApprovalsWhitelistUserIDs), ",")
|
||||||
c.Data["status_check_contexts"] = strings.Join(rule.StatusCheckContexts, "\n")
|
c.Data["status_check_contexts"] = strings.Join(rule.StatusCheckContexts, "\n")
|
||||||
@ -91,6 +92,7 @@ func SettingsProtectedBranch(c *context.Context) {
|
|||||||
}
|
}
|
||||||
c.Data["Teams"] = teams
|
c.Data["Teams"] = teams
|
||||||
c.Data["whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.WhitelistTeamIDs), ",")
|
c.Data["whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.WhitelistTeamIDs), ",")
|
||||||
|
c.Data["force_push_whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.ForcePushWhitelistTeamIDs), ",")
|
||||||
c.Data["merge_whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.MergeWhitelistTeamIDs), ",")
|
c.Data["merge_whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.MergeWhitelistTeamIDs), ",")
|
||||||
c.Data["approvals_whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.ApprovalsWhitelistTeamIDs), ",")
|
c.Data["approvals_whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.ApprovalsWhitelistTeamIDs), ",")
|
||||||
}
|
}
|
||||||
@ -149,7 +151,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var whitelistUsers, whitelistTeams, mergeWhitelistUsers, mergeWhitelistTeams, approvalsWhitelistUsers, approvalsWhitelistTeams []int64
|
var whitelistUsers, whitelistTeams, forcePushWhitelistUsers, forcePushWhitelistTeams, mergeWhitelistUsers, mergeWhitelistTeams, approvalsWhitelistUsers, approvalsWhitelistTeams []int64
|
||||||
protectBranch.RuleName = f.RuleName
|
protectBranch.RuleName = f.RuleName
|
||||||
if f.RequiredApprovals < 0 {
|
if f.RequiredApprovals < 0 {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_approvals_min"))
|
ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_approvals_min"))
|
||||||
@ -178,6 +180,27 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
|
|||||||
protectBranch.WhitelistDeployKeys = false
|
protectBranch.WhitelistDeployKeys = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch f.EnableForcePush {
|
||||||
|
case "all":
|
||||||
|
protectBranch.CanForcePush = true
|
||||||
|
protectBranch.EnableForcePushWhitelist = false
|
||||||
|
protectBranch.ForcePushWhitelistDeployKeys = false
|
||||||
|
case "whitelist":
|
||||||
|
protectBranch.CanForcePush = true
|
||||||
|
protectBranch.EnableForcePushWhitelist = true
|
||||||
|
protectBranch.ForcePushWhitelistDeployKeys = f.ForcePushWhitelistDeployKeys
|
||||||
|
if strings.TrimSpace(f.ForcePushWhitelistUsers) != "" {
|
||||||
|
forcePushWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.ForcePushWhitelistUsers, ","))
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(f.ForcePushWhitelistTeams) != "" {
|
||||||
|
forcePushWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.ForcePushWhitelistTeams, ","))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
protectBranch.CanForcePush = false
|
||||||
|
protectBranch.EnableForcePushWhitelist = false
|
||||||
|
protectBranch.ForcePushWhitelistDeployKeys = false
|
||||||
|
}
|
||||||
|
|
||||||
protectBranch.EnableMergeWhitelist = f.EnableMergeWhitelist
|
protectBranch.EnableMergeWhitelist = f.EnableMergeWhitelist
|
||||||
if f.EnableMergeWhitelist {
|
if f.EnableMergeWhitelist {
|
||||||
if strings.TrimSpace(f.MergeWhitelistUsers) != "" {
|
if strings.TrimSpace(f.MergeWhitelistUsers) != "" {
|
||||||
@ -236,6 +259,8 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
|
|||||||
err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{
|
err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{
|
||||||
UserIDs: whitelistUsers,
|
UserIDs: whitelistUsers,
|
||||||
TeamIDs: whitelistTeams,
|
TeamIDs: whitelistTeams,
|
||||||
|
ForcePushUserIDs: forcePushWhitelistUsers,
|
||||||
|
ForcePushTeamIDs: forcePushWhitelistTeams,
|
||||||
MergeUserIDs: mergeWhitelistUsers,
|
MergeUserIDs: mergeWhitelistUsers,
|
||||||
MergeTeamIDs: mergeWhitelistTeams,
|
MergeTeamIDs: mergeWhitelistTeams,
|
||||||
ApprovalsUserIDs: approvalsWhitelistUsers,
|
ApprovalsUserIDs: approvalsWhitelistUsers,
|
||||||
|
@ -111,6 +111,10 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err)
|
log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err)
|
||||||
}
|
}
|
||||||
|
forcePushWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.ForcePushWhitelistUserIDs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetUserNamesByIDs (ForcePushWhitelistUserIDs): %v", err)
|
||||||
|
}
|
||||||
mergeWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.MergeWhitelistUserIDs)
|
mergeWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.MergeWhitelistUserIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err)
|
log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err)
|
||||||
@ -123,6 +127,10 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err)
|
log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err)
|
||||||
}
|
}
|
||||||
|
forcePushWhitelistTeams, err := user_model.GetUserNamesByIDs(ctx, bp.ForcePushWhitelistTeamIDs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetUserNamesByIDs (ForcePushWhitelistTeamIDs): %v", err)
|
||||||
|
}
|
||||||
mergeWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.MergeWhitelistTeamIDs)
|
mergeWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.MergeWhitelistTeamIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err)
|
log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err)
|
||||||
@ -145,6 +153,11 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api
|
|||||||
PushWhitelistUsernames: pushWhitelistUsernames,
|
PushWhitelistUsernames: pushWhitelistUsernames,
|
||||||
PushWhitelistTeams: pushWhitelistTeams,
|
PushWhitelistTeams: pushWhitelistTeams,
|
||||||
PushWhitelistDeployKeys: bp.WhitelistDeployKeys,
|
PushWhitelistDeployKeys: bp.WhitelistDeployKeys,
|
||||||
|
EnableForcePush: bp.CanForcePush,
|
||||||
|
EnableForcePushWhitelist: bp.EnableForcePushWhitelist,
|
||||||
|
ForcePushWhitelistUsernames: forcePushWhitelistUsernames,
|
||||||
|
ForcePushWhitelistTeams: forcePushWhitelistTeams,
|
||||||
|
ForcePushWhitelistDeployKeys: bp.ForcePushWhitelistDeployKeys,
|
||||||
EnableMergeWhitelist: bp.EnableMergeWhitelist,
|
EnableMergeWhitelist: bp.EnableMergeWhitelist,
|
||||||
MergeWhitelistUsernames: mergeWhitelistUsernames,
|
MergeWhitelistUsernames: mergeWhitelistUsernames,
|
||||||
MergeWhitelistTeams: mergeWhitelistTeams,
|
MergeWhitelistTeams: mergeWhitelistTeams,
|
||||||
|
@ -198,6 +198,10 @@ type ProtectBranchForm struct {
|
|||||||
WhitelistUsers string
|
WhitelistUsers string
|
||||||
WhitelistTeams string
|
WhitelistTeams string
|
||||||
WhitelistDeployKeys bool
|
WhitelistDeployKeys bool
|
||||||
|
EnableForcePush string
|
||||||
|
ForcePushWhitelistUsers string
|
||||||
|
ForcePushWhitelistTeams string
|
||||||
|
ForcePushWhitelistDeployKeys bool
|
||||||
EnableMergeWhitelist bool
|
EnableMergeWhitelist bool
|
||||||
MergeWhitelistUsers string
|
MergeWhitelistUsers string
|
||||||
MergeWhitelistTeams string
|
MergeWhitelistTeams string
|
||||||
|
@ -116,27 +116,25 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest,
|
|||||||
return false, false, err
|
return false, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// can't do rebase on protected branch because need force push
|
if err := pr.LoadBaseRepo(ctx); err != nil {
|
||||||
if pb == nil {
|
return false, false, err
|
||||||
if err := pr.LoadBaseRepo(ctx); err != nil {
|
}
|
||||||
return false, false, err
|
prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests)
|
||||||
|
if err != nil {
|
||||||
|
if repo_model.IsErrUnitTypeNotExist(err) {
|
||||||
|
return false, false, nil
|
||||||
}
|
}
|
||||||
prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests)
|
log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err)
|
||||||
if err != nil {
|
return false, false, err
|
||||||
if repo_model.IsErrUnitTypeNotExist(err) {
|
|
||||||
return false, false, nil
|
|
||||||
}
|
|
||||||
log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err)
|
|
||||||
return false, false, err
|
|
||||||
}
|
|
||||||
rebaseAllowed = prUnit.PullRequestsConfig().AllowRebaseUpdate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update function need push permission
|
rebaseAllowed = prUnit.PullRequestsConfig().AllowRebaseUpdate
|
||||||
|
|
||||||
|
// If branch protected, disable rebase unless user is whitelisted to force push (which extends regular push)
|
||||||
if pb != nil {
|
if pb != nil {
|
||||||
pb.Repo = pull.BaseRepo
|
pb.Repo = pull.BaseRepo
|
||||||
if !pb.CanUserPush(ctx, user) {
|
if !pb.CanUserForcePush(ctx, user) {
|
||||||
return false, false, nil
|
rebaseAllowed = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +94,69 @@
|
|||||||
<p class="help">{{ctx.Locale.Tr "repo.settings.require_signed_commits_desc"}}</p>
|
<p class="help">{{ctx.Locale.Tr "repo.settings.require_signed_commits_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.event_force_push"}}</h5>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui radio checkbox">
|
||||||
|
<input type="radio" name="enable_force_push" value="none" class="toggle-target-disabled" data-target="#force_push_whitelist_box" {{if not .Rule.CanForcePush}}checked{{end}}>
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.protect_disable_force_push"}}</label>
|
||||||
|
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_disable_force_push_desc"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui radio checkbox">
|
||||||
|
<input type="radio" name="enable_force_push" value="all" class="toggle-target-disabled" data-target="#force_push_whitelist_box" {{if and (.Rule.CanForcePush) (not .Rule.EnableForcePushWhitelist)}}checked{{end}}>
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.protect_enable_force_push_all"}}</label>
|
||||||
|
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_enable_force_push_all_desc"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grouped fields">
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui radio checkbox">
|
||||||
|
<input type="radio" name="enable_force_push" value="whitelist" class="toggle-target-enabled" data-target="#force_push_whitelist_box" {{if and (.Rule.CanForcePush) (.Rule.EnableForcePushWhitelist)}}checked{{end}}>
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.protect_enable_force_push_whitelist"}}</label>
|
||||||
|
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_enable_force_push_whitelist_desc"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="force_push_whitelist_box" class="grouped fields {{if not .Rule.EnableForcePushWhitelist}}disabled{{end}}">
|
||||||
|
<div class="checkbox-sub-item field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.protect_force_push_whitelist_users"}}</label>
|
||||||
|
<div class="ui multiple search selection dropdown">
|
||||||
|
<input type="hidden" name="force_push_whitelist_users" value="{{.force_push_whitelist_users}}">
|
||||||
|
<div class="default text">{{ctx.Locale.Tr "repo.settings.protect_whitelist_search_users"}}</div>
|
||||||
|
<div class="menu">
|
||||||
|
{{range .Users}}
|
||||||
|
<div class="item" data-value="{{.ID}}">
|
||||||
|
{{ctx.AvatarUtils.Avatar . 28 "mini"}}{{template "repo/search_name" .}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{if .Owner.IsOrganization}}
|
||||||
|
<div class="checkbox-sub-item field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.protect_force_push_whitelist_teams"}}</label>
|
||||||
|
<div class="ui multiple search selection dropdown">
|
||||||
|
<input type="hidden" name="force_push_whitelist_teams" value="{{.force_push_whitelist_teams}}">
|
||||||
|
<div class="default text">{{ctx.Locale.Tr "repo.settings.protect_whitelist_search_teams"}}</div>
|
||||||
|
<div class="menu">
|
||||||
|
{{range .Teams}}
|
||||||
|
<div class="item" data-value="{{.ID}}">
|
||||||
|
{{svg "octicon-people"}}
|
||||||
|
{{.Name}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<div class="checkbox-sub-item field">
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" name="force_push_whitelist_deploy_keys" {{if .Rule.ForcePushWhitelistDeployKeys}}checked{{end}}>
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.protect_force_push_whitelist_deploy_keys"}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.event_pull_request_approvals"}}</h5>
|
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.event_pull_request_approvals"}}</h5>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.protect_required_approvals"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.protect_required_approvals"}}</label>
|
||||||
|
78
templates/swagger/v1_json.tmpl
generated
78
templates/swagger/v1_json.tmpl
generated
@ -16926,6 +16926,14 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "EnablePushWhitelist"
|
"x-go-name": "EnablePushWhitelist"
|
||||||
},
|
},
|
||||||
|
"enable_force_push": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "EnableForcePush"
|
||||||
|
},
|
||||||
|
"enable_force_push_whitelist": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "EnableForcePushWhitelist"
|
||||||
|
},
|
||||||
"enable_status_check": {
|
"enable_status_check": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "EnableStatusCheck"
|
"x-go-name": "EnableStatusCheck"
|
||||||
@ -16966,6 +16974,24 @@
|
|||||||
},
|
},
|
||||||
"x-go-name": "PushWhitelistUsernames"
|
"x-go-name": "PushWhitelistUsernames"
|
||||||
},
|
},
|
||||||
|
"force_push_whitelist_deploy_keys": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "ForcePushWhitelistDeployKeys"
|
||||||
|
},
|
||||||
|
"force_push_whitelist_teams": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "ForcePushWhitelistTeams"
|
||||||
|
},
|
||||||
|
"force_push_whitelist_usernames": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "ForcePushWhitelistUsernames"
|
||||||
|
},
|
||||||
"require_signed_commits": {
|
"require_signed_commits": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "RequireSignedCommits"
|
"x-go-name": "RequireSignedCommits"
|
||||||
@ -17567,6 +17593,14 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "EnablePushWhitelist"
|
"x-go-name": "EnablePushWhitelist"
|
||||||
},
|
},
|
||||||
|
"enable_force_push": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "EnableForcePush"
|
||||||
|
},
|
||||||
|
"enable_force_push_whitelist": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "EnableForcePushWhitelist"
|
||||||
|
},
|
||||||
"enable_status_check": {
|
"enable_status_check": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "EnableStatusCheck"
|
"x-go-name": "EnableStatusCheck"
|
||||||
@ -17607,6 +17641,24 @@
|
|||||||
},
|
},
|
||||||
"x-go-name": "PushWhitelistUsernames"
|
"x-go-name": "PushWhitelistUsernames"
|
||||||
},
|
},
|
||||||
|
"force_push_whitelist_deploy_keys": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "ForcePushWhitelistDeployKeys"
|
||||||
|
},
|
||||||
|
"force_push_whitelist_teams": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "ForcePushWhitelistTeams"
|
||||||
|
},
|
||||||
|
"force_push_whitelist_usernames": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "ForcePushWhitelistUsernames"
|
||||||
|
},
|
||||||
"require_signed_commits": {
|
"require_signed_commits": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "RequireSignedCommits"
|
"x-go-name": "RequireSignedCommits"
|
||||||
@ -18699,6 +18751,14 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "EnablePushWhitelist"
|
"x-go-name": "EnablePushWhitelist"
|
||||||
},
|
},
|
||||||
|
"enable_force_push": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "EnableForcePush"
|
||||||
|
},
|
||||||
|
"enable_force_push_whitelist": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "EnableForcePushWhitelist"
|
||||||
|
},
|
||||||
"enable_status_check": {
|
"enable_status_check": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "EnableStatusCheck"
|
"x-go-name": "EnableStatusCheck"
|
||||||
@ -18739,6 +18799,24 @@
|
|||||||
},
|
},
|
||||||
"x-go-name": "PushWhitelistUsernames"
|
"x-go-name": "PushWhitelistUsernames"
|
||||||
},
|
},
|
||||||
|
"force_push_whitelist_deploy_keys": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "ForcePushWhitelistDeployKeys"
|
||||||
|
},
|
||||||
|
"force_push_whitelist_teams": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "ForcePushWhitelistTeams"
|
||||||
|
},
|
||||||
|
"force_push_whitelist_usernames": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "ForcePushWhitelistUsernames"
|
||||||
|
},
|
||||||
"require_signed_commits": {
|
"require_signed_commits": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "RequireSignedCommits"
|
"x-go-name": "RequireSignedCommits"
|
||||||
|
Loading…
Reference in New Issue
Block a user