@@ -9,14 +9,20 @@ import (
99"time"
1010
1111"github.com/google/uuid"
12+ "github.com/prometheus/client_golang/prometheus"
1213"github.com/stretchr/testify/assert"
1314"github.com/stretchr/testify/require"
1415"go.uber.org/goleak"
1516
17+ "cdr.dev/slog"
1618"cdr.dev/slog/sloggers/slogtest"
19+ "github.com/coder/coder/v2/coderd/coderdtest"
1720"github.com/coder/coder/v2/coderd/database"
21+ "github.com/coder/coder/v2/coderd/database/dbauthz"
1822"github.com/coder/coder/v2/coderd/database/dbgen"
1923"github.com/coder/coder/v2/coderd/database/dbtestutil"
24+ "github.com/coder/coder/v2/coderd/provisionerdserver"
25+ "github.com/coder/coder/v2/coderd/rbac"
2026"github.com/coder/coder/v2/coderd/unhanger"
2127"github.com/coder/coder/v2/provisionersdk"
2228"github.com/coder/coder/v2/testutil"
@@ -37,7 +43,7 @@ func TestDetectorNoJobs(t *testing.T) {
3743statsCh = make (chan unhanger.Stats )
3844)
3945
40- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
46+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
4147detector .Start ()
4248tickCh <- time .Now ()
4349
@@ -84,7 +90,7 @@ func TestDetectorNoHungJobs(t *testing.T) {
8490})
8591}
8692
87- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
93+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
8894detector .Start ()
8995tickCh <- now
9096
@@ -190,7 +196,7 @@ func TestDetectorHungWorkspaceBuild(t *testing.T) {
190196t .Log ("previous job ID: " ,previousWorkspaceBuildJob .ID )
191197t .Log ("current job ID: " ,currentWorkspaceBuildJob .ID )
192198
193- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
199+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
194200detector .Start ()
195201tickCh <- now
196202
@@ -313,7 +319,7 @@ func TestDetectorHungWorkspaceBuildNoOverrideState(t *testing.T) {
313319t .Log ("previous job ID: " ,previousWorkspaceBuildJob .ID )
314320t .Log ("current job ID: " ,currentWorkspaceBuildJob .ID )
315321
316- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
322+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
317323detector .Start ()
318324tickCh <- now
319325
@@ -406,7 +412,7 @@ func TestDetectorHungWorkspaceBuildNoOverrideStateIfNoExistingBuild(t *testing.T
406412
407413t .Log ("current job ID: " ,currentWorkspaceBuildJob .ID )
408414
409- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
415+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
410416detector .Start ()
411417tickCh <- now
412418
@@ -469,29 +475,42 @@ func TestDetectorHungOtherJobTypes(t *testing.T) {
469475Type :database .ProvisionerJobTypeTemplateVersionImport ,
470476Input : []byte ("{}" ),
471477})
472-
473- // Template dry-run job.
474- templateDryRunJob = dbgen .ProvisionerJob (t ,db ,pubsub , database.ProvisionerJob {
475- CreatedAt :tenMinAgo ,
476- UpdatedAt :sixMinAgo ,
477- StartedAt : sql.NullTime {
478- Time :tenMinAgo ,
479- Valid :true ,
480- },
478+ _ = dbgen .TemplateVersion (t ,db , database.TemplateVersion {
481479OrganizationID :org .ID ,
482- InitiatorID :user .ID ,
483- Provisioner :database .ProvisionerTypeEcho ,
484- StorageMethod :database .ProvisionerStorageMethodFile ,
485- FileID :file .ID ,
486- Type :database .ProvisionerJobTypeTemplateVersionDryRun ,
487- Input : []byte ("{}" ),
480+ JobID :templateImportJob .ID ,
481+ CreatedBy :user .ID ,
488482})
489483)
490484
485+ // Template dry-run job.
486+ dryRunVersion := dbgen .TemplateVersion (t ,db , database.TemplateVersion {
487+ OrganizationID :org .ID ,
488+ CreatedBy :user .ID ,
489+ })
490+ input ,err := json .Marshal (provisionerdserver.TemplateVersionDryRunJob {
491+ TemplateVersionID :dryRunVersion .ID ,
492+ })
493+ require .NoError (t ,err )
494+ templateDryRunJob := dbgen .ProvisionerJob (t ,db ,pubsub , database.ProvisionerJob {
495+ CreatedAt :tenMinAgo ,
496+ UpdatedAt :sixMinAgo ,
497+ StartedAt : sql.NullTime {
498+ Time :tenMinAgo ,
499+ Valid :true ,
500+ },
501+ OrganizationID :org .ID ,
502+ InitiatorID :user .ID ,
503+ Provisioner :database .ProvisionerTypeEcho ,
504+ StorageMethod :database .ProvisionerStorageMethodFile ,
505+ FileID :file .ID ,
506+ Type :database .ProvisionerJobTypeTemplateVersionDryRun ,
507+ Input :input ,
508+ })
509+
491510t .Log ("template import job ID: " ,templateImportJob .ID )
492511t .Log ("template dry-run job ID: " ,templateDryRunJob .ID )
493512
494- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
513+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
495514detector .Start ()
496515tickCh <- now
497516
@@ -564,11 +583,16 @@ func TestDetectorHungCanceledJob(t *testing.T) {
564583Type :database .ProvisionerJobTypeTemplateVersionImport ,
565584Input : []byte ("{}" ),
566585})
586+ _ = dbgen .TemplateVersion (t ,db , database.TemplateVersion {
587+ OrganizationID :org .ID ,
588+ JobID :templateImportJob .ID ,
589+ CreatedBy :user .ID ,
590+ })
567591)
568592
569593t .Log ("template import job ID: " ,templateImportJob .ID )
570594
571- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
595+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
572596detector .Start ()
573597tickCh <- now
574598
@@ -657,6 +681,11 @@ func TestDetectorPushesLogs(t *testing.T) {
657681Type :database .ProvisionerJobTypeTemplateVersionImport ,
658682Input : []byte ("{}" ),
659683})
684+ _ = dbgen .TemplateVersion (t ,db , database.TemplateVersion {
685+ OrganizationID :org .ID ,
686+ JobID :templateImportJob .ID ,
687+ CreatedBy :user .ID ,
688+ })
660689)
661690
662691t .Log ("template import job ID: " ,templateImportJob .ID )
@@ -678,7 +707,7 @@ func TestDetectorPushesLogs(t *testing.T) {
678707require .Len (t ,logs ,10 )
679708}
680709
681- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
710+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
682711detector .Start ()
683712
684713// Create pubsub subscription to listen for new log events.
@@ -752,7 +781,7 @@ func TestDetectorMaxJobsPerRun(t *testing.T) {
752781// Create unhanger.MaxJobsPerRun + 1 hung jobs.
753782now := time .Now ()
754783for i := 0 ;i < unhanger .MaxJobsPerRun + 1 ;i ++ {
755- dbgen .ProvisionerJob (t ,db ,pubsub , database.ProvisionerJob {
784+ pj := dbgen .ProvisionerJob (t ,db ,pubsub , database.ProvisionerJob {
756785CreatedAt :now .Add (- time .Hour ),
757786UpdatedAt :now .Add (- time .Hour ),
758787StartedAt : sql.NullTime {
@@ -767,9 +796,14 @@ func TestDetectorMaxJobsPerRun(t *testing.T) {
767796Type :database .ProvisionerJobTypeTemplateVersionImport ,
768797Input : []byte ("{}" ),
769798})
799+ _ = dbgen .TemplateVersion (t ,db , database.TemplateVersion {
800+ OrganizationID :org .ID ,
801+ JobID :pj .ID ,
802+ CreatedBy :user .ID ,
803+ })
770804}
771805
772- detector := unhanger .New (ctx ,db ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
806+ detector := unhanger .New (ctx ,wrapDBAuthz ( db , log ) ,pubsub ,log ,tickCh ).WithStatsChannel (statsCh )
773807detector .Start ()
774808tickCh <- now
775809
@@ -788,3 +822,14 @@ func TestDetectorMaxJobsPerRun(t *testing.T) {
788822detector .Close ()
789823detector .Wait ()
790824}
825+
826+ // wrapDBAuthz adds our Authorization/RBAC around the given database store, to
827+ // ensure the unhanger has the right permissions to do its work.
828+ func wrapDBAuthz (db database.Store ,logger slog.Logger ) database.Store {
829+ return dbauthz .New (
830+ db ,
831+ rbac .NewStrictCachingAuthorizer (prometheus .NewRegistry ()),
832+ logger ,
833+ coderdtest .AccessControlStorePointer (),
834+ )
835+ }