From 73a77edd75fe969afd269a1d6b8940af97fa904d Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Thu, 7 Aug 2025 03:34:26 +0000 Subject: [PATCH 1/2] fix: use system context for querying workspaces when deleting users --- coderd/users.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coderd/users.go b/coderd/users.go index 7fbb8e7d04cdf..851c52d71188e 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -542,7 +542,10 @@ func (api *API) deleteUser(rw http.ResponseWriter, r *http.Request) { return } - workspaces, err := api.Database.GetWorkspaces(ctx, database.GetWorkspacesParams{ + // This query is ONLY done to get the workspace count, so we use a system + // context to return ALL workspaces. Not just workspaces the user can view. + // nolint:gocritic + workspaces, err := api.Database.GetWorkspaces(dbauthz.AsSystemRestricted(ctx), database.GetWorkspacesParams{ OwnerID: user.ID, }) if err != nil { From bfcc771705ad7cf99636b5898ec216955c4c5ad9 Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Thu, 7 Aug 2025 03:43:24 +0000 Subject: [PATCH 2/2] test --- coderd/users_test.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/coderd/users_test.go b/coderd/users_test.go index 9d695f37c9906..5928fc6486f51 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -377,6 +377,43 @@ func TestDeleteUser(t *testing.T) { require.ErrorAs(t, err, &apiErr, "should be a coderd error") require.Equal(t, http.StatusForbidden, apiErr.StatusCode(), "should be forbidden") }) + t.Run("CountCheckIncludesAllWorkspaces", func(t *testing.T) { + t.Parallel() + client, _ := coderdtest.NewWithProvisionerCloser(t, nil) + firstUser := coderdtest.CreateFirstUser(t, client) + + // Create a target user who will own a workspace + targetUserClient, targetUser := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID) + + // Create a User Admin who should not have permission to see the target user's workspace + userAdminClient, userAdmin := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID) + + // Grant User Admin role to the userAdmin + userAdmin, err := client.UpdateUserRoles(context.Background(), userAdmin.ID.String(), codersdk.UpdateRoles{ + Roles: []string{rbac.RoleUserAdmin().String()}, + }) + require.NoError(t, err) + + // Create a template and workspace owned by the target user + version := coderdtest.CreateTemplateVersion(t, client, firstUser.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, firstUser.OrganizationID, version.ID) + _ = coderdtest.CreateWorkspace(t, targetUserClient, template.ID) + + workspaces, err := userAdminClient.Workspaces(context.Background(), codersdk.WorkspaceFilter{ + Owner: targetUser.Username, + }) + require.NoError(t, err) + require.Len(t, workspaces.Workspaces, 0) + + // Attempt to delete the target user - this should fail because the + // user has a workspace not visible to the deleting user. + err = userAdminClient.DeleteUser(context.Background(), targetUser.ID) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusExpectationFailed, apiErr.StatusCode()) + require.Contains(t, apiErr.Message, "has workspaces") + }) } func TestNotifyUserStatusChanged(t *testing.T) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy