Skip to content

Commit 41148d9

Browse files
committed
test: add unit test for workspace ban role
1 parent 1b998d0 commit 41148d9

File tree

4 files changed

+66
-4
lines changed

4 files changed

+66
-4
lines changed

coderd/httpapi/httpapi.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,13 @@ func ResourceNotFound(rw http.ResponseWriter) {
151151
Write(context.Background(), rw, http.StatusNotFound, ResourceNotFoundResponse)
152152
}
153153

154+
var ResourceForbiddenResponse = codersdk.Response{
155+
Message: "Forbidden.",
156+
Detail: "You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials.",
157+
}
158+
154159
func Forbidden(rw http.ResponseWriter) {
155-
Write(context.Background(), rw, http.StatusForbidden, codersdk.Response{
156-
Message: "Forbidden.",
157-
Detail: "You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials.",
158-
})
160+
Write(context.Background(), rw, http.StatusForbidden, ResourceForbiddenResponse)
159161
}
160162

161163
func InternalServerError(rw http.ResponseWriter, err error) {

coderd/workspaces_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,53 @@ func TestWorkspace(t *testing.T) {
375375
require.Error(t, err, "create workspace with archived version")
376376
require.ErrorContains(t, err, "Archived template versions cannot")
377377
})
378+
379+
t.Run("WorkspaceBan", func(t *testing.T) {
380+
t.Parallel()
381+
owner, _, _ := coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
382+
first := coderdtest.CreateFirstUser(t, owner)
383+
384+
version := coderdtest.CreateTemplateVersion(t, owner, first.OrganizationID, nil)
385+
coderdtest.AwaitTemplateVersionJobCompleted(t, owner, version.ID)
386+
template := coderdtest.CreateTemplate(t, owner, first.OrganizationID, version.ID)
387+
388+
goodClient, _ := coderdtest.CreateAnotherUser(t, owner, first.OrganizationID)
389+
390+
// When a user with workspace-creation-ban
391+
client, user := coderdtest.CreateAnotherUser(t, owner, first.OrganizationID, rbac.ScopedRoleOrgWorkspaceCreationBan(first.OrganizationID))
392+
393+
// Ensure a similar user can create a workspace
394+
coderdtest.CreateWorkspace(t, goodClient, template.ID)
395+
396+
ctx := testutil.Context(t, testutil.WaitLong)
397+
// Then: Cannot create a workspace
398+
_, err := client.CreateUserWorkspace(ctx, codersdk.Me, codersdk.CreateWorkspaceRequest{
399+
TemplateID: template.ID,
400+
TemplateVersionID: uuid.UUID{},
401+
Name: "random",
402+
})
403+
require.Error(t, err)
404+
var apiError *codersdk.Error
405+
require.ErrorAs(t, err, &apiError)
406+
require.Equal(t, http.StatusForbidden, apiError.StatusCode())
407+
408+
// When: workspace-ban use has a workspace
409+
wrk, err := owner.CreateUserWorkspace(ctx, user.ID.String(), codersdk.CreateWorkspaceRequest{
410+
TemplateID: template.ID,
411+
TemplateVersionID: uuid.UUID{},
412+
Name: "random",
413+
})
414+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, wrk.LatestBuild.ID)
415+
416+
// Then: They cannot delete said workspace
417+
_, err = client.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{
418+
Transition: codersdk.WorkspaceTransitionDelete,
419+
ProvisionerState: []byte{},
420+
})
421+
require.Error(t, err)
422+
require.ErrorAs(t, err, &apiError)
423+
require.Equal(t, http.StatusForbidden, apiError.StatusCode())
424+
})
378425
}
379426

380427
func TestResolveAutostart(t *testing.T) {

coderd/wsbuilder/wsbuilder.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,15 @@ func (b *Builder) authorize(authFunc func(action policy.Action, object rbac.Obje
790790
return BuildError{http.StatusBadRequest, msg, xerrors.New(msg)}
791791
}
792792
if !authFunc(action, b.workspace) {
793+
if authFunc(policy.ActionRead, b.workspace) {
794+
// If the user can read the workspace, but not delete/create/update. Show
795+
// a more helpful error. They are allowed to know the workspace exists.
796+
return BuildError{
797+
Status: http.StatusForbidden,
798+
Message: fmt.Sprintf("You do not have permission to %s this workspace.", action),
799+
Wrapped: xerrors.New(httpapi.ResourceForbiddenResponse.Detail),
800+
}
801+
}
793802
// We use the same wording as the httpapi to avoid leaking the existence of the workspace
794803
return BuildError{http.StatusNotFound, httpapi.ResourceNotFoundResponse.Message, xerrors.New(httpapi.ResourceNotFoundResponse.Message)}
795804
}

site/src/api/typesGenerated.ts

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)