X Tutup
Skip to content

fix: allow users with workspace:create for any owner to list users#21947

Merged
f0ssel merged 7 commits intomainfrom
provisioner-d4k0
Feb 19, 2026
Merged

fix: allow users with workspace:create for any owner to list users#21947
f0ssel merged 7 commits intomainfrom
provisioner-d4k0

Conversation

@f0ssel
Copy link
Collaborator

@f0ssel f0ssel commented Feb 5, 2026

Summary

Custom roles that can create workspaces on behalf of other users need to be able to list users to populate the owner dropdown in the workspace creation UI. Previously, this required a separate user:read permission, causing the dropdown to fail for custom roles.

Changes

  • Modified GetUsers in dbauthz to check if the user can create workspaces for any owner (workspace:create with owner_id: *)
  • If the user has this permission, they can list all users without needing explicit user:read permission
  • Added tests to verify the new behavior

Testing

  • Updated mock tests to assert the new authorization check
  • Added integration tests for both positive and negative cases

Fixes #18203

@f0ssel f0ssel force-pushed the provisioner-d4k0 branch 7 times, most recently from d1593f3 to 67c0d33 Compare February 9, 2026 16:55
Custom roles that can create workspaces on behalf of other users need to
be able to list users to populate the owner dropdown in the workspace
creation UI.

This adds a new endpoint:
GET /organizations/{organization}/members/{user}/workspaces/available-users

The endpoint:
- Checks if the user can create workspaces for any owner in the org
- Returns all users (using system context, like templateAvailablePermissions)
- Returns minimal user data (id, username, name, avatar_url)

Also adds SDK method and tests.

Fixes #18203
@f0ssel f0ssel marked this pull request as ready for review February 9, 2026 20:56
Switch the Create Workspace page to use the new scoped
GET /organizations/{org}/members/me/workspaces/available-users
endpoint instead of the global GET /api/v2/users endpoint.

This adds:
- getWorkspaceAvailableUsers API client method
- workspaceAvailableUsers React Query wrapper
- WorkspaceUserAutocomplete component using MinimalUser type
- Updated CreateWorkspacePage owner state to use MinimalUser

The new endpoint only returns users the caller can create workspaces
for, providing a lower-privilege alternative to the global users list.
@f0ssel f0ssel requested a review from Emyrk February 9, 2026 21:35
Copy link
Member

@Emyrk Emyrk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add this test to roles_test.go to have a test for which built in roles can do this.

{
	Name: "CreateWorkspaceForMembers",
	// When creating the WithID won't be set, but it does not change the result.
	Actions:  []policy.Action{policy.ActionCreate},
	Resource: rbac.ResourceWorkspace.InOrg(orgID).WithOwner(policy.WildcardSymbol),
	AuthorizeMap: map[bool][]hasAuthSubjects{
		true:  {owner, orgAdmin},
		false: {setOtherOrg, orgUserAdmin, orgAuditor, memberMe, userAdmin, templateAdmin, orgTemplateAdmin},
	},
},

Copy link
Member

@Emyrk Emyrk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit on the test, and 1 suggested test

Comment on lines +2967 to +2997
func (api *API) workspaceAvailableUsers(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
organization := httpmw.OrganizationParam(r)

// This endpoint requires the user to be able to create workspaces for other
// users in this organization. We check if they can create a workspace with
// a wildcard owner.
if !api.Authorize(r, policy.ActionCreate, rbac.ResourceWorkspace.InOrg(organization.ID).WithOwner(policy.WildcardSymbol)) {
httpapi.Forbidden(rw)
return
}

// Use system context to list all users. The authorization check above
// ensures only users who can create workspaces for others can access this.
//nolint:gocritic // System context needed to list users for workspace owner selection.
users, _, ok := api.GetUsers(rw, r.WithContext(dbauthz.AsSystemRestricted(ctx)))
if !ok {
return
}

minimalUsers := make([]codersdk.MinimalUser, 0, len(users))
for _, user := range users {
minimalUsers = append(minimalUsers, codersdk.MinimalUser{
ID: user.ID,
Username: user.Username,
Name: user.Name,
AvatarURL: user.AvatarURL,
})
}

httpapi.Write(ctx, rw, http.StatusOK, minimalUsers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea 👍

t.Run("OwnerCanListUsers", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, client)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use an org admin instead. Owners can do everything anyway

- Add CreateWorkspaceForMembers RBAC test case to roles_test.go
  verifying only owner and orgAdmin can create workspaces for any owner
- Change OwnerCanListUsers test to OrgAdminCanListUsers, using an org
  admin client instead of owner (owners can do everything anyway)
- Remove unnecessary IncludeProvisionerDaemon from both test sub-tests
@f0ssel f0ssel merged commit e8d6016 into main Feb 19, 2026
42 checks passed
@f0ssel f0ssel deleted the provisioner-d4k0 branch February 19, 2026 18:04
@github-actions github-actions bot locked and limited conversation to collaborators Feb 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom roles cannot create workspaces on behalf of members in UI via the list

2 participants

X Tutup