fix(enterprise/coderd): skip org membership check for prebuilds user on group patch (#18329)

Currently, the prebuilds documentation states:

```
### Managing resource quotas

Prebuilt workspaces can be used in conjunction with [resource quotas](../../users/quotas.md).
Because unclaimed prebuilt workspaces are owned by the `prebuilds` user, you can:

1. Configure quotas for any group that includes this user.
1. Set appropriate limits to balance prebuilt workspace availability with resource constraints.

If a quota is exceeded, the prebuilt workspace will fail provisioning the same way other workspaces do.
```

If you need to have a separate quota for prebuilds as opposed to regular
users, you are required to create a separate group, as quotas are
applied to groups.

Currently it is not possible to create a separate 'prebuilds' group with
only the prebuilds user to add a quota. This PR skips the org membership
check specifically for the prebuilds user when patching a group.


![image](https://github.com/user-attachments/assets/2ff566bb-97bd-4c73-917a-903ea54dd7a6)
This commit is contained in:
Cian Johnston
2025-06-23 10:32:30 +01:00
committed by GitHub
parent 66e8dbbe17
commit 0a12ec5fd8
2 changed files with 32 additions and 0 deletions

View File

@ -171,6 +171,12 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
})
return
}
// Skip membership checks for the prebuilds user. There is a valid use case
// for adding the prebuilds user to a single group: in order to set a quota
// allowance specifically for prebuilds.
if id == database.PrebuildsSystemUserID.String() {
continue
}
_, err := database.ExpectOne(api.Database.OrganizationMembers(ctx, database.OrganizationMembersParams{
OrganizationID: group.OrganizationID,
UserID: uuid.MustParse(id),

View File

@ -463,6 +463,32 @@ func TestPatchGroup(t *testing.T) {
require.Equal(t, http.StatusBadRequest, cerr.StatusCode())
})
// For quotas to work with prebuilds, it's currently required to add the
// prebuilds user into a group with a quota allowance.
// See: docs/admin/templates/extending-templates/prebuilt-workspaces.md
t.Run("PrebuildsUser", func(t *testing.T) {
t.Parallel()
client, user := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
codersdk.FeatureTemplateRBAC: 1,
},
}})
userAdminClient, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleUserAdmin())
ctx := testutil.Context(t, testutil.WaitLong)
group, err := userAdminClient.CreateGroup(ctx, user.OrganizationID, codersdk.CreateGroupRequest{
Name: "prebuilds",
QuotaAllowance: 123,
})
require.NoError(t, err)
group, err = userAdminClient.PatchGroup(ctx, group.ID, codersdk.PatchGroupRequest{
Name: "prebuilds",
AddUsers: []string{database.PrebuildsSystemUserID.String()},
})
require.NoError(t, err)
})
t.Run("Everyone", func(t *testing.T) {
t.Parallel()
t.Run("NoUpdateName", func(t *testing.T) {