feat(enterprise/coderd): allow system users to be added to groups (#19518)

closes https://github.com/coder/coder/issues/18274

This pull request makes system users visible in various group related
queries so that they can be added to and removed from groups. This
allows system user quotas to be configured. System users are still
ignored in certain queries, such as when license seat consumption is
determined.

This pull request further ensures the existence of a
"coder_prebuilt_workspaces" group in any organization that needs
prebuilt workspaces

---------

Co-authored-by: Susana Ferreira <susana@coder.com>
This commit is contained in:
Sas Swart
2025-08-27 16:57:59 +02:00
committed by GitHub
co-authored by Susana Ferreira
parent dbc6c980b9
commit 4e9ee80882
9 changed files with 688 additions and 277 deletions
+10
View File
@@ -487,6 +487,16 @@ var (
rbac.ResourceFile.Type: {
policy.ActionRead,
},
// Needs to be able to add the prebuilds system user to the "prebuilds" group in each organization that needs prebuilt workspaces
// so that prebuilt workspaces can be scheduled and owned in those organizations.
rbac.ResourceGroup.Type: {
policy.ActionRead,
policy.ActionCreate,
policy.ActionUpdate,
},
rbac.ResourceGroupMember.Type: {
policy.ActionRead,
},
}),
},
}),
+11 -3
View File
@@ -6609,16 +6609,19 @@ WHERE
organization_id = $1
ELSE true
END
-- Filter by system type
AND CASE WHEN $2::bool THEN TRUE ELSE is_system = false END
ORDER BY
-- Deterministic and consistent ordering of all users. This is to ensure consistent pagination.
LOWER(username) ASC OFFSET $2
LOWER(username) ASC OFFSET $3
LIMIT
-- A null limit means "no limit", so 0 means return all
NULLIF($3 :: int, 0)
NULLIF($4 :: int, 0)
`
type PaginatedOrganizationMembersParams struct {
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
IncludeSystem bool `db:"include_system" json:"include_system"`
OffsetOpt int32 `db:"offset_opt" json:"offset_opt"`
LimitOpt int32 `db:"limit_opt" json:"limit_opt"`
}
@@ -6634,7 +6637,12 @@ type PaginatedOrganizationMembersRow struct {
}
func (q *sqlQuerier) PaginatedOrganizationMembers(ctx context.Context, arg PaginatedOrganizationMembersParams) ([]PaginatedOrganizationMembersRow, error) {
rows, err := q.db.QueryContext(ctx, paginatedOrganizationMembers, arg.OrganizationID, arg.OffsetOpt, arg.LimitOpt)
rows, err := q.db.QueryContext(ctx, paginatedOrganizationMembers,
arg.OrganizationID,
arg.IncludeSystem,
arg.OffsetOpt,
arg.LimitOpt,
)
if err != nil {
return nil, err
}
@@ -89,6 +89,8 @@ WHERE
organization_id = @organization_id
ELSE true
END
-- Filter by system type
AND CASE WHEN @include_system::bool THEN TRUE ELSE is_system = false END
ORDER BY
-- Deterministic and consistent ordering of all users. This is to ensure consistent pagination.
LOWER(username) ASC OFFSET @offset_opt
+1
View File
@@ -203,6 +203,7 @@ func (api *API) paginatedMembers(rw http.ResponseWriter, r *http.Request) {
paginatedMemberRows, err := api.Database.PaginatedOrganizationMembers(ctx, database.PaginatedOrganizationMembersParams{
OrganizationID: organization.ID,
IncludeSystem: false,
// #nosec G115 - Pagination limits are small and fit in int32
LimitOpt: int32(paginationParams.Limit),
// #nosec G115 - Pagination offsets are small and fit in int32