@@ -93,49 +93,47 @@ public async Task Constructor_CreatesSecretPathIfNotExists(SecretsRepositoryType
93
93
[ InlineData ( SecretsRepositoryType . KeyVault , ScriptSecretsType . Function ) ]
94
94
public async Task ReadAsync_ReadsExpectedFile ( SecretsRepositoryType repositoryType , ScriptSecretsType secretsType )
95
95
{
96
- using ( var directory = new TempDirectory ( ) )
96
+ using var directory = new TempDirectory ( ) ;
97
+
98
+ await _fixture . TestInitialize ( repositoryType , directory . Path ) ;
99
+ ScriptSecrets testSecrets = null ;
100
+ if ( secretsType == ScriptSecretsType . Host )
97
101
{
98
- await _fixture . TestInitialize ( repositoryType , directory . Path ) ;
99
- ScriptSecrets testSecrets = null ;
100
- if ( secretsType == ScriptSecretsType . Host )
102
+ testSecrets = new HostSecrets ( )
101
103
{
102
- testSecrets = new HostSecrets ( )
103
- {
104
- MasterKey = new Key ( "master" , "test" ) ,
105
- FunctionKeys = new List < Key > ( ) { new Key ( KeyName , "test" ) } ,
106
- SystemKeys = new List < Key > ( ) { new Key ( KeyName , "test" ) }
107
- } ;
108
- }
109
- else
104
+ MasterKey = new ( "master" , "test" ) ,
105
+ FunctionKeys = [ new ( KeyName , "test" ) ] ,
106
+ SystemKeys = [ new ( KeyName , "test" ) ]
107
+ } ;
108
+ }
109
+ else
110
+ {
111
+ testSecrets = new FunctionSecrets ( )
110
112
{
111
- testSecrets = new FunctionSecrets ( )
112
- {
113
- Keys = new List < Key > ( ) { new Key ( KeyName , "test" ) }
114
- } ;
115
- }
116
- string testFunctionName = secretsType == ScriptSecretsType . Host ? "host" : functionName ;
113
+ Keys = [ new ( KeyName , "test" ) ]
114
+ } ;
115
+ }
116
+ string testFunctionName = secretsType == ScriptSecretsType . Host ? "host" : functionName ;
117
117
118
- await _fixture . WriteSecret ( testFunctionName , testSecrets ) ;
118
+ await _fixture . WriteSecret ( testFunctionName , testSecrets ) ;
119
119
120
- var target = _fixture . GetNewSecretRepository ( ) ;
120
+ var target = _fixture . GetNewSecretRepository ( ) ;
121
121
122
- ScriptSecrets secretsContent = await target . ReadAsync ( secretsType , testFunctionName ) ;
123
-
124
- if ( secretsType == ScriptSecretsType . Host )
125
- {
126
- Assert . Equal ( ( secretsContent as HostSecrets ) . MasterKey . Name , "master" ) ;
127
- Assert . Equal ( ( secretsContent as HostSecrets ) . MasterKey . Value , "test" ) ;
128
- Assert . Equal ( ( secretsContent as HostSecrets ) . FunctionKeys [ 0 ] . Name , KeyName ) ;
129
- Assert . Equal ( ( secretsContent as HostSecrets ) . FunctionKeys [ 0 ] . Value , "test" ) ;
130
- Assert . Equal ( ( secretsContent as HostSecrets ) . SystemKeys [ 0 ] . Name , KeyName ) ;
131
- Assert . Equal ( ( secretsContent as HostSecrets ) . SystemKeys [ 0 ] . Value , "test" ) ;
132
- }
133
- else
134
- {
135
- Assert . Equal ( ( secretsContent as FunctionSecrets ) . Keys [ 0 ] . Name , KeyName ) ;
136
- Assert . Equal ( ( secretsContent as FunctionSecrets ) . Keys [ 0 ] . Value , "test" ) ;
137
- }
122
+ ScriptSecrets secretsContent = await target . ReadAsync ( secretsType , testFunctionName ) ;
138
123
124
+ if ( secretsType == ScriptSecretsType . Host )
125
+ {
126
+ Assert . Equal ( ( secretsContent as HostSecrets ) . MasterKey . Name , "master" ) ;
127
+ Assert . Equal ( ( secretsContent as HostSecrets ) . MasterKey . Value , "test" ) ;
128
+ Assert . Equal ( ( secretsContent as HostSecrets ) . FunctionKeys [ 0 ] . Name , KeyName ) ;
129
+ Assert . Equal ( ( secretsContent as HostSecrets ) . FunctionKeys [ 0 ] . Value , "test" ) ;
130
+ Assert . Equal ( ( secretsContent as HostSecrets ) . SystemKeys [ 0 ] . Name , KeyName ) ;
131
+ Assert . Equal ( ( secretsContent as HostSecrets ) . SystemKeys [ 0 ] . Value , "test" ) ;
132
+ }
133
+ else
134
+ {
135
+ Assert . Equal ( ( secretsContent as FunctionSecrets ) . Keys [ 0 ] . Name , KeyName ) ;
136
+ Assert . Equal ( ( secretsContent as FunctionSecrets ) . Keys [ 0 ] . Value , "test" ) ;
139
137
}
140
138
}
141
139
@@ -526,6 +524,8 @@ async Task RunTest()
526
524
527
525
public class Fixture : IDisposable
528
526
{
527
+ private readonly DefaultAzureCredentialOptions _azureCredentialOptions ;
528
+
529
529
public Fixture ( )
530
530
{
531
531
TestSiteName = "Test_test" ;
@@ -534,17 +534,15 @@ public Fixture()
534
534
var configuration = TestHelpers . GetTestConfiguration ( ) ;
535
535
BlobConnectionString = configuration . GetWebJobsConnectionString ( ConnectionStringNames . Storage ) ;
536
536
KeyVaultUri = configuration . GetWebJobsConnectionString ( EnvironmentSettingNames . AzureWebJobsSecretStorageKeyVaultUri ) ;
537
- KeyVaultClientId = configuration . GetWebJobsConnectionString ( EnvironmentSettingNames . AzureWebJobsSecretStorageKeyVaultClientId ) ;
538
- KeyVaultClientSecret = configuration . GetWebJobsConnectionString ( EnvironmentSettingNames . AzureWebJobsSecretStorageKeyVaultClientSecret ) ;
539
- KeyVaultTenantId = configuration . GetWebJobsConnectionString ( EnvironmentSettingNames . AzureWebJobsSecretStorageKeyVaultTenantId ) ;
540
537
541
- if ( KeyVaultTenantId is not null && KeyVaultClientId is not null &&
542
- KeyVaultClientSecret is not null && KeyVaultUri is not null )
538
+ // Exclude managed identity for the test to avoid using the
539
+ // credential setup in the test environment.
540
+ _azureCredentialOptions = new DefaultAzureCredentialOptions
543
541
{
544
- // These will fail later if required; but sometimes when testing locally you don't care about KeyVault
545
- var credential = new ClientSecretCredential ( KeyVaultTenantId , KeyVaultClientId , KeyVaultClientSecret ) ;
546
- SecretClient = new SecretClient ( new Uri ( KeyVaultUri ) , credential ) ;
547
- }
542
+ ExcludeManagedIdentityCredential = true ,
543
+ } ;
544
+
545
+ SecretClient = new SecretClient ( new Uri ( KeyVaultUri ) , new DefaultAzureCredential ( _azureCredentialOptions ) ) ;
548
546
549
547
AzureBlobStorageProvider = TestHelpers . GetAzureBlobStorageProvider ( configuration ) ;
550
548
}
@@ -565,12 +563,6 @@ public Fixture()
565
563
566
564
public string KeyVaultUri { get ; private set ; }
567
565
568
- public string KeyVaultClientId { get ; private set ; }
569
-
570
- public string KeyVaultClientSecret { get ; private set ; }
571
-
572
- public string KeyVaultTenantId { get ; private set ; }
573
-
574
566
public SecretsRepositoryType RepositoryType { get ; private set ; }
575
567
576
568
public ILoggerProvider LoggerProvider { get ; private set ; }
@@ -612,22 +604,14 @@ public async Task TestInitialize(SecretsRepositoryType repositoryType, string se
612
604
public ISecretsRepository GetNewSecretRepository ( )
613
605
{
614
606
var logger = LoggerProvider . CreateLogger ( "Test" ) ;
615
- if ( RepositoryType == SecretsRepositoryType . BlobStorage )
616
- {
617
- return new BlobStorageSecretsRepository ( SecretsDirectory , ConnectionStringNames . Storage , TestSiteName , logger , Environment , AzureBlobStorageProvider ) ;
618
- }
619
- else if ( RepositoryType == SecretsRepositoryType . BlobStorageSas )
620
- {
621
- return new BlobStorageSasSecretsRepository ( SecretsDirectory , BlobSasConnectionUri . ToString ( ) , TestSiteName , logger , Environment , AzureBlobStorageProvider ) ;
622
- }
623
- else if ( RepositoryType == SecretsRepositoryType . FileSystem )
624
- {
625
- return new FileSystemSecretsRepository ( SecretsDirectory , logger , Environment ) ;
626
- }
627
- else
607
+
608
+ return RepositoryType switch
628
609
{
629
- return new KeyVaultSecretsRepository ( SecretsDirectory , KeyVaultUri , KeyVaultClientId , KeyVaultClientSecret , KeyVaultTenantId , logger , Environment , new WorkloadIdentityCredential ( ) ) ;
630
- }
610
+ SecretsRepositoryType . BlobStorage => new BlobStorageSecretsRepository ( SecretsDirectory , ConnectionStringNames . Storage , TestSiteName , logger , Environment , AzureBlobStorageProvider ) ,
611
+ SecretsRepositoryType . BlobStorageSas => new BlobStorageSasSecretsRepository ( SecretsDirectory , BlobSasConnectionUri . ToString ( ) , TestSiteName , logger , Environment , AzureBlobStorageProvider ) ,
612
+ SecretsRepositoryType . FileSystem => new FileSystemSecretsRepository ( SecretsDirectory , logger , Environment ) ,
613
+ _ => new KeyVaultSecretsRepository ( SecretsDirectory , KeyVaultUri , logger , Environment , new DefaultAzureCredential ( _azureCredentialOptions ) )
614
+ } ;
631
615
}
632
616
633
617
public void Dispose ( )
@@ -652,10 +636,8 @@ private string RelativeBlobPath(string functionNameOrHost)
652
636
653
637
private string SecretsFileOrSentinelPath ( string functionNameOrHost )
654
638
{
655
- string secretFilePath = null ;
656
639
string fileName = string . Format ( CultureInfo . InvariantCulture , "{0}.json" , functionNameOrHost ) ;
657
- secretFilePath = Path . Combine ( SecretsDirectory , fileName ) ;
658
- return secretFilePath ;
640
+ return Path . Combine ( SecretsDirectory , fileName ) ;
659
641
}
660
642
661
643
public async Task WriteSecret ( string functionNameOrHost , ScriptSecrets scriptSecret )
@@ -703,7 +685,8 @@ private async Task WriteSecretsKeyVaultAndUpdateSectinelFile(string functionName
703
685
Dictionary < string , string > dictionary = KeyVaultSecretsRepository . GetDictionaryFromScriptSecrets ( secrets , functionNameOrHost ) ;
704
686
foreach ( string key in dictionary . Keys )
705
687
{
706
- await SecretClient . SetSecretAsync ( key , dictionary [ key ] ) ;
688
+ await Utility . InvokeWithRetriesWhenAsync ( ( ) => SecretClient . SetSecretAsync ( key , dictionary [ key ] ) ,
689
+ 5 , TimeSpan . FromSeconds ( 1 ) , ( e ) => e is RequestFailedException rfex && rfex . Status == 409 ) ;
707
690
}
708
691
}
709
692
@@ -818,16 +801,28 @@ private async Task ClearAllBlobSecrets()
818
801
}
819
802
}
820
803
804
+ private async Task DeleteKeyVaultSecret ( SecretProperties secret )
805
+ {
806
+ var result = await SecretClient . StartDeleteSecretAsync ( secret . Name ) ;
807
+ await result . WaitForCompletionAsync ( ) ;
808
+
809
+ if ( result . HasCompleted && secret . RecoveryLevel . Contains ( "purgeable" , StringComparison . OrdinalIgnoreCase ) )
810
+ {
811
+ await SecretClient . PurgeDeletedSecretAsync ( secret . Name ) ;
812
+ }
813
+ }
814
+
821
815
private async Task ClearAllKeyVaultSecrets ( )
822
816
{
823
- var secretsPages = KeyVaultSecretsRepository . GetKeyVaultSecretsPagesAsync ( SecretClient ) . AsPages ( ) ;
824
- await foreach ( Page < SecretProperties > page in secretsPages )
817
+ var pages = SecretClient . GetPropertiesOfSecretsAsync ( ) ;
818
+
819
+ var secretOperations = new List < Task > ( ) ;
820
+ await foreach ( var item in pages )
825
821
{
826
- foreach ( SecretProperties item in page . Values )
827
- {
828
- await SecretClient . StartDeleteSecretAsync ( item . Name ) ;
829
- }
822
+ secretOperations . Add ( DeleteKeyVaultSecret ( item ) ) ;
830
823
}
824
+
825
+ await Task . WhenAll ( secretOperations ) ;
831
826
}
832
827
}
833
828
}
0 commit comments