@@ -5532,6 +5532,19 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppCodes() {
55325532UserID :user .ID ,
55335533}).Asserts (rbac .ResourceOauth2AppCodeToken .WithOwner (user .ID .String ()),policy .ActionDelete )
55345534}))
5535+ s .Run ("ConsumeOAuth2ProviderAppCodeByPrefix" ,s .Subtest (func (db database.Store ,check * expects ) {
5536+ user := dbgen .User (s .T (),db , database.User {})
5537+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5538+ // Use unique prefix to avoid test isolation issues
5539+ uniquePrefix := fmt .Sprintf ("prefix-%s-%d" ,s .T ().Name (),time .Now ().UnixNano ())
5540+ code := dbgen .OAuth2ProviderAppCode (s .T (),db , database.OAuth2ProviderAppCode {
5541+ SecretPrefix : []byte (uniquePrefix ),
5542+ UserID :user .ID ,
5543+ AppID :app .ID ,
5544+ ExpiresAt :time .Now ().Add (24 * time .Hour ),// Extended expiry for test stability
5545+ })
5546+ check .Args (code .SecretPrefix ).Asserts (code ,policy .ActionUpdate ).Returns (code )
5547+ }))
55355548}
55365549
55375550func (s * MethodTestSuite )TestOAuth2ProviderAppTokens () {
@@ -5607,6 +5620,115 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppTokens() {
56075620}))
56085621}
56095622
5623+ func (s * MethodTestSuite )TestOAuth2ProviderDeviceCodes () {
5624+ s .Run ("InsertOAuth2ProviderDeviceCode" ,s .Subtest (func (db database.Store ,check * expects ) {
5625+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5626+ check .Args (database.InsertOAuth2ProviderDeviceCodeParams {
5627+ ClientID :app .ID ,
5628+ DeviceCodePrefix :"testpref" ,
5629+ DeviceCodeHash : []byte ("hash" ),
5630+ UserCode :"TEST1234" ,
5631+ VerificationUri :"http://example.com/device" ,
5632+ }).Asserts (rbac .ResourceOauth2AppCodeToken ,policy .ActionCreate )
5633+ }))
5634+ s .Run ("GetOAuth2ProviderDeviceCodeByID" ,s .Subtest (func (db database.Store ,check * expects ) {
5635+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5636+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5637+ ClientID :app .ID ,
5638+ DeviceCodePrefix :"testpref" ,
5639+ UserCode :"TEST1234" ,
5640+ VerificationUri :"http://example.com/device" ,
5641+ })
5642+ require .NoError (s .T (),err )
5643+ check .Args (deviceCode .ID ).Asserts (deviceCode ,policy .ActionRead ).Returns (deviceCode )
5644+ }))
5645+ s .Run ("GetOAuth2ProviderDeviceCodeByPrefix" ,s .Subtest (func (db database.Store ,check * expects ) {
5646+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5647+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5648+ ClientID :app .ID ,
5649+ DeviceCodePrefix :"testpref" ,
5650+ UserCode :"TEST1234" ,
5651+ VerificationUri :"http://example.com/device" ,
5652+ })
5653+ require .NoError (s .T (),err )
5654+ check .Args (deviceCode .DeviceCodePrefix ).Asserts (deviceCode ,policy .ActionRead ).Returns (deviceCode )
5655+ }))
5656+ s .Run ("GetOAuth2ProviderDeviceCodeByUserCode" ,s .Subtest (func (db database.Store ,check * expects ) {
5657+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5658+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5659+ ClientID :app .ID ,
5660+ DeviceCodePrefix :"testpref" ,
5661+ UserCode :"TEST1234" ,
5662+ VerificationUri :"http://example.com/device" ,
5663+ })
5664+ require .NoError (s .T (),err )
5665+ check .Args (deviceCode .UserCode ).Asserts (deviceCode ,policy .ActionRead ).Returns (deviceCode )
5666+ }))
5667+ s .Run ("GetOAuth2ProviderDeviceCodesByClientID" ,s .Subtest (func (db database.Store ,check * expects ) {
5668+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5669+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5670+ ClientID :app .ID ,
5671+ DeviceCodePrefix :"testpref" ,
5672+ UserCode :"TEST1234" ,
5673+ VerificationUri :"http://example.com/device" ,
5674+ })
5675+ require .NoError (s .T (),err )
5676+ check .Args (app .ID ).Asserts (rbac .ResourceOauth2AppCodeToken ,policy .ActionRead ).Returns ([]database.OAuth2ProviderDeviceCode {deviceCode })
5677+ }))
5678+ s .Run ("ConsumeOAuth2ProviderDeviceCodeByPrefix" ,s .Subtest (func (db database.Store ,check * expects ) {
5679+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5680+ user := dbgen .User (s .T (),db , database.User {})
5681+ // Use unique identifiers to avoid test isolation issues
5682+ // Device code prefix must be exactly 8 characters
5683+ uniquePrefix := fmt .Sprintf ("t%07d" ,time .Now ().UnixNano ()% 10000000 )
5684+ uniqueUserCode := fmt .Sprintf ("USER%04d" ,time .Now ().UnixNano ()% 10000 )
5685+ // Create device code using dbgen (now available!)
5686+ deviceCode := dbgen .OAuth2ProviderDeviceCode (s .T (),db , database.OAuth2ProviderDeviceCode {
5687+ DeviceCodePrefix :uniquePrefix ,
5688+ UserCode :uniqueUserCode ,
5689+ ClientID :app .ID ,
5690+ ExpiresAt :time .Now ().Add (24 * time .Hour ),// Extended expiry for test stability
5691+ })
5692+ // Authorize the device code so it can be consumed
5693+ deviceCode ,err := db .UpdateOAuth2ProviderDeviceCodeAuthorization (s .T ().Context (), database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams {
5694+ ID :deviceCode .ID ,
5695+ UserID : uuid.NullUUID {UUID :user .ID ,Valid :true },
5696+ Status :database .OAuth2DeviceStatusAuthorized ,
5697+ })
5698+ require .NoError (s .T (),err )
5699+ require .Equal (s .T (),database .OAuth2DeviceStatusAuthorized ,deviceCode .Status )
5700+ check .Args (uniquePrefix ).Asserts (deviceCode ,policy .ActionUpdate ).Returns (deviceCode )
5701+ }))
5702+ s .Run ("UpdateOAuth2ProviderDeviceCodeAuthorization" ,s .Subtest (func (db database.Store ,check * expects ) {
5703+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5704+ user := dbgen .User (s .T (),db , database.User {})
5705+ // Create device code using dbgen
5706+ deviceCode := dbgen .OAuth2ProviderDeviceCode (s .T (),db , database.OAuth2ProviderDeviceCode {
5707+ ClientID :app .ID ,
5708+ })
5709+ require .Equal (s .T (),database .OAuth2DeviceStatusPending ,deviceCode .Status )
5710+ check .Args (database.UpdateOAuth2ProviderDeviceCodeAuthorizationParams {
5711+ ID :deviceCode .ID ,
5712+ UserID : uuid.NullUUID {UUID :user .ID ,Valid :true },
5713+ Status :database .OAuth2DeviceStatusAuthorized ,
5714+ }).Asserts (deviceCode ,policy .ActionUpdate )
5715+ }))
5716+ s .Run ("DeleteOAuth2ProviderDeviceCodeByID" ,s .Subtest (func (db database.Store ,check * expects ) {
5717+ app := dbgen .OAuth2ProviderApp (s .T (),db , database.OAuth2ProviderApp {})
5718+ deviceCode ,err := db .InsertOAuth2ProviderDeviceCode (context .Background (), database.InsertOAuth2ProviderDeviceCodeParams {
5719+ ClientID :app .ID ,
5720+ DeviceCodePrefix :"testpref" ,
5721+ UserCode :"TEST1234" ,
5722+ VerificationUri :"http://example.com/device" ,
5723+ })
5724+ require .NoError (s .T (),err )
5725+ check .Args (deviceCode .ID ).Asserts (deviceCode ,policy .ActionDelete )
5726+ }))
5727+ s .Run ("DeleteExpiredOAuth2ProviderDeviceCodes" ,s .Subtest (func (db database.Store ,check * expects ) {
5728+ check .Args ().Asserts (rbac .ResourceSystem ,policy .ActionDelete )
5729+ }))
5730+ }
5731+
56105732func (s * MethodTestSuite )TestResourcesMonitor () {
56115733createAgent := func (t * testing.T ,db database.Store ) (database.WorkspaceAgent , database.WorkspaceTable ) {
56125734t .Helper ()