mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-07 08:32:16 +00:00
feat(repo): split repository creation limit into user and org scopes (#37872)
## Background `MAX_CREATION_LIMIT` applies to whoever owns a new repository, with no distinction between individual users and organizations. Admins who want different limits for the two - most commonly "block personal repos but let orgs create freely" - currently have to set per-user / per-org overrides on every entity. ## Changes Adds two new `[repository]` settings: - `USER_MAX_CREATION_LIMIT`: global limit for individual users - `ORG_MAX_CREATION_LIMIT`: global limit for organizations `MAX_CREATION_LIMIT` is kept as a shortcut: when set, it becomes the default value for both new keys. When the new keys are explicitly configured, they take precedence. Deployments that only set `MAX_CREATION_LIMIT` see behavior identical to now. Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
@@ -674,12 +674,18 @@ func TestGetInactiveUsers(t *testing.T) {
|
||||
|
||||
func TestCanCreateRepo(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Repository.MaxCreationLimit)()
|
||||
defer test.MockVariableValue(&setting.Repository.UserMaxCreationLimit)()
|
||||
defer test.MockVariableValue(&setting.Repository.OrgMaxCreationLimit)()
|
||||
const noLimit = -1
|
||||
doerActions := user_model.NewActionsUser()
|
||||
doerNormal := &user_model.User{ID: 2}
|
||||
doerAdmin := &user_model.User{ID: 1, IsAdmin: true}
|
||||
orgOwner := func(numRepos, maxRepoCreation int) *user_model.User {
|
||||
return &user_model.User{ID: 3, Type: user_model.UserTypeOrganization, NumRepos: numRepos, MaxRepoCreation: maxRepoCreation}
|
||||
}
|
||||
t.Run("NoGlobalLimit", func(t *testing.T) {
|
||||
setting.Repository.MaxCreationLimit = noLimit
|
||||
setting.Repository.UserMaxCreationLimit = noLimit
|
||||
setting.Repository.OrgMaxCreationLimit = noLimit
|
||||
|
||||
assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 10, MaxRepoCreation: 0}))
|
||||
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 10, MaxRepoCreation: 100}))
|
||||
@@ -693,7 +699,8 @@ func TestCanCreateRepo(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GlobalLimit50", func(t *testing.T) {
|
||||
setting.Repository.MaxCreationLimit = 50
|
||||
setting.Repository.UserMaxCreationLimit = 50
|
||||
setting.Repository.OrgMaxCreationLimit = 50
|
||||
|
||||
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 10, MaxRepoCreation: noLimit}))
|
||||
assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 60, MaxRepoCreation: noLimit})) // limited by global limit
|
||||
@@ -707,4 +714,33 @@ func TestCanCreateRepo(t *testing.T) {
|
||||
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 10, MaxRepoCreation: 100}))
|
||||
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 60, MaxRepoCreation: 100}))
|
||||
})
|
||||
|
||||
t.Run("UserBlockedOrgsUnlimited", func(t *testing.T) {
|
||||
// User and org limits are independent: a deployment can block personal repos while leaving orgs unrestricted.
|
||||
setting.Repository.UserMaxCreationLimit = 0
|
||||
setting.Repository.OrgMaxCreationLimit = noLimit
|
||||
|
||||
// regular user is blocked
|
||||
assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 0, MaxRepoCreation: noLimit}))
|
||||
// per-user override grants individual exceptions even when the global user limit is 0
|
||||
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 3, MaxRepoCreation: 5}))
|
||||
assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{ID: 2, NumRepos: 5, MaxRepoCreation: 5}))
|
||||
|
||||
// organization can create unlimited repos
|
||||
assert.True(t, doerNormal.CanCreateRepoIn(orgOwner(10, noLimit)))
|
||||
assert.True(t, doerNormal.CanCreateRepoIn(orgOwner(999, noLimit)))
|
||||
// per-org override still wins over the global org limit
|
||||
assert.False(t, doerNormal.CanCreateRepoIn(orgOwner(5, 5)))
|
||||
})
|
||||
|
||||
t.Run("OrgGlobalLimitWithPerOrgOverride", func(t *testing.T) {
|
||||
setting.Repository.UserMaxCreationLimit = noLimit
|
||||
setting.Repository.OrgMaxCreationLimit = 10
|
||||
|
||||
assert.True(t, doerNormal.CanCreateRepoIn(orgOwner(5, noLimit)))
|
||||
assert.False(t, doerNormal.CanCreateRepoIn(orgOwner(10, noLimit)))
|
||||
|
||||
// per-org override bypasses the global org limit
|
||||
assert.True(t, doerNormal.CanCreateRepoIn(orgOwner(10, 100)))
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user