@@ -20,9 +20,11 @@ import (
2020 "cdr.dev/slog/sloggers/slogtest"
2121 "github.com/coder/coder/v2/coderd/audit"
2222 "github.com/coder/coder/v2/coderd/coderdtest"
23+ "github.com/coder/coder/v2/coderd/coderdtest/oidctest"
2324 "github.com/coder/coder/v2/coderd/database"
2425 "github.com/coder/coder/v2/coderd/database/dbauthz"
2526 "github.com/coder/coder/v2/coderd/database/dbtime"
27+ "github.com/coder/coder/v2/coderd/externalauth"
2628 "github.com/coder/coder/v2/coderd/rbac"
2729 "github.com/coder/coder/v2/codersdk"
2830 "github.com/coder/coder/v2/provisioner/echo"
@@ -711,6 +713,78 @@ func TestWorkspaceBuildStatus(t *testing.T) {
711713 require .EqualValues (t , codersdk .WorkspaceStatusDeleted , workspace .LatestBuild .Status )
712714}
713715
716+ func TestWorkspaceDeleteSuspendedUser (t * testing.T ) {
717+ t .Parallel ()
718+ const providerID = "fake-github"
719+ fake := oidctest .NewFakeIDP (t , oidctest .WithServing ())
720+
721+ validateCalls := 0
722+ userSuspended := false
723+ owner := coderdtest .New (t , & coderdtest.Options {
724+ IncludeProvisionerDaemon : true ,
725+ ExternalAuthConfigs : []* externalauth.Config {
726+ fake .ExternalAuthConfig (t , providerID , & oidctest.ExternalAuthConfigOptions {
727+ ValidatePayload : func (email string ) (interface {}, int , error ) {
728+ validateCalls ++
729+ if userSuspended {
730+ // Simulate the user being suspended from the IDP too.
731+ return "" , http .StatusForbidden , fmt .Errorf ("user is suspended" )
732+ }
733+ return "OK" , 0 , nil
734+ },
735+ }),
736+ },
737+ })
738+
739+ first := coderdtest .CreateFirstUser (t , owner )
740+
741+ // New user that we will suspend when we try to delete the workspace.
742+ client , user := coderdtest .CreateAnotherUser (t , owner , first .OrganizationID , rbac .RoleTemplateAdmin ())
743+ fake .ExternalLogin (t , client )
744+
745+ version := coderdtest .CreateTemplateVersion (t , client , first .OrganizationID , & echo.Responses {
746+ Parse : echo .ParseComplete ,
747+ ProvisionApply : echo .ApplyComplete ,
748+ ProvisionPlan : []* proto.Response {{
749+ Type : & proto.Response_Plan {
750+ Plan : & proto.PlanComplete {
751+ Error : "" ,
752+ Resources : nil ,
753+ Parameters : nil ,
754+ ExternalAuthProviders : []* proto.ExternalAuthProviderResource {
755+ {
756+ Id : providerID ,
757+ Optional : false ,
758+ },
759+ },
760+ },
761+ },
762+ }},
763+ })
764+
765+ validateCalls = 0 // Reset
766+ coderdtest .AwaitTemplateVersionJobCompleted (t , client , version .ID )
767+ template := coderdtest .CreateTemplate (t , client , first .OrganizationID , version .ID )
768+ workspace := coderdtest .CreateWorkspace (t , client , first .OrganizationID , template .ID )
769+ coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , workspace .LatestBuild .ID )
770+ require .Equal (t , 1 , validateCalls ) // Ensure the external link is working
771+
772+ // Suspend the user
773+ ctx := testutil .Context (t , testutil .WaitLong )
774+ _ , err := owner .UpdateUserStatus (ctx , user .ID .String (), codersdk .UserStatusSuspended )
775+ require .NoError (t , err , "suspend user" )
776+
777+ // Now delete the workspace build
778+ userSuspended = true
779+ build , err := owner .CreateWorkspaceBuild (ctx , workspace .ID , codersdk.CreateWorkspaceBuildRequest {
780+ Transition : codersdk .WorkspaceTransitionDelete ,
781+ })
782+ require .NoError (t , err )
783+ build = coderdtest .AwaitWorkspaceBuildJobCompleted (t , owner , build .ID )
784+ require .Equal (t , 2 , validateCalls )
785+ require .Equal (t , codersdk .WorkspaceStatusDeleted , build .Status )
786+ }
787+
714788func TestWorkspaceBuildDebugMode (t * testing.T ) {
715789 t .Parallel ()
716790
0 commit comments