@@ -5423,6 +5423,19 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppCodes() {
54235423UserID :user .ID ,
54245424}).Asserts (rbac .ResourceOauth2AppCodeToken .WithOwner (user .ID .String ()),policy .ActionDelete )
54255425}))
5426+ s .Run ("ConsumeOAuth2ProviderAppCodeByPrefix" ,s .Subtest (func (db database.Store ,check * expects ) {
5427+ user := dbgen .User (s .T (),db , database.User {})
5428+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5429+ // Use unique prefix to avoid test isolation issues
5430+ uniquePrefix := fmt .Sprintf ("prefix-%s-%d" ,s .T ().Name (),time .Now ().UnixNano ())
5431+ code := dbgen .OAuth2ProviderAppCode (s .T (),db , database.OAuth2ProviderAppCode {
5432+ SecretPrefix : []byte (uniquePrefix ),
5433+ UserID :user .ID ,
5434+ AppID :app .ID ,
5435+ ExpiresAt :time .Now ().Add (24 * time .Hour ),// Extended expiry for test stability
5436+ })
5437+ check .Args (code .SecretPrefix ).Asserts (code ,policy .ActionUpdate ).Returns (code )
5438+ }))
54265439}
54275440
54285441func (s * MethodTestSuite )TestOAuth2ProviderAppTokens () {
@@ -5498,6 +5511,115 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppTokens() {
54985511}))
54995512}
55005513
5514+ func (s * MethodTestSuite )TestOAuth2ProviderDeviceCodes () {
5515+ s .Run ("InsertOAuth2ProviderDeviceCode" ,s .Subtest (func (db database.Store ,check * expects ) {
5516+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5517+ check .Args (database.InsertOAuth2ProviderDeviceCodeParams {
5518+ ClientID :app .ID ,
5519+ DeviceCodePrefix :"testpref" ,
5520+ DeviceCodeHash : []byte ("hash" ),
5521+ UserCode :"TEST1234" ,
5522+ VerificationUri :"http://example.com/device" ,
5523+ }).Asserts (rbac .ResourceOauth2AppCodeToken ,policy .ActionCreate )
5524+ }))
5525+ s .Run ("GetOAuth2ProviderDeviceCodeByID" ,s .Subtest (func (db database.Store ,check * expects ) {
5526+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5527+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5528+ ClientID :app .ID ,
5529+ DeviceCodePrefix :"testpref" ,
5530+ UserCode :"TEST1234" ,
5531+ VerificationUri :"http://example.com/device" ,
5532+ })
5533+ require .NoError (s .T (),err )
5534+ check .Args (deviceCode .ID ).Asserts (deviceCode ,policy .ActionRead ).Returns (deviceCode )
5535+ }))
5536+ s .Run ("GetOAuth2ProviderDeviceCodeByPrefix" ,s .Subtest (func (db database.Store ,check * expects ) {
5537+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5538+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5539+ ClientID :app .ID ,
5540+ DeviceCodePrefix :"testpref" ,
5541+ UserCode :"TEST1234" ,
5542+ VerificationUri :"http://example.com/device" ,
5543+ })
5544+ require .NoError (s .T (),err )
5545+ check .Args (deviceCode .DeviceCodePrefix ).Asserts (deviceCode ,policy .ActionRead ).Returns (deviceCode )
5546+ }))
5547+ s .Run ("GetOAuth2ProviderDeviceCodeByUserCode" ,s .Subtest (func (db database.Store ,check * expects ) {
5548+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5549+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5550+ ClientID :app .ID ,
5551+ DeviceCodePrefix :"testpref" ,
5552+ UserCode :"TEST1234" ,
5553+ VerificationUri :"http://example.com/device" ,
5554+ })
5555+ require .NoError (s .T (),err )
5556+ check .Args (deviceCode .UserCode ).Asserts (deviceCode ,policy .ActionRead ).Returns (deviceCode )
5557+ }))
5558+ s .Run ("GetOAuth2ProviderDeviceCodesByClientID" ,s .Subtest (func (db database.Store ,check * expects ) {
5559+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5560+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5561+ ClientID :app .ID ,
5562+ DeviceCodePrefix :"testpref" ,
5563+ UserCode :"TEST1234" ,
5564+ VerificationUri :"http://example.com/device" ,
5565+ })
5566+ require .NoError (s .T (),err )
5567+ check .Args (app .ID ).Asserts (rbac .ResourceOauth2AppCodeToken ,policy .ActionRead ).Returns ([]database.OAuth2ProviderDeviceCode {deviceCode })
5568+ }))
5569+ s .Run ("ConsumeOAuth2ProviderDeviceCodeByPrefix" ,s .Subtest (func (db database.Store ,check * expects ) {
5570+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5571+ user := dbgen .User (s .T (),db , database.User {})
5572+ // Use unique identifiers to avoid test isolation issues
5573+ // Device code prefix must be exactly 8 characters
5574+ uniquePrefix := fmt .Sprintf ("t%07d" ,time .Now ().UnixNano ()% 10000000 )
5575+ uniqueUserCode := fmt .Sprintf ("USER%04d" ,time .Now ().UnixNano ()% 10000 )
5576+ // Create device code using dbgen (now available!)
5577+ deviceCode := dbgen .OAuth2ProviderDeviceCode (s .T (),db , database.OAuth2ProviderDeviceCode {
5578+ DeviceCodePrefix :uniquePrefix ,
5579+ UserCode :uniqueUserCode ,
5580+ ClientID :app .ID ,
5581+ ExpiresAt :time .Now ().Add (24 * time .Hour ),// Extended expiry for test stability
5582+ })
5583+ // Authorize the device code so it can be consumed
5584+ deviceCode ,err := db .UpdateOAuth2ProviderDeviceCodeAuthorization (s .T ().Context (), database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams {
5585+ ID :deviceCode .ID ,
5586+ UserID : uuid.NullUUID {UUID :user .ID ,Valid :true },
5587+ Status :database .OAuth2DeviceStatusAuthorized ,
5588+ })
5589+ require .NoError (s .T (),err )
5590+ require .Equal (s .T (),database .OAuth2DeviceStatusAuthorized ,deviceCode .Status )
5591+ check .Args (uniquePrefix ).Asserts (deviceCode ,policy .ActionUpdate ).Returns (deviceCode )
5592+ }))
5593+ s .Run ("UpdateOAuth2ProviderDeviceCodeAuthorization" ,s .Subtest (func (db database.Store ,check * expects ) {
5594+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5595+ user := dbgen .User (s .T (),db , database.User {})
5596+ // Create device code using dbgen
5597+ deviceCode := dbgen .OAuth2ProviderDeviceCode (s .T (),db , database.OAuth2ProviderDeviceCode {
5598+ ClientID :app .ID ,
5599+ })
5600+ require .Equal (s .T (),database .OAuth2DeviceStatusPending ,deviceCode .Status )
5601+ check .Args (database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams {
5602+ ID :deviceCode .ID ,
5603+ UserID : uuid.NullUUID {UUID :user .ID ,Valid :true },
5604+ Status :database .OAuth2DeviceStatusAuthorized ,
5605+ }).Asserts (deviceCode ,policy .ActionUpdate )
5606+ }))
5607+ s .Run ("DeleteOAuth2ProviderDeviceCodeByID" ,s .Subtest (func (db database.Store ,check * expects ) {
5608+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5609+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5610+ ClientID :app .ID ,
5611+ DeviceCodePrefix :"testpref" ,
5612+ UserCode :"TEST1234" ,
5613+ VerificationUri :"http://example.com/device" ,
5614+ })
5615+ require .NoError (s .T (),err )
5616+ check .Args (deviceCode .ID ).Asserts (deviceCode ,policy .ActionDelete )
5617+ }))
5618+ s .Run ("DeleteExpiredOAuth2ProviderDeviceCodes" ,s .Subtest (func (db database.Store ,check * expects ) {
5619+ check .Args ().Asserts (rbac .ResourceSystem ,policy .ActionDelete )
5620+ }))
5621+ }
5622+
55015623func (s * MethodTestSuite )TestResourcesMonitor () {
55025624createAgent := func (t * testing.T ,db database.Store ) (database.WorkspaceAgent , database.WorkspaceTable ) {
55035625t .Helper ()