@@ -511,6 +511,102 @@ public async Task AzureReposProvider_GetCredentialAsync_PatMode_ExistingPat_Retu
511511 Assert . Equal ( personalAccessToken , credential . Password ) ;
512512 }
513513
514+ [ Fact ]
515+ public async Task AzureReposProvider_GetCredentialAsync_ManagedIdentity_ReturnsManagedIdCredential ( )
516+ {
517+ var input = new InputArguments ( new Dictionary < string , string >
518+ {
519+ [ "protocol" ] = "https" ,
520+ [ "host" ] = "dev.azure.com" ,
521+ [ "path" ] = "org/proj/_git/repo"
522+ } ) ;
523+
524+ const string accessToken = "MANAGED-IDENTITY-TOKEN" ;
525+ const string managedIdentity = "MANAGED-IDENTITY" ;
526+
527+ var context = new TestCommandContext
528+ {
529+ Environment =
530+ {
531+ Variables =
532+ {
533+ [ AzureDevOpsConstants . EnvironmentVariables . ManagedIdentity ] = managedIdentity
534+ }
535+ }
536+ } ;
537+
538+ var azDevOps = Mock . Of < IAzureDevOpsRestApi > ( ) ;
539+ var authorityCache = Mock . Of < IAzureDevOpsAuthorityCache > ( ) ;
540+ var userMgr = Mock . Of < IAzureReposBindingManager > ( ) ;
541+ var msAuthMock = new Mock < IMicrosoftAuthentication > ( ) ;
542+
543+ msAuthMock . Setup ( x => x . GetTokenForManagedIdentityAsync ( It . IsAny < string > ( ) , It . IsAny < string > ( ) ) )
544+ . ReturnsAsync ( new MockMsAuthResult { AccessToken = accessToken } ) ;
545+
546+ var provider = new AzureReposHostProvider ( context , azDevOps , msAuthMock . Object , authorityCache , userMgr ) ;
547+
548+ ICredential credential = await provider . GetCredentialAsync ( input ) ;
549+
550+ Assert . NotNull ( credential ) ;
551+ Assert . Equal ( managedIdentity , credential . Account ) ;
552+ Assert . Equal ( accessToken , credential . Password ) ;
553+
554+ msAuthMock . Verify (
555+ x => x . GetTokenForManagedIdentityAsync ( managedIdentity ,
556+ AzureDevOpsConstants . AzureDevOpsResourceId ) , Times . Once ) ;
557+ }
558+
559+ [ Fact ]
560+ public async Task AzureReposProvider_GetCredentialAsync_ServicePrincipal_ReturnsSPCredential ( )
561+ {
562+ var input = new InputArguments ( new Dictionary < string , string >
563+ {
564+ [ "protocol" ] = "https" ,
565+ [ "host" ] = "dev.azure.com" ,
566+ [ "path" ] = "org/proj/_git/repo"
567+ } ) ;
568+
569+ const string accessToken = "SP-TOKEN" ;
570+ const string tenantId = "78B1822F-107D-40A3-A29C-AB68D8066074" ;
571+ const string clientId = "49B4DC1A-58A8-4EEE-A81B-616A40D0BA64" ;
572+ const string servicePrincipal = $ "{ tenantId } /{ clientId } ";
573+ const string servicePrincipalSecret = "CLIENT-SECRET" ;
574+
575+ var context = new TestCommandContext
576+ {
577+ Environment =
578+ {
579+ Variables =
580+ {
581+ [ AzureDevOpsConstants . EnvironmentVariables . ServicePrincipalId ] = servicePrincipal ,
582+ [ AzureDevOpsConstants . EnvironmentVariables . ServicePrincipalSecret ] = servicePrincipalSecret
583+ }
584+ }
585+ } ;
586+
587+ var azDevOps = Mock . Of < IAzureDevOpsRestApi > ( ) ;
588+ var authorityCache = Mock . Of < IAzureDevOpsAuthorityCache > ( ) ;
589+ var userMgr = Mock . Of < IAzureReposBindingManager > ( ) ;
590+ var msAuthMock = new Mock < IMicrosoftAuthentication > ( ) ;
591+
592+ msAuthMock . Setup ( x =>
593+ x . GetTokenForServicePrincipalAsync ( It . IsAny < ServicePrincipalIdentity > ( ) , It . IsAny < string [ ] > ( ) ) )
594+ . ReturnsAsync ( new MockMsAuthResult { AccessToken = accessToken } ) ;
595+
596+ var provider = new AzureReposHostProvider ( context , azDevOps , msAuthMock . Object , authorityCache , userMgr ) ;
597+
598+ ICredential credential = await provider . GetCredentialAsync ( input ) ;
599+
600+ Assert . NotNull ( credential ) ;
601+ Assert . Equal ( clientId , credential . Account ) ;
602+ Assert . Equal ( accessToken , credential . Password ) ;
603+
604+ msAuthMock . Verify ( x => x . GetTokenForServicePrincipalAsync (
605+ It . Is < ServicePrincipalIdentity > ( sp => sp . TenantId == tenantId && sp . Id == clientId ) ,
606+ It . Is < string [ ] > ( scopes => scopes . Length == 1 && scopes [ 0 ] == AzureDevOpsConstants . AzureDevOpsDefaultScopes [ 0 ] ) ) ,
607+ Times . Once ) ;
608+ }
609+
514610 [ Fact ]
515611 public async Task AzureReposHostProvider_ConfigureAsync_UseHttpPathSetTrue_DoesNothing ( )
516612 {
0 commit comments