Skip to content

Commit 80c5967

Browse files
noerwlafriks
andcommitted
Cleanup protected branches when deleting users & teams (#19158)
* Clean up protected_branches when deleting user fixes #19094 * Clean up protected_branches when deleting teams * fix issue Co-authored-by: Lauris BH <[email protected]>
1 parent 3e5c844 commit 80c5967

File tree

3 files changed

+103
-2
lines changed

3 files changed

+103
-2
lines changed

Diff for: models/org_team.go

+40-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
user_model "code.gitea.io/gitea/models/user"
2020
"code.gitea.io/gitea/modules/log"
2121
"code.gitea.io/gitea/modules/setting"
22+
"code.gitea.io/gitea/modules/util"
2223

2324
"xorm.io/builder"
2425
)
@@ -776,8 +777,45 @@ func DeleteTeam(t *Team) error {
776777
return err
777778
}
778779

779-
if err := t.removeAllRepositories(ctx); err != nil {
780-
return err
780+
// update branch protections
781+
{
782+
protections := make([]*ProtectedBranch, 0, 10)
783+
err := sess.In("repo_id",
784+
builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
785+
Find(&protections)
786+
if err != nil {
787+
return fmt.Errorf("findProtectedBranches: %v", err)
788+
}
789+
for _, p := range protections {
790+
var matched1, matched2, matched3 bool
791+
if len(p.WhitelistTeamIDs) != 0 {
792+
p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList(
793+
p.WhitelistTeamIDs, t.ID)
794+
}
795+
if len(p.ApprovalsWhitelistTeamIDs) != 0 {
796+
p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList(
797+
p.ApprovalsWhitelistTeamIDs, t.ID)
798+
}
799+
if len(p.MergeWhitelistTeamIDs) != 0 {
800+
p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList(
801+
p.MergeWhitelistTeamIDs, t.ID)
802+
}
803+
if matched1 || matched2 || matched3 {
804+
if _, err = sess.ID(p.ID).Cols(
805+
"whitelist_team_i_ds",
806+
"merge_whitelist_team_i_ds",
807+
"approvals_whitelist_team_i_ds",
808+
).Update(p); err != nil {
809+
return fmt.Errorf("updateProtectedBranches: %v", err)
810+
}
811+
}
812+
}
813+
}
814+
815+
if !t.IncludesAllRepositories {
816+
if err := t.removeAllRepositories(ctx); err != nil {
817+
return err
818+
}
781819
}
782820

783821
// Delete team-user.

Diff for: models/user.go

+45
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
user_model "code.gitea.io/gitea/models/user"
1919
"code.gitea.io/gitea/modules/setting"
2020
"code.gitea.io/gitea/modules/structs"
21+
"code.gitea.io/gitea/modules/util"
2122

2223
"xorm.io/builder"
2324
)
@@ -130,6 +131,50 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
130131
}
131132
}
132133

134+
// ***** START: Branch Protections *****
135+
{
136+
const batchSize = 50
137+
for start := 0; ; start += batchSize {
138+
protections := make([]*ProtectedBranch, 0, batchSize)
139+
// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings.
140+
// We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`,
141+
// though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`).
142+
// Also, as we didn't update branch protections when removing entries from `access` table,
143+
// it's safer to iterate all protected branches.
144+
if err = e.Limit(batchSize, start).Find(&protections); err != nil {
145+
return fmt.Errorf("findProtectedBranches: %v", err)
146+
}
147+
if len(protections) == 0 {
148+
break
149+
}
150+
for _, p := range protections {
151+
var matched1, matched2, matched3 bool
152+
if len(p.WhitelistUserIDs) != 0 {
153+
p.WhitelistUserIDs, matched1 = util.RemoveIDFromList(
154+
p.WhitelistUserIDs, u.ID)
155+
}
156+
if len(p.ApprovalsWhitelistUserIDs) != 0 {
157+
p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList(
158+
p.ApprovalsWhitelistUserIDs, u.ID)
159+
}
160+
if len(p.MergeWhitelistUserIDs) != 0 {
161+
p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList(
162+
p.MergeWhitelistUserIDs, u.ID)
163+
}
164+
if matched1 || matched2 || matched3 {
165+
if _, err = e.ID(p.ID).Cols(
166+
"whitelist_user_i_ds",
167+
"merge_whitelist_user_i_ds",
168+
"approvals_whitelist_user_i_ds",
169+
).Update(p); err != nil {
170+
return fmt.Errorf("updateProtectedBranches: %v", err)
171+
}
172+
}
173+
}
174+
}
175+
}
176+
// ***** END: Branch Protections *****
177+
133178
// ***** START: PublicKey *****
134179
if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil {
135180
return fmt.Errorf("deletePublicKeys: %v", err)

Diff for: modules/util/slice.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package util
6+
7+
// RemoveIDFromList removes the given ID from the slice, if found.
8+
// It does not preserve order, and assumes the ID is unique.
9+
func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
10+
n := len(list) - 1
11+
for i, item := range list {
12+
if item == id {
13+
list[i] = list[n]
14+
return list[:n], true
15+
}
16+
}
17+
return list, false
18+
}

0 commit comments

Comments
 (0)