feat: org branch protection per-user (username/email) allowlists + actions-bot toggle (#727) #750
@@ -28,19 +28,28 @@ type OrgProtectedBranch struct {
|
||||
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableWhitelist bool `xorm:"NOT NULL DEFAULT false"`
|
||||
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
WhitelistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"`
|
||||
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
MergeWhitelistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CanForcePush bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableForcePushAllowlist bool `xorm:"NOT NULL DEFAULT false"`
|
||||
ForcePushAllowlistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||
ForcePushAllowlistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
ForcePushAllowlistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CanDelete bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableDeleteAllowlist bool `xorm:"NOT NULL DEFAULT false"`
|
||||
DeleteAllowlistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||
DeleteAllowlistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
DeleteAllowlistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`
|
||||
StatusCheckContexts []string `xorm:"JSON TEXT"`
|
||||
RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||
EnableApprovalsWhitelist bool `xorm:"NOT NULL DEFAULT false"`
|
||||
ApprovalsWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
|
||||
ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
BlockOnRejectedReviews bool `xorm:"NOT NULL DEFAULT false"`
|
||||
BlockOnOfficialReviewRequests bool `xorm:"NOT NULL DEFAULT false"`
|
||||
BlockOnOutdatedBranch bool `xorm:"NOT NULL DEFAULT false"`
|
||||
@@ -84,8 +93,9 @@ func (o *OrgProtectedBranch) Match(branchName string) bool {
|
||||
}
|
||||
|
||||
// ToProtectedBranch converts an org-level rule to a ProtectedBranch for use
|
||||
// in the standard enforcement path. Fields that are user-scoped (WhitelistUserIDs etc.)
|
||||
// are left empty because org rules only reference teams.
|
||||
// in the standard enforcement path. Both team-scoped and user-scoped allowlists
|
||||
// (plus the Actions-bot toggles) are carried across; deploy-key allowances remain
|
||||
// repo-only because an org rule cannot express them.
|
||||
func (o *OrgProtectedBranch) ToProtectedBranch() *ProtectedBranch {
|
||||
return &ProtectedBranch{
|
||||
ID: o.ID,
|
||||
@@ -94,19 +104,28 @@ func (o *OrgProtectedBranch) ToProtectedBranch() *ProtectedBranch {
|
||||
CanPush: o.CanPush,
|
||||
EnableWhitelist: o.EnableWhitelist,
|
||||
WhitelistTeamIDs: o.WhitelistTeamIDs,
|
||||
WhitelistUserIDs: o.WhitelistUserIDs,
|
||||
WhitelistActionsUser: o.WhitelistActionsUser,
|
||||
EnableMergeWhitelist: o.EnableMergeWhitelist,
|
||||
MergeWhitelistTeamIDs: o.MergeWhitelistTeamIDs,
|
||||
MergeWhitelistUserIDs: o.MergeWhitelistUserIDs,
|
||||
MergeWhitelistActionsUser: o.MergeWhitelistActionsUser,
|
||||
CanForcePush: o.CanForcePush,
|
||||
EnableForcePushAllowlist: o.EnableForcePushAllowlist,
|
||||
ForcePushAllowlistTeamIDs: o.ForcePushAllowlistTeamIDs,
|
||||
ForcePushAllowlistUserIDs: o.ForcePushAllowlistUserIDs,
|
||||
ForcePushAllowlistActionsUser: o.ForcePushAllowlistActionsUser,
|
||||
CanDelete: o.CanDelete,
|
||||
EnableDeleteAllowlist: o.EnableDeleteAllowlist,
|
||||
DeleteAllowlistTeamIDs: o.DeleteAllowlistTeamIDs,
|
||||
DeleteAllowlistUserIDs: o.DeleteAllowlistUserIDs,
|
||||
DeleteAllowlistActionsUser: o.DeleteAllowlistActionsUser,
|
||||
EnableStatusCheck: o.EnableStatusCheck,
|
||||
StatusCheckContexts: o.StatusCheckContexts,
|
||||
RequiredApprovals: o.RequiredApprovals,
|
||||
EnableApprovalsWhitelist: o.EnableApprovalsWhitelist,
|
||||
ApprovalsWhitelistTeamIDs: o.ApprovalsWhitelistTeamIDs,
|
||||
ApprovalsWhitelistUserIDs: o.ApprovalsWhitelistUserIDs,
|
||||
BlockOnRejectedReviews: o.BlockOnRejectedReviews,
|
||||
BlockOnOfficialReviewRequests: o.BlockOnOfficialReviewRequests,
|
||||
BlockOnOutdatedBranch: o.BlockOnOutdatedBranch,
|
||||
|
||||
@@ -26,32 +26,32 @@ func mergeMostRestrictive(repoRule, orgRule *ProtectedBranch) *ProtectedBranch {
|
||||
eff.CanPush = repoRule.CanPush && orgRule.CanPush
|
||||
eff.EnableWhitelist, eff.WhitelistUserIDs = mergeAllowlist(repoRule.EnableWhitelist, repoRule.WhitelistUserIDs, orgRule.EnableWhitelist, orgRule.WhitelistUserIDs)
|
||||
_, eff.WhitelistTeamIDs = mergeAllowlist(repoRule.EnableWhitelist, repoRule.WhitelistTeamIDs, orgRule.EnableWhitelist, orgRule.WhitelistTeamIDs)
|
||||
// Deploy-key and Actions-user allowances are not expressible in an
|
||||
// OrgProtectedBranch (it is team-only), so the org rule imposes no constraint on
|
||||
// them; carry the repo values through unchanged. ANDing against the org side's
|
||||
// always-false zero value would silently lock out every deploy-key and
|
||||
// Actions-bot push in any org that has a matching branch rule (see #727 review).
|
||||
// Deploy-key allowances are still not expressible in an OrgProtectedBranch, so the
|
||||
// org rule imposes no constraint on them; carry the repo value through unchanged.
|
||||
// ANDing against the org side's always-false zero value would silently lock out
|
||||
// every deploy-key push in any org that has a matching branch rule (see #727 review).
|
||||
// The Actions-bot toggle IS now expressible org-side, so merge it most-restrictively.
|
||||
eff.WhitelistDeployKeys = repoRule.WhitelistDeployKeys
|
||||
eff.WhitelistActionsUser = repoRule.WhitelistActionsUser
|
||||
eff.WhitelistActionsUser = mergeAllowFlag(repoRule.EnableWhitelist, repoRule.WhitelistActionsUser, orgRule.EnableWhitelist, orgRule.WhitelistActionsUser)
|
||||
|
||||
// Force push.
|
||||
eff.CanForcePush = repoRule.CanForcePush && orgRule.CanForcePush
|
||||
eff.EnableForcePushAllowlist, eff.ForcePushAllowlistUserIDs = mergeAllowlist(repoRule.EnableForcePushAllowlist, repoRule.ForcePushAllowlistUserIDs, orgRule.EnableForcePushAllowlist, orgRule.ForcePushAllowlistUserIDs)
|
||||
_, eff.ForcePushAllowlistTeamIDs = mergeAllowlist(repoRule.EnableForcePushAllowlist, repoRule.ForcePushAllowlistTeamIDs, orgRule.EnableForcePushAllowlist, orgRule.ForcePushAllowlistTeamIDs)
|
||||
eff.ForcePushAllowlistDeployKeys = repoRule.ForcePushAllowlistDeployKeys
|
||||
eff.ForcePushAllowlistActionsUser = repoRule.ForcePushAllowlistActionsUser
|
||||
eff.ForcePushAllowlistActionsUser = mergeAllowFlag(repoRule.EnableForcePushAllowlist, repoRule.ForcePushAllowlistActionsUser, orgRule.EnableForcePushAllowlist, orgRule.ForcePushAllowlistActionsUser)
|
||||
|
||||
// Delete.
|
||||
eff.CanDelete = repoRule.CanDelete && orgRule.CanDelete
|
||||
eff.EnableDeleteAllowlist, eff.DeleteAllowlistUserIDs = mergeAllowlist(repoRule.EnableDeleteAllowlist, repoRule.DeleteAllowlistUserIDs, orgRule.EnableDeleteAllowlist, orgRule.DeleteAllowlistUserIDs)
|
||||
_, eff.DeleteAllowlistTeamIDs = mergeAllowlist(repoRule.EnableDeleteAllowlist, repoRule.DeleteAllowlistTeamIDs, orgRule.EnableDeleteAllowlist, orgRule.DeleteAllowlistTeamIDs)
|
||||
eff.DeleteAllowlistDeployKeys = repoRule.DeleteAllowlistDeployKeys
|
||||
eff.DeleteAllowlistActionsUser = repoRule.DeleteAllowlistActionsUser
|
||||
eff.DeleteAllowlistActionsUser = mergeAllowFlag(repoRule.EnableDeleteAllowlist, repoRule.DeleteAllowlistActionsUser, orgRule.EnableDeleteAllowlist, orgRule.DeleteAllowlistActionsUser)
|
||||
|
||||
// Merge whitelist.
|
||||
eff.EnableMergeWhitelist, eff.MergeWhitelistUserIDs = mergeAllowlist(repoRule.EnableMergeWhitelist, repoRule.MergeWhitelistUserIDs, orgRule.EnableMergeWhitelist, orgRule.MergeWhitelistUserIDs)
|
||||
_, eff.MergeWhitelistTeamIDs = mergeAllowlist(repoRule.EnableMergeWhitelist, repoRule.MergeWhitelistTeamIDs, orgRule.EnableMergeWhitelist, orgRule.MergeWhitelistTeamIDs)
|
||||
eff.MergeWhitelistActionsUser = repoRule.MergeWhitelistActionsUser
|
||||
eff.MergeWhitelistActionsUser = mergeAllowFlag(repoRule.EnableMergeWhitelist, repoRule.MergeWhitelistActionsUser, orgRule.EnableMergeWhitelist, orgRule.MergeWhitelistActionsUser)
|
||||
|
||||
// Status checks.
|
||||
eff.EnableStatusCheck = repoRule.EnableStatusCheck || orgRule.EnableStatusCheck
|
||||
@@ -94,6 +94,25 @@ func mergeAllowlist(aEnabled bool, aIDs []int64, bEnabled bool, bIDs []int64) (b
|
||||
}
|
||||
}
|
||||
|
||||
// mergeAllowFlag combines two "allow the Actions bot" toggles under most-restrictive
|
||||
// semantics, mirroring mergeAllowlist. A toggle only grants access when its Enable flag
|
||||
// is set; a disabled allowlist means "everyone", so it imposes no constraint. Therefore:
|
||||
// if both allowlists are enabled the bot is allowed only when BOTH sides allow it; if
|
||||
// only one is enabled that side's flag governs; if neither is enabled the flag is
|
||||
// irrelevant (fall back to the repo/a value).
|
||||
func mergeAllowFlag(aEnabled, aFlag, bEnabled, bFlag bool) bool {
|
||||
switch {
|
||||
case aEnabled && bEnabled:
|
||||
return aFlag && bFlag
|
||||
case aEnabled:
|
||||
return aFlag
|
||||
case bEnabled:
|
||||
return bFlag
|
||||
default:
|
||||
return aFlag
|
||||
}
|
||||
}
|
||||
|
||||
func intersectInt64(a, b []int64) []int64 {
|
||||
if len(a) == 0 || len(b) == 0 {
|
||||
return nil
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMergeAllowFlag(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
aEnabled bool
|
||||
aFlag bool
|
||||
bEnabled bool
|
||||
bFlag bool
|
||||
expected bool
|
||||
}{
|
||||
// Both allowlists enabled: bot allowed only when BOTH allow it.
|
||||
{"both enabled, both allow", true, true, true, true, true},
|
||||
{"both enabled, a denies", true, false, true, true, false},
|
||||
{"both enabled, b denies", true, true, true, false, false},
|
||||
{"both enabled, both deny", true, false, true, false, false},
|
||||
// Only one side enabled: that side governs.
|
||||
{"only a enabled, a allows", true, true, false, false, true},
|
||||
{"only a enabled, a denies", true, false, false, true, false},
|
||||
{"only b enabled, b allows", false, false, true, true, true},
|
||||
{"only b enabled, b denies", false, true, true, false, false},
|
||||
// Neither enabled: flag irrelevant, falls back to a's flag.
|
||||
{"neither enabled, a true", false, true, false, false, true},
|
||||
{"neither enabled, a false", false, false, false, true, false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
assert.Equal(t, c.expected, mergeAllowFlag(c.aEnabled, c.aFlag, c.bEnabled, c.bFlag))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeMostRestrictiveUserIDsIntersect(t *testing.T) {
|
||||
repoRule := &ProtectedBranch{
|
||||
EnableWhitelist: true,
|
||||
WhitelistUserIDs: []int64{1, 2, 3},
|
||||
// Deploy keys are repo-only and must always pass through unchanged.
|
||||
WhitelistDeployKeys: true,
|
||||
ForcePushAllowlistDeployKeys: true,
|
||||
DeleteAllowlistDeployKeys: true,
|
||||
}
|
||||
orgRule := &ProtectedBranch{
|
||||
EnableWhitelist: true,
|
||||
WhitelistUserIDs: []int64{2, 3, 4},
|
||||
// Org rule cannot express deploy keys; these zero values must NOT override repo.
|
||||
}
|
||||
|
||||
eff := mergeMostRestrictive(repoRule, orgRule)
|
||||
|
||||
// User IDs are intersected when both allowlists are enabled.
|
||||
assert.True(t, eff.EnableWhitelist)
|
||||
assert.ElementsMatch(t, []int64{2, 3}, eff.WhitelistUserIDs)
|
||||
|
||||
// Deploy-key allowances still pass through from the repo rule.
|
||||
assert.True(t, eff.WhitelistDeployKeys)
|
||||
assert.True(t, eff.ForcePushAllowlistDeployKeys)
|
||||
assert.True(t, eff.DeleteAllowlistDeployKeys)
|
||||
}
|
||||
|
||||
func TestMergeMostRestrictiveActionsUserFlags(t *testing.T) {
|
||||
// Both sides enable their allowlist and both allow the bot -> allowed.
|
||||
repoRule := &ProtectedBranch{
|
||||
EnableWhitelist: true,
|
||||
WhitelistActionsUser: true,
|
||||
EnableForcePushAllowlist: true,
|
||||
// force-push: org denies -> effective deny.
|
||||
ForcePushAllowlistActionsUser: true,
|
||||
EnableDeleteAllowlist: true,
|
||||
DeleteAllowlistActionsUser: true,
|
||||
// merge: repo allowlist disabled, org enabled+denies -> org governs (deny).
|
||||
EnableMergeWhitelist: false,
|
||||
MergeWhitelistActionsUser: true,
|
||||
}
|
||||
orgRule := &ProtectedBranch{
|
||||
EnableWhitelist: true,
|
||||
WhitelistActionsUser: true,
|
||||
EnableForcePushAllowlist: true,
|
||||
ForcePushAllowlistActionsUser: false,
|
||||
EnableDeleteAllowlist: true,
|
||||
DeleteAllowlistActionsUser: true,
|
||||
EnableMergeWhitelist: true,
|
||||
MergeWhitelistActionsUser: false,
|
||||
}
|
||||
|
||||
eff := mergeMostRestrictive(repoRule, orgRule)
|
||||
|
||||
assert.True(t, eff.WhitelistActionsUser, "push: both allow")
|
||||
assert.False(t, eff.ForcePushAllowlistActionsUser, "force-push: org denies")
|
||||
assert.True(t, eff.DeleteAllowlistActionsUser, "delete: both allow")
|
||||
assert.False(t, eff.MergeWhitelistActionsUser, "merge: org enabled and denies")
|
||||
}
|
||||
@@ -444,6 +444,7 @@ func prepareMigrationTasks() []*migration {
|
||||
newMigration(364, "Add org push policy table", v1_27.AddOrgPushPolicyTable),
|
||||
newMigration(365, "Add org repo defaults table", v1_27.AddOrgRepoDefaultsTable),
|
||||
newMigration(366, "Add org email domain policy table", v1_27.AddOrgEmailDomainPolicyTable),
|
||||
newMigration(367, "Add user allowlists to org protected branch", v1_27.AddUserAllowlistsToOrgProtectedBranch),
|
||||
}
|
||||
return preparedMigrations
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package v1_27
|
||||
|
||||
import "xorm.io/xorm"
|
||||
|
||||
// AddUserAllowlistsToOrgProtectedBranch adds per-user allowlist columns (username or
|
||||
// email resolved to user IDs) plus the "allow Actions bot" toggles to org-level branch
|
||||
// protection rules for the push, merge, force-push and delete categories, mirroring the
|
||||
// per-repo user allowlists so an org rule can also grant access to individual users and
|
||||
// the Actions bot. See issue #727.
|
||||
func AddUserAllowlistsToOrgProtectedBranch(x *xorm.Engine) error {
|
||||
type OrgProtectedBranch struct {
|
||||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
WhitelistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
MergeWhitelistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
ForcePushAllowlistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
ForcePushAllowlistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
DeleteAllowlistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
DeleteAllowlistActionsUser bool `xorm:"NOT NULL DEFAULT false"`
|
||||
ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
|
||||
}
|
||||
return x.Sync(new(OrgProtectedBranch))
|
||||
}
|
||||
@@ -14,19 +14,28 @@ type OrgBranchProtection struct {
|
||||
EnablePush bool `json:"enable_push"`
|
||||
EnablePushWhitelist bool `json:"enable_push_whitelist"`
|
||||
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
||||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
||||
PushWhitelistActionsUser bool `json:"push_whitelist_actions_user"`
|
||||
EnableForcePush bool `json:"enable_force_push"`
|
||||
EnableForcePushAllowlist bool `json:"enable_force_push_allowlist"`
|
||||
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
|
||||
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
|
||||
ForcePushAllowlistActionsUser bool `json:"force_push_allowlist_actions_user"`
|
||||
EnableDelete bool `json:"enable_delete"`
|
||||
EnableDeleteAllowlist bool `json:"enable_delete_allowlist"`
|
||||
DeleteAllowlistTeams []string `json:"delete_allowlist_teams"`
|
||||
DeleteAllowlistUsernames []string `json:"delete_allowlist_usernames"`
|
||||
DeleteAllowlistActionsUser bool `json:"delete_allowlist_actions_user"`
|
||||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
|
||||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
||||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
||||
MergeWhitelistActionsUser bool `json:"merge_whitelist_actions_user"`
|
||||
EnableStatusCheck bool `json:"enable_status_check"`
|
||||
StatusCheckContexts []string `json:"status_check_contexts"`
|
||||
RequiredApprovals int64 `json:"required_approvals"`
|
||||
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist"`
|
||||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"`
|
||||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
|
||||
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"`
|
||||
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests"`
|
||||
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"`
|
||||
@@ -49,19 +58,28 @@ type CreateOrgBranchProtectionOption struct {
|
||||
EnablePush bool `json:"enable_push"`
|
||||
EnablePushWhitelist bool `json:"enable_push_whitelist"`
|
||||
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
||||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
||||
PushWhitelistActionsUser bool `json:"push_whitelist_actions_user"`
|
||||
EnableForcePush bool `json:"enable_force_push"`
|
||||
EnableForcePushAllowlist bool `json:"enable_force_push_allowlist"`
|
||||
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
|
||||
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
|
||||
ForcePushAllowlistActionsUser bool `json:"force_push_allowlist_actions_user"`
|
||||
EnableDelete bool `json:"enable_delete"`
|
||||
EnableDeleteAllowlist bool `json:"enable_delete_allowlist"`
|
||||
DeleteAllowlistTeams []string `json:"delete_allowlist_teams"`
|
||||
DeleteAllowlistUsernames []string `json:"delete_allowlist_usernames"`
|
||||
DeleteAllowlistActionsUser bool `json:"delete_allowlist_actions_user"`
|
||||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
|
||||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
||||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
||||
MergeWhitelistActionsUser bool `json:"merge_whitelist_actions_user"`
|
||||
EnableStatusCheck bool `json:"enable_status_check"`
|
||||
StatusCheckContexts []string `json:"status_check_contexts"`
|
||||
RequiredApprovals int64 `json:"required_approvals"`
|
||||
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist"`
|
||||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"`
|
||||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
|
||||
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"`
|
||||
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests"`
|
||||
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"`
|
||||
@@ -79,19 +97,28 @@ type EditOrgBranchProtectionOption struct {
|
||||
EnablePush *bool `json:"enable_push"`
|
||||
EnablePushWhitelist *bool `json:"enable_push_whitelist"`
|
||||
PushWhitelistTeams []string `json:"push_whitelist_teams"`
|
||||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
|
||||
PushWhitelistActionsUser *bool `json:"push_whitelist_actions_user"`
|
||||
EnableForcePush *bool `json:"enable_force_push"`
|
||||
EnableForcePushAllowlist *bool `json:"enable_force_push_allowlist"`
|
||||
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
|
||||
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
|
||||
ForcePushAllowlistActionsUser *bool `json:"force_push_allowlist_actions_user"`
|
||||
EnableDelete *bool `json:"enable_delete"`
|
||||
EnableDeleteAllowlist *bool `json:"enable_delete_allowlist"`
|
||||
DeleteAllowlistTeams []string `json:"delete_allowlist_teams"`
|
||||
DeleteAllowlistUsernames []string `json:"delete_allowlist_usernames"`
|
||||
DeleteAllowlistActionsUser *bool `json:"delete_allowlist_actions_user"`
|
||||
EnableMergeWhitelist *bool `json:"enable_merge_whitelist"`
|
||||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
|
||||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
|
||||
MergeWhitelistActionsUser *bool `json:"merge_whitelist_actions_user"`
|
||||
EnableStatusCheck *bool `json:"enable_status_check"`
|
||||
StatusCheckContexts []string `json:"status_check_contexts"`
|
||||
RequiredApprovals *int64 `json:"required_approvals"`
|
||||
EnableApprovalsWhitelist *bool `json:"enable_approvals_whitelist"`
|
||||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"`
|
||||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
|
||||
BlockOnRejectedReviews *bool `json:"block_on_rejected_reviews"`
|
||||
BlockOnOfficialReviewRequests *bool `json:"block_on_official_review_requests"`
|
||||
BlockOnOutdatedBranch *bool `json:"block_on_outdated_branch"`
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
git_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/git"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/organization"
|
||||
user_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user"
|
||||
api "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/web"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context"
|
||||
@@ -36,6 +37,18 @@ func toAPIOrgBranchProtection(ctx *context.APIContext, rule *git_model.OrgProtec
|
||||
return names
|
||||
}
|
||||
|
||||
resolveUserNames := func(ids []int64) []string {
|
||||
names := make([]string, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
u, err := user_model.GetUserByID(ctx, id)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
names = append(names, u.Name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
return &api.OrgBranchProtection{
|
||||
ID: rule.ID,
|
||||
OrgID: rule.OrgID,
|
||||
@@ -44,19 +57,28 @@ func toAPIOrgBranchProtection(ctx *context.APIContext, rule *git_model.OrgProtec
|
||||
EnablePush: rule.CanPush,
|
||||
EnablePushWhitelist: rule.EnableWhitelist,
|
||||
PushWhitelistTeams: resolveTeamNames(rule.WhitelistTeamIDs),
|
||||
PushWhitelistUsernames: resolveUserNames(rule.WhitelistUserIDs),
|
||||
PushWhitelistActionsUser: rule.WhitelistActionsUser,
|
||||
EnableForcePush: rule.CanForcePush,
|
||||
EnableForcePushAllowlist: rule.EnableForcePushAllowlist,
|
||||
ForcePushAllowlistTeams: resolveTeamNames(rule.ForcePushAllowlistTeamIDs),
|
||||
ForcePushAllowlistUsernames: resolveUserNames(rule.ForcePushAllowlistUserIDs),
|
||||
ForcePushAllowlistActionsUser: rule.ForcePushAllowlistActionsUser,
|
||||
EnableDelete: rule.CanDelete,
|
||||
EnableDeleteAllowlist: rule.EnableDeleteAllowlist,
|
||||
DeleteAllowlistTeams: resolveTeamNames(rule.DeleteAllowlistTeamIDs),
|
||||
DeleteAllowlistUsernames: resolveUserNames(rule.DeleteAllowlistUserIDs),
|
||||
DeleteAllowlistActionsUser: rule.DeleteAllowlistActionsUser,
|
||||
EnableMergeWhitelist: rule.EnableMergeWhitelist,
|
||||
MergeWhitelistTeams: resolveTeamNames(rule.MergeWhitelistTeamIDs),
|
||||
MergeWhitelistUsernames: resolveUserNames(rule.MergeWhitelistUserIDs),
|
||||
MergeWhitelistActionsUser: rule.MergeWhitelistActionsUser,
|
||||
EnableStatusCheck: rule.EnableStatusCheck,
|
||||
StatusCheckContexts: rule.StatusCheckContexts,
|
||||
RequiredApprovals: rule.RequiredApprovals,
|
||||
EnableApprovalsWhitelist: rule.EnableApprovalsWhitelist,
|
||||
ApprovalsWhitelistTeams: resolveTeamNames(rule.ApprovalsWhitelistTeamIDs),
|
||||
ApprovalsWhitelistUsernames: resolveUserNames(rule.ApprovalsWhitelistUserIDs),
|
||||
BlockOnRejectedReviews: rule.BlockOnRejectedReviews,
|
||||
BlockOnOfficialReviewRequests: rule.BlockOnOfficialReviewRequests,
|
||||
BlockOnOutdatedBranch: rule.BlockOnOutdatedBranch,
|
||||
@@ -88,6 +110,41 @@ func resolveTeamIDs(ctx *context.APIContext, orgID int64, names []string) ([]int
|
||||
return ids, true
|
||||
}
|
||||
|
||||
// resolveUserIDs converts a list of user identifiers (each a username or an email
|
||||
// address) to deduped user IDs, returning 422 on the first unknown identifier. Each
|
||||
// entry is looked up by username first, then falls back to an activated email address.
|
||||
func resolveUserIDs(ctx *context.APIContext, names []string) ([]int64, bool) {
|
||||
if len(names) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
seen := make(map[int64]struct{}, len(names))
|
||||
ids := make([]int64, 0, len(names))
|
||||
for _, name := range names {
|
||||
u, err := user_model.GetUserByName(ctx, name)
|
||||
if err != nil {
|
||||
if !user_model.IsErrUserNotExist(err) {
|
||||
ctx.APIErrorInternal(err)
|
||||
return nil, false
|
||||
}
|
||||
u, err = user_model.GetUserByEmail(ctx, name)
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.APIError(http.StatusUnprocessableEntity, "unknown user: "+name)
|
||||
} else {
|
||||
ctx.APIErrorInternal(err)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
if _, dup := seen[u.ID]; dup {
|
||||
continue
|
||||
}
|
||||
seen[u.ID] = struct{}{}
|
||||
ids = append(ids, u.ID)
|
||||
}
|
||||
return ids, true
|
||||
}
|
||||
|
||||
// ListOrgBranchProtections list org-level branch protection rules
|
||||
func ListOrgBranchProtections(ctx *context.APIContext) {
|
||||
// swagger:operation GET /orgs/{org}/branch_protections organization orgListBranchProtections
|
||||
@@ -218,6 +275,26 @@ func CreateOrgBranchProtection(ctx *context.APIContext) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
pushUsers, ok := resolveUserIDs(ctx, form.PushWhitelistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
forcePushUsers, ok := resolveUserIDs(ctx, form.ForcePushAllowlistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
mergeUsers, ok := resolveUserIDs(ctx, form.MergeWhitelistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
approvalsUsers, ok := resolveUserIDs(ctx, form.ApprovalsWhitelistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
deleteUsers, ok := resolveUserIDs(ctx, form.DeleteAllowlistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
rule := &git_model.OrgProtectedBranch{
|
||||
OrgID: orgID,
|
||||
@@ -226,19 +303,28 @@ func CreateOrgBranchProtection(ctx *context.APIContext) {
|
||||
CanPush: form.EnablePush,
|
||||
EnableWhitelist: form.EnablePush && form.EnablePushWhitelist,
|
||||
WhitelistTeamIDs: pushTeams,
|
||||
WhitelistUserIDs: pushUsers,
|
||||
WhitelistActionsUser: form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistActionsUser,
|
||||
CanForcePush: form.EnablePush && form.EnableForcePush,
|
||||
EnableForcePushAllowlist: form.EnablePush && form.EnableForcePush && form.EnableForcePushAllowlist,
|
||||
ForcePushAllowlistTeamIDs: forcePushTeams,
|
||||
ForcePushAllowlistUserIDs: forcePushUsers,
|
||||
ForcePushAllowlistActionsUser: form.EnablePush && form.EnableForcePush && form.EnableForcePushAllowlist && form.ForcePushAllowlistActionsUser,
|
||||
CanDelete: form.EnableDelete,
|
||||
EnableDeleteAllowlist: form.EnableDelete && form.EnableDeleteAllowlist,
|
||||
DeleteAllowlistTeamIDs: deleteTeams,
|
||||
DeleteAllowlistUserIDs: deleteUsers,
|
||||
DeleteAllowlistActionsUser: form.EnableDelete && form.EnableDeleteAllowlist && form.DeleteAllowlistActionsUser,
|
||||
EnableMergeWhitelist: form.EnableMergeWhitelist,
|
||||
MergeWhitelistTeamIDs: mergeTeams,
|
||||
MergeWhitelistUserIDs: mergeUsers,
|
||||
MergeWhitelistActionsUser: form.EnableMergeWhitelist && form.MergeWhitelistActionsUser,
|
||||
EnableStatusCheck: form.EnableStatusCheck,
|
||||
StatusCheckContexts: form.StatusCheckContexts,
|
||||
RequiredApprovals: form.RequiredApprovals,
|
||||
EnableApprovalsWhitelist: form.EnableApprovalsWhitelist,
|
||||
ApprovalsWhitelistTeamIDs: approvalsTeams,
|
||||
ApprovalsWhitelistUserIDs: approvalsUsers,
|
||||
BlockOnRejectedReviews: form.BlockOnRejectedReviews,
|
||||
BlockOnOfficialReviewRequests: form.BlockOnOfficialReviewRequests,
|
||||
BlockOnOutdatedBranch: form.BlockOnOutdatedBranch,
|
||||
@@ -320,6 +406,16 @@ func EditOrgBranchProtection(ctx *context.APIContext) {
|
||||
}
|
||||
rule.WhitelistTeamIDs = ids
|
||||
}
|
||||
if form.PushWhitelistUsernames != nil {
|
||||
ids, ok := resolveUserIDs(ctx, form.PushWhitelistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
rule.WhitelistUserIDs = ids
|
||||
}
|
||||
if form.PushWhitelistActionsUser != nil {
|
||||
rule.WhitelistActionsUser = *form.PushWhitelistActionsUser
|
||||
}
|
||||
if form.EnableForcePush != nil {
|
||||
rule.CanForcePush = *form.EnableForcePush
|
||||
}
|
||||
@@ -333,6 +429,16 @@ func EditOrgBranchProtection(ctx *context.APIContext) {
|
||||
}
|
||||
rule.ForcePushAllowlistTeamIDs = ids
|
||||
}
|
||||
if form.ForcePushAllowlistUsernames != nil {
|
||||
ids, ok := resolveUserIDs(ctx, form.ForcePushAllowlistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
rule.ForcePushAllowlistUserIDs = ids
|
||||
}
|
||||
if form.ForcePushAllowlistActionsUser != nil {
|
||||
rule.ForcePushAllowlistActionsUser = *form.ForcePushAllowlistActionsUser
|
||||
}
|
||||
if form.EnableDelete != nil {
|
||||
rule.CanDelete = *form.EnableDelete
|
||||
}
|
||||
@@ -346,6 +452,16 @@ func EditOrgBranchProtection(ctx *context.APIContext) {
|
||||
}
|
||||
rule.DeleteAllowlistTeamIDs = ids
|
||||
}
|
||||
if form.DeleteAllowlistUsernames != nil {
|
||||
ids, ok := resolveUserIDs(ctx, form.DeleteAllowlistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
rule.DeleteAllowlistUserIDs = ids
|
||||
}
|
||||
if form.DeleteAllowlistActionsUser != nil {
|
||||
rule.DeleteAllowlistActionsUser = *form.DeleteAllowlistActionsUser
|
||||
}
|
||||
if form.EnableMergeWhitelist != nil {
|
||||
rule.EnableMergeWhitelist = *form.EnableMergeWhitelist
|
||||
}
|
||||
@@ -356,6 +472,16 @@ func EditOrgBranchProtection(ctx *context.APIContext) {
|
||||
}
|
||||
rule.MergeWhitelistTeamIDs = ids
|
||||
}
|
||||
if form.MergeWhitelistUsernames != nil {
|
||||
ids, ok := resolveUserIDs(ctx, form.MergeWhitelistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
rule.MergeWhitelistUserIDs = ids
|
||||
}
|
||||
if form.MergeWhitelistActionsUser != nil {
|
||||
rule.MergeWhitelistActionsUser = *form.MergeWhitelistActionsUser
|
||||
}
|
||||
if form.EnableStatusCheck != nil {
|
||||
rule.EnableStatusCheck = *form.EnableStatusCheck
|
||||
}
|
||||
@@ -375,6 +501,13 @@ func EditOrgBranchProtection(ctx *context.APIContext) {
|
||||
}
|
||||
rule.ApprovalsWhitelistTeamIDs = ids
|
||||
}
|
||||
if form.ApprovalsWhitelistUsernames != nil {
|
||||
ids, ok := resolveUserIDs(ctx, form.ApprovalsWhitelistUsernames)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
rule.ApprovalsWhitelistUserIDs = ids
|
||||
}
|
||||
if form.BlockOnRejectedReviews != nil {
|
||||
rule.BlockOnRejectedReviews = *form.BlockOnRejectedReviews
|
||||
}
|
||||
|
||||
Generated
+153
@@ -25356,6 +25356,13 @@
|
||||
},
|
||||
"x-go-name": "ApprovalsWhitelistTeams"
|
||||
},
|
||||
"approvals_whitelist_username": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "ApprovalsWhitelistUsernames"
|
||||
},
|
||||
"block_admin_merge_override": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockAdminMergeOverride"
|
||||
@@ -25372,6 +25379,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockOnRejectedReviews"
|
||||
},
|
||||
"delete_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DeleteAllowlistActionsUser"
|
||||
},
|
||||
"delete_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -25379,6 +25390,13 @@
|
||||
},
|
||||
"x-go-name": "DeleteAllowlistTeams"
|
||||
},
|
||||
"delete_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "DeleteAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -25419,6 +25437,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableStatusCheck"
|
||||
},
|
||||
"force_push_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "ForcePushAllowlistActionsUser"
|
||||
},
|
||||
"force_push_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -25426,10 +25448,21 @@
|
||||
},
|
||||
"x-go-name": "ForcePushAllowlistTeams"
|
||||
},
|
||||
"force_push_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "ForcePushAllowlistUsernames"
|
||||
},
|
||||
"ignore_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "IgnoreStaleApprovals"
|
||||
},
|
||||
"merge_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "MergeWhitelistActionsUser"
|
||||
},
|
||||
"merge_whitelist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -25437,6 +25470,13 @@
|
||||
},
|
||||
"x-go-name": "MergeWhitelistTeams"
|
||||
},
|
||||
"merge_whitelist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "MergeWhitelistUsernames"
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
@@ -25446,6 +25486,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "ProtectedFilePatterns"
|
||||
},
|
||||
"push_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "PushWhitelistActionsUser"
|
||||
},
|
||||
"push_whitelist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -25453,6 +25497,13 @@
|
||||
},
|
||||
"x-go-name": "PushWhitelistTeams"
|
||||
},
|
||||
"push_whitelist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "PushWhitelistUsernames"
|
||||
},
|
||||
"require_signed_commits": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "RequireSignedCommits"
|
||||
@@ -26786,6 +26837,13 @@
|
||||
},
|
||||
"x-go-name": "ApprovalsWhitelistTeams"
|
||||
},
|
||||
"approvals_whitelist_username": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "ApprovalsWhitelistUsernames"
|
||||
},
|
||||
"block_admin_merge_override": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockAdminMergeOverride"
|
||||
@@ -26802,6 +26860,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockOnRejectedReviews"
|
||||
},
|
||||
"delete_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DeleteAllowlistActionsUser"
|
||||
},
|
||||
"delete_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -26809,6 +26871,13 @@
|
||||
},
|
||||
"x-go-name": "DeleteAllowlistTeams"
|
||||
},
|
||||
"delete_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "DeleteAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -26849,6 +26918,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableStatusCheck"
|
||||
},
|
||||
"force_push_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "ForcePushAllowlistActionsUser"
|
||||
},
|
||||
"force_push_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -26856,10 +26929,21 @@
|
||||
},
|
||||
"x-go-name": "ForcePushAllowlistTeams"
|
||||
},
|
||||
"force_push_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "ForcePushAllowlistUsernames"
|
||||
},
|
||||
"ignore_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "IgnoreStaleApprovals"
|
||||
},
|
||||
"merge_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "MergeWhitelistActionsUser"
|
||||
},
|
||||
"merge_whitelist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -26867,6 +26951,13 @@
|
||||
},
|
||||
"x-go-name": "MergeWhitelistTeams"
|
||||
},
|
||||
"merge_whitelist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "MergeWhitelistUsernames"
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
@@ -26876,6 +26967,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "ProtectedFilePatterns"
|
||||
},
|
||||
"push_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "PushWhitelistActionsUser"
|
||||
},
|
||||
"push_whitelist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -26883,6 +26978,13 @@
|
||||
},
|
||||
"x-go-name": "PushWhitelistTeams"
|
||||
},
|
||||
"push_whitelist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "PushWhitelistUsernames"
|
||||
},
|
||||
"require_signed_commits": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "RequireSignedCommits"
|
||||
@@ -29749,6 +29851,13 @@
|
||||
},
|
||||
"x-go-name": "ApprovalsWhitelistTeams"
|
||||
},
|
||||
"approvals_whitelist_username": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "ApprovalsWhitelistUsernames"
|
||||
},
|
||||
"block_admin_merge_override": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockAdminMergeOverride"
|
||||
@@ -29770,6 +29879,10 @@
|
||||
"format": "date-time",
|
||||
"x-go-name": "Created"
|
||||
},
|
||||
"delete_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DeleteAllowlistActionsUser"
|
||||
},
|
||||
"delete_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -29777,6 +29890,13 @@
|
||||
},
|
||||
"x-go-name": "DeleteAllowlistTeams"
|
||||
},
|
||||
"delete_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "DeleteAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -29817,6 +29937,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableStatusCheck"
|
||||
},
|
||||
"force_push_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "ForcePushAllowlistActionsUser"
|
||||
},
|
||||
"force_push_allowlist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -29824,6 +29948,13 @@
|
||||
},
|
||||
"x-go-name": "ForcePushAllowlistTeams"
|
||||
},
|
||||
"force_push_allowlist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "ForcePushAllowlistUsernames"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
@@ -29833,6 +29964,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "IgnoreStaleApprovals"
|
||||
},
|
||||
"merge_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "MergeWhitelistActionsUser"
|
||||
},
|
||||
"merge_whitelist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -29840,6 +29975,13 @@
|
||||
},
|
||||
"x-go-name": "MergeWhitelistTeams"
|
||||
},
|
||||
"merge_whitelist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "MergeWhitelistUsernames"
|
||||
},
|
||||
"org_id": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
@@ -29854,6 +29996,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "ProtectedFilePatterns"
|
||||
},
|
||||
"push_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "PushWhitelistActionsUser"
|
||||
},
|
||||
"push_whitelist_teams": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -29861,6 +30007,13 @@
|
||||
},
|
||||
"x-go-name": "PushWhitelistTeams"
|
||||
},
|
||||
"push_whitelist_usernames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "PushWhitelistUsernames"
|
||||
},
|
||||
"require_signed_commits": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "RequireSignedCommits"
|
||||
|
||||
@@ -4483,6 +4483,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "ApprovalsWhitelistTeams"
|
||||
},
|
||||
"approvals_whitelist_username": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "ApprovalsWhitelistUsernames"
|
||||
},
|
||||
"block_admin_merge_override": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockAdminMergeOverride"
|
||||
@@ -4499,6 +4506,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockOnRejectedReviews"
|
||||
},
|
||||
"delete_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DeleteAllowlistActionsUser"
|
||||
},
|
||||
"delete_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -4506,6 +4517,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "DeleteAllowlistTeams"
|
||||
},
|
||||
"delete_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "DeleteAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -4546,6 +4564,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableStatusCheck"
|
||||
},
|
||||
"force_push_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "ForcePushAllowlistActionsUser"
|
||||
},
|
||||
"force_push_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -4553,10 +4575,21 @@
|
||||
"type": "array",
|
||||
"x-go-name": "ForcePushAllowlistTeams"
|
||||
},
|
||||
"force_push_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "ForcePushAllowlistUsernames"
|
||||
},
|
||||
"ignore_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "IgnoreStaleApprovals"
|
||||
},
|
||||
"merge_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "MergeWhitelistActionsUser"
|
||||
},
|
||||
"merge_whitelist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -4564,6 +4597,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "MergeWhitelistTeams"
|
||||
},
|
||||
"merge_whitelist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "MergeWhitelistUsernames"
|
||||
},
|
||||
"priority": {
|
||||
"format": "int64",
|
||||
"type": "integer",
|
||||
@@ -4573,6 +4613,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "ProtectedFilePatterns"
|
||||
},
|
||||
"push_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "PushWhitelistActionsUser"
|
||||
},
|
||||
"push_whitelist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -4580,6 +4624,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "PushWhitelistTeams"
|
||||
},
|
||||
"push_whitelist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "PushWhitelistUsernames"
|
||||
},
|
||||
"require_signed_commits": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "RequireSignedCommits"
|
||||
@@ -5885,6 +5936,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "ApprovalsWhitelistTeams"
|
||||
},
|
||||
"approvals_whitelist_username": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "ApprovalsWhitelistUsernames"
|
||||
},
|
||||
"block_admin_merge_override": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockAdminMergeOverride"
|
||||
@@ -5901,6 +5959,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockOnRejectedReviews"
|
||||
},
|
||||
"delete_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DeleteAllowlistActionsUser"
|
||||
},
|
||||
"delete_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -5908,6 +5970,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "DeleteAllowlistTeams"
|
||||
},
|
||||
"delete_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "DeleteAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -5948,6 +6017,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableStatusCheck"
|
||||
},
|
||||
"force_push_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "ForcePushAllowlistActionsUser"
|
||||
},
|
||||
"force_push_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -5955,10 +6028,21 @@
|
||||
"type": "array",
|
||||
"x-go-name": "ForcePushAllowlistTeams"
|
||||
},
|
||||
"force_push_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "ForcePushAllowlistUsernames"
|
||||
},
|
||||
"ignore_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "IgnoreStaleApprovals"
|
||||
},
|
||||
"merge_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "MergeWhitelistActionsUser"
|
||||
},
|
||||
"merge_whitelist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -5966,6 +6050,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "MergeWhitelistTeams"
|
||||
},
|
||||
"merge_whitelist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "MergeWhitelistUsernames"
|
||||
},
|
||||
"priority": {
|
||||
"format": "int64",
|
||||
"type": "integer",
|
||||
@@ -5975,6 +6066,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "ProtectedFilePatterns"
|
||||
},
|
||||
"push_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "PushWhitelistActionsUser"
|
||||
},
|
||||
"push_whitelist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -5982,6 +6077,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "PushWhitelistTeams"
|
||||
},
|
||||
"push_whitelist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "PushWhitelistUsernames"
|
||||
},
|
||||
"require_signed_commits": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "RequireSignedCommits"
|
||||
@@ -8856,6 +8958,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "ApprovalsWhitelistTeams"
|
||||
},
|
||||
"approvals_whitelist_username": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "ApprovalsWhitelistUsernames"
|
||||
},
|
||||
"block_admin_merge_override": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "BlockAdminMergeOverride"
|
||||
@@ -8877,6 +8986,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "Created"
|
||||
},
|
||||
"delete_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DeleteAllowlistActionsUser"
|
||||
},
|
||||
"delete_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -8884,6 +8997,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "DeleteAllowlistTeams"
|
||||
},
|
||||
"delete_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "DeleteAllowlistUsernames"
|
||||
},
|
||||
"dismiss_stale_approvals": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "DismissStaleApprovals"
|
||||
@@ -8924,6 +9044,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableStatusCheck"
|
||||
},
|
||||
"force_push_allowlist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "ForcePushAllowlistActionsUser"
|
||||
},
|
||||
"force_push_allowlist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -8931,6 +9055,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "ForcePushAllowlistTeams"
|
||||
},
|
||||
"force_push_allowlist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "ForcePushAllowlistUsernames"
|
||||
},
|
||||
"id": {
|
||||
"format": "int64",
|
||||
"type": "integer",
|
||||
@@ -8940,6 +9071,10 @@
|
||||
"type": "boolean",
|
||||
"x-go-name": "IgnoreStaleApprovals"
|
||||
},
|
||||
"merge_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "MergeWhitelistActionsUser"
|
||||
},
|
||||
"merge_whitelist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -8947,6 +9082,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "MergeWhitelistTeams"
|
||||
},
|
||||
"merge_whitelist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "MergeWhitelistUsernames"
|
||||
},
|
||||
"org_id": {
|
||||
"format": "int64",
|
||||
"type": "integer",
|
||||
@@ -8961,6 +9103,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "ProtectedFilePatterns"
|
||||
},
|
||||
"push_whitelist_actions_user": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "PushWhitelistActionsUser"
|
||||
},
|
||||
"push_whitelist_teams": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -8968,6 +9114,13 @@
|
||||
"type": "array",
|
||||
"x-go-name": "PushWhitelistTeams"
|
||||
},
|
||||
"push_whitelist_usernames": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "PushWhitelistUsernames"
|
||||
},
|
||||
"require_signed_commits": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "RequireSignedCommits"
|
||||
|
||||
Reference in New Issue
Block a user