1
1
package coderd_test
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"database/sql"
6
7
"errors"
@@ -25,6 +26,7 @@ import (
25
26
"github.com/coder/coder/v2/coderd/coderdtest/oidctest"
26
27
"github.com/coder/coder/v2/coderd/database"
27
28
"github.com/coder/coder/v2/coderd/database/dbauthz"
29
+ "github.com/coder/coder/v2/coderd/database/dbfake"
28
30
"github.com/coder/coder/v2/coderd/database/dbgen"
29
31
"github.com/coder/coder/v2/coderd/database/dbtestutil"
30
32
"github.com/coder/coder/v2/coderd/database/dbtime"
@@ -371,42 +373,174 @@ func TestWorkspaceBuildsProvisionerState(t *testing.T) {
371
373
372
374
t .Run ("Orphan" , func (t * testing.T ) {
373
375
t .Parallel ()
374
- client := coderdtest .New (t , & coderdtest.Options {IncludeProvisionerDaemon : true })
375
- first := coderdtest .CreateFirstUser (t , client )
376
-
377
- ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
378
- defer cancel ()
379
376
380
- version := coderdtest .CreateTemplateVersion (t , client , first .OrganizationID , nil )
381
- template := coderdtest .CreateTemplate (t , client , first .OrganizationID , version .ID )
382
- coderdtest .AwaitTemplateVersionJobCompleted (t , client , version .ID )
377
+ t .Run ("WithoutDelete" , func (t * testing.T ) {
378
+ t .Parallel ()
379
+ client , store := coderdtest .NewWithDatabase (t , nil )
380
+ first := coderdtest .CreateFirstUser (t , client )
381
+ templateAdmin , templateAdminUser := coderdtest .CreateAnotherUser (t , client , first .OrganizationID , rbac .RoleTemplateAdmin ())
382
+
383
+ r := dbfake .WorkspaceBuild (t , store , database.WorkspaceTable {
384
+ OwnerID : templateAdminUser .ID ,
385
+ OrganizationID : first .OrganizationID ,
386
+ }).Do ()
387
+
388
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
389
+ defer cancel ()
390
+
391
+ // Trying to orphan without delete transition fails.
392
+ _ , err := templateAdmin .CreateWorkspaceBuild (ctx , r .Workspace .ID , codersdk.CreateWorkspaceBuildRequest {
393
+ TemplateVersionID : r .TemplateVersion .ID ,
394
+ Transition : codersdk .WorkspaceTransitionStart ,
395
+ Orphan : true ,
396
+ })
397
+ require .Error (t , err , "Orphan is only permitted when deleting a workspace." )
398
+ cerr := coderdtest .SDKError (t , err )
399
+ require .Equal (t , http .StatusBadRequest , cerr .StatusCode ())
400
+ })
383
401
384
- workspace := coderdtest .CreateWorkspace (t , client , template .ID )
385
- coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , workspace .LatestBuild .ID )
402
+ t .Run ("WithState" , func (t * testing.T ) {
403
+ t .Parallel ()
404
+ client , store := coderdtest .NewWithDatabase (t , nil )
405
+ first := coderdtest .CreateFirstUser (t , client )
406
+ templateAdmin , templateAdminUser := coderdtest .CreateAnotherUser (t , client , first .OrganizationID , rbac .RoleTemplateAdmin ())
407
+
408
+ r := dbfake .WorkspaceBuild (t , store , database.WorkspaceTable {
409
+ OwnerID : templateAdminUser .ID ,
410
+ OrganizationID : first .OrganizationID ,
411
+ }).Do ()
412
+
413
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
414
+ defer cancel ()
415
+
416
+ // Providing both state and orphan fails.
417
+ _ , err := templateAdmin .CreateWorkspaceBuild (ctx , r .Workspace .ID , codersdk.CreateWorkspaceBuildRequest {
418
+ TemplateVersionID : r .TemplateVersion .ID ,
419
+ Transition : codersdk .WorkspaceTransitionDelete ,
420
+ ProvisionerState : []byte (" " ),
421
+ Orphan : true ,
422
+ })
423
+ require .Error (t , err )
424
+ cerr := coderdtest .SDKError (t , err )
425
+ require .Equal (t , http .StatusBadRequest , cerr .StatusCode ())
426
+ })
386
427
387
- // Providing both state and orphan fails.
388
- _ , err := client .CreateWorkspaceBuild (ctx , workspace .ID , codersdk.CreateWorkspaceBuildRequest {
389
- TemplateVersionID : workspace .LatestBuild .TemplateVersionID ,
390
- Transition : codersdk .WorkspaceTransitionDelete ,
391
- ProvisionerState : []byte (" " ),
392
- Orphan : true ,
428
+ t .Run ("NoPermission" , func (t * testing.T ) {
429
+ t .Parallel ()
430
+ client , store := coderdtest .NewWithDatabase (t , nil )
431
+ first := coderdtest .CreateFirstUser (t , client )
432
+ member , memberUser := coderdtest .CreateAnotherUser (t , client , first .OrganizationID )
433
+
434
+ r := dbfake .WorkspaceBuild (t , store , database.WorkspaceTable {
435
+ OwnerID : memberUser .ID ,
436
+ OrganizationID : first .OrganizationID ,
437
+ }).Do ()
438
+
439
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
440
+ defer cancel ()
441
+
442
+ // Trying to orphan without being a template admin fails.
443
+ _ , err := member .CreateWorkspaceBuild (ctx , r .Workspace .ID , codersdk.CreateWorkspaceBuildRequest {
444
+ TemplateVersionID : r .TemplateVersion .ID ,
445
+ Transition : codersdk .WorkspaceTransitionDelete ,
446
+ Orphan : true ,
447
+ })
448
+ require .Error (t , err )
449
+ cerr := coderdtest .SDKError (t , err )
450
+ require .Equal (t , http .StatusForbidden , cerr .StatusCode ())
393
451
})
394
- require .Error (t , err )
395
- cerr := coderdtest .SDKError (t , err )
396
- require .Equal (t , http .StatusBadRequest , cerr .StatusCode ())
397
452
398
- // Regular orphan operation succeeds.
399
- build , err := client .CreateWorkspaceBuild (ctx , workspace .ID , codersdk.CreateWorkspaceBuildRequest {
400
- TemplateVersionID : workspace .LatestBuild .TemplateVersionID ,
401
- Transition : codersdk .WorkspaceTransitionDelete ,
402
- Orphan : true ,
453
+ t .Run ("OK" , func (t * testing.T ) {
454
+ // Include a provisioner so that we can test that provisionerdserver
455
+ // performs deletion.
456
+ auditor := audit .NewMock ()
457
+ client , store := coderdtest .NewWithDatabase (t , & coderdtest.Options {IncludeProvisionerDaemon : true , Auditor : auditor })
458
+ first := coderdtest .CreateFirstUser (t , client )
459
+ templateAdmin , templateAdminUser := coderdtest .CreateAnotherUser (t , client , first .OrganizationID , rbac .RoleTemplateAdmin ())
460
+
461
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
462
+ defer cancel ()
463
+ // This is a valid zip file. Without this the job will fail to complete.
464
+ // TODO: add this to dbfake by default.
465
+ zipBytes := make ([]byte , 22 )
466
+ zipBytes [0 ] = 80
467
+ zipBytes [1 ] = 75
468
+ zipBytes [2 ] = 0o5
469
+ zipBytes [3 ] = 0o6
470
+ uploadRes , err := client .Upload (ctx , codersdk .ContentTypeZip , bytes .NewReader (zipBytes ))
471
+ require .NoError (t , err )
472
+
473
+ tv := dbfake .TemplateVersion (t , store ).
474
+ FileID (uploadRes .ID ).
475
+ Seed (database.TemplateVersion {
476
+ OrganizationID : first .OrganizationID ,
477
+ CreatedBy : templateAdminUser .ID ,
478
+ }).
479
+ Do ()
480
+
481
+ r := dbfake .WorkspaceBuild (t , store , database.WorkspaceTable {
482
+ OwnerID : templateAdminUser .ID ,
483
+ OrganizationID : first .OrganizationID ,
484
+ TemplateID : tv .Template .ID ,
485
+ }).Do ()
486
+
487
+ auditor .ResetLogs ()
488
+ // Regular orphan operation succeeds.
489
+ build , err := templateAdmin .CreateWorkspaceBuild (ctx , r .Workspace .ID , codersdk.CreateWorkspaceBuildRequest {
490
+ TemplateVersionID : r .TemplateVersion .ID ,
491
+ Transition : codersdk .WorkspaceTransitionDelete ,
492
+ Orphan : true ,
493
+ })
494
+ require .NoError (t , err )
495
+ coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , build .ID )
496
+
497
+ // Validate that the deletion was audited.
498
+ require .True (t , auditor .Contains (t , database.AuditLog {
499
+ ResourceID : build .ID ,
500
+ Action : database .AuditActionDelete ,
501
+ }))
403
502
})
404
- require .NoError (t , err )
405
- coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , build .ID )
406
503
407
- _ , err = client .Workspace (ctx , workspace .ID )
408
- require .Error (t , err )
409
- require .Equal (t , http .StatusGone , coderdtest .SDKError (t , err ).StatusCode ())
504
+ t .Run ("NoProvisioners" , func (t * testing.T ) {
505
+ t .Parallel ()
506
+ auditor := audit .NewMock ()
507
+ client , store := coderdtest .NewWithDatabase (t , & coderdtest.Options {Auditor : auditor })
508
+ first := coderdtest .CreateFirstUser (t , client )
509
+ templateAdmin , templateAdminUser := coderdtest .CreateAnotherUser (t , client , first .OrganizationID , rbac .RoleTemplateAdmin ())
510
+
511
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
512
+ defer cancel ()
513
+ r := dbfake .WorkspaceBuild (t , store , database.WorkspaceTable {
514
+ OwnerID : templateAdminUser .ID ,
515
+ OrganizationID : first .OrganizationID ,
516
+ }).Do ()
517
+
518
+ // nolint:gocritic // For testing
519
+ daemons , err := store .GetProvisionerDaemons (dbauthz .AsSystemReadProvisionerDaemons (ctx ))
520
+ require .NoError (t , err )
521
+ require .Empty (t , daemons , "Provisioner daemons should be empty for this test" )
522
+
523
+ // Orphan deletion still succeeds despite no provisioners being available.
524
+ build , err := templateAdmin .CreateWorkspaceBuild (ctx , r .Workspace .ID , codersdk.CreateWorkspaceBuildRequest {
525
+ TemplateVersionID : r .TemplateVersion .ID ,
526
+ Transition : codersdk .WorkspaceTransitionDelete ,
527
+ Orphan : true ,
528
+ })
529
+ require .NoError (t , err )
530
+ require .Equal (t , codersdk .WorkspaceTransitionDelete , build .Transition )
531
+ require .Equal (t , codersdk .ProvisionerJobSucceeded , build .Job .Status )
532
+ require .Empty (t , build .Job .Error )
533
+
534
+ ws , err := client .Workspace (ctx , r .Workspace .ID )
535
+ require .Empty (t , ws )
536
+ require .Equal (t , http .StatusGone , coderdtest .SDKError (t , err ).StatusCode ())
537
+
538
+ // Validate that the deletion was audited.
539
+ require .True (t , auditor .Contains (t , database.AuditLog {
540
+ ResourceID : build .ID ,
541
+ Action : database .AuditActionDelete ,
542
+ }))
543
+ })
410
544
})
411
545
}
412
546
0 commit comments