@@ -490,3 +490,135 @@ func containsProvisionerDaemon(daemons []database.ProvisionerDaemon, name string
490490return d .Name == name
491491})
492492}
493+
494+ //nolint:paralleltest // It uses LockIDDBPurge.
495+ func TestDeleteExpiredOAuth2ProviderAppCodes (t * testing.T ) {
496+ ctx ,cancel := context .WithTimeout (context .Background (),testutil .WaitShort )
497+ defer cancel ()
498+
499+ clk := quartz .NewMock (t )
500+ db ,_ := dbtestutil .NewDB (t ,dbtestutil .WithDumpOnFailure ())
501+ logger := slogtest .Make (t ,& slogtest.Options {IgnoreErrors :true })
502+
503+ now := dbtime .Now ()
504+ clk .Set (now ).MustWait (ctx )
505+
506+ // Create test data
507+ user := dbgen .User (t ,db , database.User {})
508+ app := dbgen .OAuth2ProviderApp (t ,db , database.OAuth2ProviderApp {
509+ Name :fmt .Sprintf ("test-codes-%d" ,time .Now ().UnixNano ()),
510+ })
511+
512+ // Create expired authorization code (should be deleted)
513+ expiredCode := dbgen .OAuth2ProviderAppCode (t ,db , database.OAuth2ProviderAppCode {
514+ ExpiresAt :now .Add (- 1 * time .Hour ),// Expired 1 hour ago
515+ AppID :app .ID ,
516+ UserID :user .ID ,
517+ })
518+
519+ // Verify code exists initially
520+ _ ,err := db .GetOAuth2ProviderAppCodeByID (ctx ,expiredCode .ID )
521+ require .NoError (t ,err )
522+
523+ // Run cleanup
524+ done := awaitDoTick (ctx ,t ,clk )
525+ closer := dbpurge .New (ctx ,logger ,db ,clk )
526+ defer closer .Close ()
527+ <- done
528+
529+ // Verify expired code is deleted
530+ _ ,err = db .GetOAuth2ProviderAppCodeByID (ctx ,expiredCode .ID )
531+ require .Error (t ,err )
532+ require .ErrorIs (t ,err ,sql .ErrNoRows )
533+ }
534+
535+ //nolint:paralleltest // It uses LockIDDBPurge.
536+ func TestDeleteExpiredOAuth2ProviderAppTokens (t * testing.T ) {
537+ ctx ,cancel := context .WithTimeout (context .Background (),testutil .WaitShort )
538+ defer cancel ()
539+
540+ clk := quartz .NewMock (t )
541+ db ,_ := dbtestutil .NewDB (t ,dbtestutil .WithDumpOnFailure ())
542+ logger := slogtest .Make (t ,& slogtest.Options {IgnoreErrors :true })
543+
544+ now := dbtime .Now ()
545+ clk .Set (now ).MustWait (ctx )
546+
547+ // Create test data
548+ user := dbgen .User (t ,db , database.User {})
549+ app := dbgen .OAuth2ProviderApp (t ,db , database.OAuth2ProviderApp {
550+ Name :fmt .Sprintf ("test-tokens-%d" ,time .Now ().UnixNano ()),
551+ })
552+ appSecret := dbgen .OAuth2ProviderAppSecret (t ,db , database.OAuth2ProviderAppSecret {
553+ AppID :app .ID ,
554+ })
555+
556+ // Create API keys for the tokens
557+ expiredAPIKey ,_ := dbgen .APIKey (t ,db , database.APIKey {
558+ UserID :user .ID ,
559+ ExpiresAt :now .Add (- 1 * time .Hour ),
560+ })
561+
562+ // Create expired access token (should be deleted)
563+ expiredToken := dbgen .OAuth2ProviderAppToken (t ,db , database.OAuth2ProviderAppToken {
564+ ExpiresAt :now .Add (- 1 * time .Hour ),// Expired 1 hour ago
565+ AppSecretID :appSecret .ID ,
566+ APIKeyID :expiredAPIKey .ID ,
567+ UserID :user .ID ,
568+ })
569+
570+ // Verify token exists initially
571+ _ ,err := db .GetOAuth2ProviderAppTokenByPrefix (ctx ,expiredToken .HashPrefix )
572+ require .NoError (t ,err )
573+
574+ // Run cleanup
575+ done := awaitDoTick (ctx ,t ,clk )
576+ closer := dbpurge .New (ctx ,logger ,db ,clk )
577+ defer closer .Close ()
578+ <- done
579+
580+ // Verify expired token is deleted
581+ _ ,err = db .GetOAuth2ProviderAppTokenByPrefix (ctx ,expiredToken .HashPrefix )
582+ require .Error (t ,err )
583+ require .ErrorIs (t ,err ,sql .ErrNoRows )
584+ }
585+
586+ //nolint:paralleltest // It uses LockIDDBPurge.
587+ func TestDeleteExpiredOAuth2ProviderDeviceCodes (t * testing.T ) {
588+ ctx ,cancel := context .WithTimeout (context .Background (),testutil .WaitShort )
589+ defer cancel ()
590+
591+ clk := quartz .NewMock (t )
592+ db ,_ := dbtestutil .NewDB (t ,dbtestutil .WithDumpOnFailure ())
593+ logger := slogtest .Make (t ,& slogtest.Options {IgnoreErrors :true })
594+
595+ now := dbtime .Now ()
596+ clk .Set (now ).MustWait (ctx )
597+
598+ // Create test data
599+ app := dbgen .OAuth2ProviderApp (t ,db , database.OAuth2ProviderApp {
600+ Name :fmt .Sprintf ("test-device-%d" ,time .Now ().UnixNano ()),
601+ })
602+
603+ // Create expired device code with pending status (should be deleted)
604+ expiredDeviceCode := dbgen .OAuth2ProviderDeviceCode (t ,db , database.OAuth2ProviderDeviceCode {
605+ ExpiresAt :now .Add (- 1 * time .Hour ),// Expired 1 hour ago
606+ ClientID :app .ID ,
607+ Status :database .OAuth2DeviceStatusPending ,
608+ })
609+
610+ // Verify device code exists initially
611+ _ ,err := db .GetOAuth2ProviderDeviceCodeByID (ctx ,expiredDeviceCode .ID )
612+ require .NoError (t ,err )
613+
614+ // Run cleanup
615+ done := awaitDoTick (ctx ,t ,clk )
616+ closer := dbpurge .New (ctx ,logger ,db ,clk )
617+ defer closer .Close ()
618+ <- done
619+
620+ // Verify expired pending device code is deleted
621+ _ ,err = db .GetOAuth2ProviderDeviceCodeByID (ctx ,expiredDeviceCode .ID )
622+ require .Error (t ,err )
623+ require .ErrorIs (t ,err ,sql .ErrNoRows )
624+ }