From 30138e6cbabc8e9c2cf5ea44d8069764f2c5ff6f Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 13 Jan 2023 11:44:23 +0100 Subject: [PATCH 01/12] chore: use coverlet code coverage --- .github/workflows/code-coverage.yml | 32 +++++++++++++++++++ .../Arcus.Security.Tests.Unit.csproj | 4 +++ 2 files changed, 36 insertions(+) create mode 100644 .github/workflows/code-coverage.yml diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml new file mode 100644 index 00000000..02086ffb --- /dev/null +++ b/.github/workflows/code-coverage.yml @@ -0,0 +1,32 @@ +name: "Code Coverage" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + language: [ 'csharp' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Coverlet coverage test + uses: b3b00/coverlet-action@1.2.4 + with: + testProject: 'src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj' + output: 'lcov.info' + outputFormat: 'lcov' \ No newline at end of file diff --git a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj index 383bdc4b..94491b6d 100644 --- a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj +++ b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj @@ -8,6 +8,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + From 84d48437743b4e16ef568de86ed2320dbfa54810 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 13 Jan 2023 12:22:01 +0100 Subject: [PATCH 02/12] pr-fix: only use net6.0 in unit tests --- src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj index 94491b6d..6ac4522c 100644 --- a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj +++ b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj @@ -1,7 +1,7 @@ - net6.0;netcoreapp3.1 + net6.0 false CS0618 From 79302b587efafc6935ed4da33ec648946e852aeb Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 13 Jan 2023 12:35:27 +0100 Subject: [PATCH 03/12] pr-fix: add coverlet.msbuild --- .../Arcus.Security.Tests.Unit.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj index 6ac4522c..418c7340 100644 --- a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj +++ b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj @@ -12,6 +12,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + From 820a93881742a87379b4a86c3a6c1016d2900548 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 13 Jan 2023 12:39:53 +0100 Subject: [PATCH 04/12] pr-fix: correct output file name --- .github/workflows/code-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 02086ffb..b6533b98 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -28,5 +28,5 @@ jobs: uses: b3b00/coverlet-action@1.2.4 with: testProject: 'src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj' - output: 'lcov.info' + output: 'lcov.net6.0.info' outputFormat: 'lcov' \ No newline at end of file From 27236c33ed39fb51ef93923cb95af9e8eef79823 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 13 Jan 2023 12:45:50 +0100 Subject: [PATCH 05/12] pr-fix: single target framework --- .github/workflows/code-coverage.yml | 3 ++- .../Arcus.Security.Tests.Unit.csproj | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index b6533b98..c21a97fc 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -28,5 +28,6 @@ jobs: uses: b3b00/coverlet-action@1.2.4 with: testProject: 'src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj' - output: 'lcov.net6.0.info' + excludes: '[Arcus.Security.Tests.*]*' + output: 'lcov.info' outputFormat: 'lcov' \ No newline at end of file diff --git a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj index 418c7340..1de08105 100644 --- a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj +++ b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj @@ -1,7 +1,7 @@ - + - net6.0 + net6.0 false CS0618 From d4bff1127cc0891c0439f0c15dbbb4763485f2df Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 13 Jan 2023 12:54:10 +0100 Subject: [PATCH 06/12] pr-fix: publish coverage report --- .github/workflows/code-coverage.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index c21a97fc..8ab2524e 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -30,4 +30,16 @@ jobs: testProject: 'src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj' excludes: '[Arcus.Security.Tests.*]*' output: 'lcov.info' - outputFormat: 'lcov' \ No newline at end of file + outputFormat: 'lcov' + + - name: ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.1.13 + with: + reports: '*/lcov.info' + targetdir: 'coveragereport' + + - name: Upload coverage report artifact + uses: actions/upload-artifact@v2.2.3 + with: + name: CoverageReport + path: coveragereport \ No newline at end of file From e715cdf8a8f4dd2a61a3feb4f24e6b36bea58a50 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 13 Jan 2023 12:55:59 +0100 Subject: [PATCH 07/12] pr-fix: publish coverage report --- .github/workflows/code-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 8ab2524e..d7028d12 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -35,7 +35,7 @@ jobs: - name: ReportGenerator uses: danielpalme/ReportGenerator-GitHub-Action@5.1.13 with: - reports: '*/lcov.info' + reports: 'src/Arcus.Security.Tests.Unit/lcov.info' targetdir: 'coveragereport' - name: Upload coverage report artifact From 2dd4f2d6fd9c4eecca1fbc2980c20c14fdf05db5 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Mon, 16 Jan 2023 06:02:27 +0100 Subject: [PATCH 08/12] pr=fix: closing code coverage gap --- .github/workflows/code-coverage.yml | 1 + .../ISecretProviderExtensions.Deprecated.cs | 2 + .../ManagedServiceIdentityAuthentication.cs | 2 + .../ServicePrincipalAuthentication.cs | 2 + .../IFunctionsHostBuilderTests.cs | 35 ++++++++++++-- .../SecretStoreBuilderExtensionsTests.cs | 46 +++++++++++++++++++ ...atedSecretNameCachedSecretProviderTests.cs | 20 ++++++++ 7 files changed, 105 insertions(+), 3 deletions(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index d7028d12..262d4a9d 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -29,6 +29,7 @@ jobs: with: testProject: 'src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj' excludes: '[Arcus.Security.Tests.*]*' + threshold: 80 output: 'lcov.info' outputFormat: 'lcov' diff --git a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs index 6ba70ec2..50c36631 100644 --- a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs +++ b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using GuardNet; @@ -10,6 +11,7 @@ namespace Arcus.Security.Core.Extensions /// Extensions on the to retrieve several secret values based on configured allowed versions. /// // ReSharper disable once InconsistentNaming + [ExcludeFromCodeCoverage] public static class ISecretProviderExtensions { /// diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs index 7600e528..4bb2f880 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Azure.Identity; using Microsoft.Azure.KeyVault; @@ -11,6 +12,7 @@ namespace Arcus.Security.Providers.AzureKeyVault.Authentication /// /// Azure Key Vault authentication by using Azure Managed Service Identity /// + [ExcludeFromCodeCoverage] [Obsolete("Azure Key Vault authentication is moved to Azure Identity approach where the managed service identity authentication becomes: " + nameof(ManagedIdentityCredential))] public class ManagedServiceIdentityAuthentication : IKeyVaultAuthentication { diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs index 24ba25bb..2223ca46 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Security.Authentication; using System.Threading.Tasks; using Azure.Identity; @@ -13,6 +14,7 @@ namespace Arcus.Security.Providers.AzureKeyVault.Authentication /// /// Representation of an that will generate a implementation using a service principle. /// + [ExcludeFromCodeCoverage] [Obsolete("Azure Key Vault authentication is moved to Azure Identity approach where the service principal authentication becomes: " + nameof(ClientSecretCredential))] public class ServicePrincipalAuthentication : IKeyVaultAuthentication { diff --git a/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs b/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs index 17c91757..c9608b9e 100644 --- a/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs +++ b/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Arcus.Security.Core; using Arcus.Security.Core.Caching; @@ -8,11 +6,11 @@ using Arcus.Security.Tests.Unit.Core.Stubs; using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Xunit; namespace Arcus.Security.Tests.Unit.AzureFunctions { + // ReSharper disable once InconsistentNaming public class IFunctionsHostBuilderTests { [Fact] @@ -30,6 +28,21 @@ public async Task ConfigureSecretStore_WithoutSecretProviders_ThrowsException() await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key")); } + [Fact] + public async Task ConfigureSecretStoreWithConfig_WithoutSecretProviders_ThrowsException() + { + // Arrange + var builder = new StubFunctionsHostBuilder(); + + // Act + builder.ConfigureSecretStore((context, config, stores) => { }); + + // Assert + IServiceProvider serviceProvider = builder.Build(); + var secretProvider = serviceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key")); + } + [Fact] public async Task ConfigureSecretStore_WithoutFoundSecretProvider_ThrowsException() { @@ -46,6 +59,22 @@ public async Task ConfigureSecretStore_WithoutFoundSecretProvider_ThrowsExceptio await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key")); } + [Fact] + public async Task ConfigureSecretStoreWithConfig_WithoutFoundSecretProvider_ThrowsException() + { + // Arrange + var builder = new StubFunctionsHostBuilder(); + var emptyProvider = new InMemorySecretProvider(); + + // Act + builder.ConfigureSecretStore((context, config, stores) => stores.AddProvider(emptyProvider)); + + // Assert + IServiceProvider serviceProvider = builder.Build(); + var secretProvider = serviceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key")); + } + [Fact] public async Task ConfigureSecretStore_WithoutFoundCachedProvider_ThrowsException() { diff --git a/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs index 482e7215..4e0fb938 100644 --- a/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs +++ b/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs @@ -73,6 +73,52 @@ public void AddCommandLine_WithMutateSecretWithoutArguments_Fails() // Assert Assert.ThrowsAny(() => builder.Build()); } + + [Fact] + public void AddCommandLine_WithMutateSecretWithArguments_Fails() + { + // Arrange + string secretName = "MySecret", expected = "P@ssw0rd"; + var arguments = new[] {$"--{secretName}={expected}"}; + var builder = new HostBuilder(); + + // Act + builder.ConfigureSecretStore((config, stores) => + { + stores.AddCommandLine(arguments, mutateSecretName: name => name); + }); + + // Assert + using (IHost host = builder.Build()) + { + var secretProvider = host.Services.GetRequiredService(); + Assert.Equal(expected, secretProvider.GetSecret(secretName).Value); + Assert.Equal(expected, secretProvider.GetRawSecret(secretName)); + } + } + + [Fact] + public void AddCommandLine_WithMutateSecretWithArgumentsWithUnknownSecretName_Fails() + { + // Arrange + string secretName = "MySecret", expected = "P@ssw0rd"; + var arguments = new[] {$"--{secretName}={expected}"}; + var builder = new HostBuilder(); + + // Act + builder.ConfigureSecretStore((config, stores) => + { + stores.AddCommandLine(arguments, mutateSecretName: name => name); + }); + + // Assert + using (IHost host = builder.Build()) + { + var secretProvider = host.Services.GetRequiredService(); + Assert.Throws(() => secretProvider.GetSecret("NotExisting")); + Assert.Throws(() => secretProvider.GetRawSecret("NotExisting")); + } + } [Fact] public void AddCommandLine_WithNameWithMutateSecretWithoutArguments_Fails() diff --git a/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs b/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs index de031941..517d8423 100644 --- a/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs +++ b/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs @@ -79,6 +79,26 @@ public async Task InvalidateSecret_WithMutation_Succeeds() await provider.InvalidateSecretAsync("Arcus:KeyVault:Secret"); } + [Fact] + public void ConfigureSecretStore_WithDefault_FailsToRetrieveCacheConfiguration() + { + // Arrange + var builder = new HostBuilder(); + + // Act + builder.ConfigureSecretStore((config, stores) => + { + stores.AddProvider(new InMemorySecretProvider()); + }); + + // Assert + using (IHost host = builder.Build()) + { + var provider = host.Services.GetRequiredService(); + Assert.Throws(() => provider.Configuration); + } + } + [Fact] public void CreateCachedProvider_WithoutImplementation_Throws() { From 134b6cbd6c92f96eb4444ce8b2f11010ac2c1c17 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Mon, 16 Jan 2023 06:09:55 +0100 Subject: [PATCH 09/12] pr-fix: run always report --- .github/workflows/code-coverage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 262d4a9d..24762e4c 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -35,12 +35,14 @@ jobs: - name: ReportGenerator uses: danielpalme/ReportGenerator-GitHub-Action@5.1.13 + if: always() with: reports: 'src/Arcus.Security.Tests.Unit/lcov.info' targetdir: 'coveragereport' - name: Upload coverage report artifact uses: actions/upload-artifact@v2.2.3 + if: always() with: name: CoverageReport path: coveragereport \ No newline at end of file From 3c51bca749019c74c36522214b872f1e2a48bc5f Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Mon, 16 Jan 2023 08:15:43 +0100 Subject: [PATCH 10/12] pr-fix: exclude providers --- .github/workflows/code-coverage.yml | 2 +- .../CertificateBasedAuthentication.cs | 2 + .../KeyVaultSecretProvider.cs | 2 +- .../DockerSecretsSecretProvider.cs | 2 + .../SecretStoreBuilderExtensions.cs | 2 + .../UserSecretsSecretProvider.cs | 2 + .../Core/CriticalExceptionsTests.cs | 54 +++++++++ .../Extensions/IHostBuilderExtensionsTests.cs | 2 +- .../SecretProviderCachingExtensionsTests.cs | 104 +++++++++++++++--- .../Core/VersionedSecretTests.cs | 15 ++- .../KeyVault/KeyVaultSecretProviderTests.cs | 16 +-- 11 files changed, 176 insertions(+), 27 deletions(-) create mode 100644 src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 24762e4c..11a1e86c 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -28,7 +28,7 @@ jobs: uses: b3b00/coverlet-action@1.2.4 with: testProject: 'src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj' - excludes: '[Arcus.Security.Tests.*]*' + excludes: '[Arcus.Security.Tests.*]*,[Arcus.Security.Providers.*]*' threshold: 80 output: 'lcov.info' outputFormat: 'lcov' diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs index 3459761f..9d6e708b 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; @@ -15,6 +16,7 @@ namespace Arcus.Security.Providers.AzureKeyVault.Authentication /// Azure Key Vault by using client ID and certificate to authenticate the . /// [Obsolete("Azure Key Vault authentication is moved to Azure Identity approach where the certificate authentication becomes: " + nameof(ClientCertificateCredential))] + [ExcludeFromCodeCoverage] public class CertificateBasedAuthentication : IKeyVaultAuthentication { private readonly string _clientId; diff --git a/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs b/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs index 3eab9c8d..71c37601 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs @@ -454,7 +454,7 @@ private TResponse InteractWithKeyVault( } throw new InvalidOperationException( - "Old Azure Key Vault client does not support asynchronous operations, please use the new Azure Key Vault secret provider overloads that uses the new Azure SDK"); + "Old Azure Key Vault client does not support synchronous operations, please use the new Azure Key Vault secret provider overloads that uses the new Azure SDK"); }); isSuccessful = true; diff --git a/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs b/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs index a25cc585..bd80f22a 100644 --- a/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs +++ b/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs @@ -2,6 +2,7 @@ using GuardNet; using Microsoft.Extensions.Configuration.KeyPerFile; using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; using Microsoft.Extensions.FileProviders; @@ -11,6 +12,7 @@ namespace Arcus.Security.Providers.DockerSecrets /// /// Represents an that provides access to the Docker secrets mounted into the Docker container as files. /// + [ExcludeFromCodeCoverage] public class DockerSecretsSecretProvider : ISyncSecretProvider { private readonly KeyPerFileConfigurationProvider _provider; diff --git a/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs b/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs index 27e6498a..9b97e4dc 100644 --- a/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs +++ b/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using Arcus.Security.Providers.DockerSecrets; using GuardNet; @@ -11,6 +12,7 @@ namespace Microsoft.Extensions.Hosting /// /// Extensions on the to easily provide access to Docker secrets in the secret store. /// + [ExcludeFromCodeCoverage] public static class SecretStoreBuilderExtensions { /// diff --git a/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs b/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs index ddcc8b6f..6f334653 100644 --- a/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs +++ b/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Arcus.Security.Core; using GuardNet; @@ -9,6 +10,7 @@ namespace Arcus.Security.Providers.UserSecrets /// /// implementation that provides user secrets. /// + [ExcludeFromCodeCoverage] public class UserSecretsSecretProvider : ISyncSecretProvider { private readonly JsonConfigurationProvider _jsonProvider; diff --git a/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs new file mode 100644 index 00000000..9142edbd --- /dev/null +++ b/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Arcus.Security.Core; +using Arcus.Security.Tests.Unit.Core.Stubs; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Arcus.Security.Tests.Unit.Core +{ + public class CriticalExceptionsTests + { + [Fact] + public async Task GetSecret_WithThrownCriticalException_FailsWithCriticalException() + { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddSecretStore(stores => + { + stores.AddProvider(new SaboteurSecretProvider(new IOException("Something happened!"))) + .AddCriticalException(); + }); + + // Assert + IServiceProvider serviceProvider = services.BuildServiceProvider(); + var secretProvider = serviceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("Some.Secret")); + } + + [Fact] + public async Task GetSecret_WithThrownNonCriticalException_FailsWithSecretNotFoundException() + { + // Arrange + var services = new ServiceCollection(); + + // Act + services.AddSecretStore(stores => + { + stores.AddProvider(new SaboteurSecretProvider(new AccessViolationException("Something happened!"))) + .AddCriticalException(); + }); + + // Assert + IServiceProvider serviceProvider = services.BuildServiceProvider(); + var secretProvider = serviceProvider.GetRequiredService(); + await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("Some.Secret")); + } + } +} diff --git a/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs index 23d66dcc..d6c33730 100644 --- a/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs +++ b/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs @@ -877,7 +877,7 @@ public void ConfigureSecretStore_WithDuplicateNames_FailsWhenRetrievingTypedCach using (IHost host = builder.Build()) { var store = host.Services.GetRequiredService(); - Assert.Throws(() => store.GetProvider(name)); + Assert.Throws(() => store.GetCachedProvider(name)); } } diff --git a/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs index e8737ddf..bb84f270 100644 --- a/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs +++ b/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs @@ -2,6 +2,8 @@ using Arcus.Security.Tests.Unit.Core.Stubs; using System; using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Options; using Xunit; namespace Arcus.Security.Tests.Unit.Core @@ -9,18 +11,64 @@ namespace Arcus.Security.Tests.Unit.Core public class SecretProviderCachingExtensionsTests { [Fact] - public async Task SecretProviderCachingExtensions_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice() + public async Task WithCachingTimeSpanMemoryCache_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice() { // Arrange - string secretKeyValue = Guid.NewGuid().ToString("N"); + var secretKeyValue = Guid.NewGuid().ToString("N"); var testSecretProvider = new TestSecretProviderStub(secretKeyValue); - string keyName = "MyValue"; + var keyName = "MyValue"; + var cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); + + // Act + ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromSeconds(3), cache); + string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + + ChangeInternalCachedSecret(testSecretProvider); + string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + + // Assert + Assert.Equal(firstValue, secondValue); + Assert.Equal(1, testSecretProvider.CallsMadeSinceCreation); + } + + [Fact] + public async Task WithCachingTimeSpanMemoryCache_TwoCallsOutsideCacheInterval_ShouldGetDifferentValue() + { + // Arrange + var secretKeyValue = Guid.NewGuid().ToString("N"); + var testSecretProvider = new TestSecretProviderStub(secretKeyValue); + var keyName = "MyValue"; + var cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); + + // Act + ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromMilliseconds(100), cache); + string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + + await Task.Delay(TimeSpan.FromMilliseconds(150)); + string newSecretValue = Guid.NewGuid().ToString("N"); + ChangeInternalCachedSecret(testSecretProvider, newSecretValue); + string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + + // Assert + Assert.Equal(secretKeyValue, firstValue); + Assert.Equal(newSecretValue, secondValue); + Assert.Equal(2, testSecretProvider.CallsMadeSinceCreation); + } + + [Fact] + public async Task WithCachingTimeSpan_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice() + { + // Arrange + var secretKeyValue = Guid.NewGuid().ToString("N"); + var testSecretProvider = new TestSecretProviderStub(secretKeyValue); + var keyName = "MyValue"; // Act ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromSeconds(3)); - var firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); - testSecretProvider.SecretValue = Guid.NewGuid().ToString("N"); // Change actual value on the internal secret provider ! - var secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + + ChangeInternalCachedSecret(testSecretProvider); + string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); // Assert Assert.Equal(firstValue, secondValue); @@ -28,26 +76,56 @@ public async Task SecretProviderCachingExtensions_TwoCallsWithinCacheInterval_Sh } [Fact] - public async Task SecretProviderCachingExtensions_TwoCallsOutsideCacheInterval_ShouldGetDifferentValue() + public async Task WithCachingTimeSpan_TwoCallsOutsideCacheInterval_ShouldGetDifferentValue() { // Arrange - string secretKeyValue = Guid.NewGuid().ToString("N"); + var secretKeyValue = Guid.NewGuid().ToString("N"); var testSecretProvider = new TestSecretProviderStub(secretKeyValue); - - string keyName = "MyValue"; + var keyName = "MyValue"; // Act ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromMilliseconds(100)); - var firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + await Task.Delay(TimeSpan.FromMilliseconds(150)); string newSecretValue = Guid.NewGuid().ToString("N"); - testSecretProvider.SecretValue = newSecretValue; // Change actual value on the internal secret provider ! - var secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + ChangeInternalCachedSecret(testSecretProvider, newSecretValue); + string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); // Assert Assert.Equal(secretKeyValue, firstValue); Assert.Equal(newSecretValue, secondValue); Assert.Equal(2, testSecretProvider.CallsMadeSinceCreation); } + + [Fact] + public async Task WithCachingDefault_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice() + { + // Arrange + var secretKeyValue = Guid.NewGuid().ToString("N"); + var testSecretProvider = new TestSecretProviderStub(secretKeyValue); + var keyName = "MyValue"; + + // Act + ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(); + string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + + ChangeInternalCachedSecret(testSecretProvider); + string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName); + + // Assert + Assert.Equal(firstValue, secondValue); + Assert.Equal(1, testSecretProvider.CallsMadeSinceCreation); + } + + private static void ChangeInternalCachedSecret(TestSecretProviderStub testSecretProvider) + { + ChangeInternalCachedSecret(testSecretProvider, Guid.NewGuid().ToString("N")); + } + + private static void ChangeInternalCachedSecret(TestSecretProviderStub testSecretProvider, string secretValue) + { + testSecretProvider.SecretValue = secretValue; + } } } diff --git a/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs b/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs index a0525a7b..56a8830c 100644 --- a/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs +++ b/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs @@ -23,7 +23,8 @@ public async Task GetRawSecret_WithVersion_ReturnsAll() var services = new ServiceCollection(); var secretName = "MySecret"; var amountOfVersions = 2; - var inMemory = new InMemorySecretVersionProvider(secretName, "secretValue", amountOfVersions); + var secretValue = "secretValue"; + var inMemory = new InMemorySecretVersionProvider(secretName, secretValue, amountOfVersions); services.AddSecretStore(stores => { stores.AddProvider(inMemory, options => options.AddVersionedSecret(secretName, amountOfVersions)); @@ -31,9 +32,17 @@ public async Task GetRawSecret_WithVersion_ReturnsAll() IServiceProvider serviceProvider = services.BuildServiceProvider(); var secretProvider = serviceProvider.GetRequiredService(); + var versionedProvider = (IVersionedSecretProvider) secretProvider; - IEnumerable secretValues = await secretProvider.GetRawSecretsAsync(secretName); - Assert.Equal(amountOfVersions, secretValues.Count()); + AssertCollectionCount(await secretProvider.GetSecretsAsync(secretName), amountOfVersions, secret => Assert.Equal(secretValue, secret.Value)); + AssertCollectionCount(await secretProvider.GetRawSecretsAsync(secretName), amountOfVersions, value => Assert.Equal(secretValue, value)); + AssertCollectionCount(await versionedProvider.GetSecretsAsync(secretName, amountOfVersions), amountOfVersions, secret => Assert.Equal(secretValue, secret.Value)); + AssertCollectionCount(await versionedProvider.GetRawSecretsAsync(secretName, amountOfVersions), amountOfVersions, value => Assert.Equal(secretValue, value)); + } + + private static void AssertCollectionCount(IEnumerable sequence, int assertionLength, Action assertion) + { + Assert.Collection(sequence, Enumerable.Repeat(assertion, assertionLength).ToArray()); } [Fact] diff --git a/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs b/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs index 47499593..4e1bc79c 100644 --- a/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs +++ b/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs @@ -94,7 +94,7 @@ public async Task KeyVaultSecretProvider_GetsRawSecretAsync_AfterRetriedTooManyR // Arrange string expected = $"secret-value-{Guid.NewGuid()}"; string secretName = $"secret-name-{Guid.NewGuid()}"; - KeyVaultSecretProvider provider = CreateSecretProviderWithTooManyRequestSimulation(expected); + KeyVaultSecretProvider provider = CreateOldSecretProviderWithTooManyRequestSimulation(expected); // Act string actual = await provider.GetRawSecretAsync(secretName); @@ -110,19 +110,19 @@ public async Task KeyVaultSecretProvider_GetsSecretAsync_AfterRetriedTooManyRequ string expected = $"secret-value-{Guid.NewGuid()}"; string secretName = $"secret-name-{Guid.NewGuid()}"; DateTime expirationDate = DateTime.UtcNow; - KeyVaultSecretProvider provider = CreateSecretProviderWithTooManyRequestSimulation(expected, expirationDate); // Act - Secret actual = await provider.GetSecretAsync(secretName); + KeyVaultSecretProvider provider = CreateOldSecretProviderWithTooManyRequestSimulation(expected, expirationDate); // Assert - Assert.NotNull(actual); - Assert.Equal(expected, actual.Value); - Assert.NotNull(actual.Version); - Assert.Equal(expirationDate, actual.Expires); + Secret actualFromAsync = await provider.GetSecretAsync(secretName); + Assert.NotNull(actualFromAsync); + Assert.Equal(expected, actualFromAsync.Value); + Assert.NotNull(actualFromAsync.Version); + Assert.Equal(expirationDate, actualFromAsync.Expires); } - private static KeyVaultSecretProvider CreateSecretProviderWithTooManyRequestSimulation(string expected, DateTime? expirationDate = null) + private static KeyVaultSecretProvider CreateOldSecretProviderWithTooManyRequestSimulation(string expected, DateTime? expirationDate = null) { // Arrange var keyVaultClient = new SimulatedKeyVaultClient( From 01c8c82786f919a2a518bd8905e44ae3ed559e17 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Mon, 16 Jan 2023 10:09:27 +0100 Subject: [PATCH 11/12] pr-fix: update w/o exclude attribute --- .../CertificateBasedAuthentication.cs | 1 - .../ManagedServiceIdentityAuthentication.cs | 1 - .../ServicePrincipalAuthentication.cs | 1 - .../DockerSecretsSecretProvider.cs | 1 - .../SecretStoreBuilderExtensions.cs | 1 - .../UserSecretsSecretProvider.cs | 1 - .../Core/CriticalExceptionsTests.cs | 9 +++-- .../Core/NamedSecretProviderTests.cs | 34 +++++++++++++++++++ .../Core/Stubs/SaboteurSecretProvider.cs | 26 +++++++++++++- 9 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 src/Arcus.Security.Tests.Unit/Core/NamedSecretProviderTests.cs diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs index 9d6e708b..3c6b409c 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs @@ -16,7 +16,6 @@ namespace Arcus.Security.Providers.AzureKeyVault.Authentication /// Azure Key Vault by using client ID and certificate to authenticate the . /// [Obsolete("Azure Key Vault authentication is moved to Azure Identity approach where the certificate authentication becomes: " + nameof(ClientCertificateCredential))] - [ExcludeFromCodeCoverage] public class CertificateBasedAuthentication : IKeyVaultAuthentication { private readonly string _clientId; diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs index 4bb2f880..b86941a3 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs @@ -12,7 +12,6 @@ namespace Arcus.Security.Providers.AzureKeyVault.Authentication /// /// Azure Key Vault authentication by using Azure Managed Service Identity /// - [ExcludeFromCodeCoverage] [Obsolete("Azure Key Vault authentication is moved to Azure Identity approach where the managed service identity authentication becomes: " + nameof(ManagedIdentityCredential))] public class ManagedServiceIdentityAuthentication : IKeyVaultAuthentication { diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs index 2223ca46..75532c3f 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs @@ -14,7 +14,6 @@ namespace Arcus.Security.Providers.AzureKeyVault.Authentication /// /// Representation of an that will generate a implementation using a service principle. /// - [ExcludeFromCodeCoverage] [Obsolete("Azure Key Vault authentication is moved to Azure Identity approach where the service principal authentication becomes: " + nameof(ClientSecretCredential))] public class ServicePrincipalAuthentication : IKeyVaultAuthentication { diff --git a/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs b/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs index bd80f22a..a64402de 100644 --- a/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs +++ b/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs @@ -12,7 +12,6 @@ namespace Arcus.Security.Providers.DockerSecrets /// /// Represents an that provides access to the Docker secrets mounted into the Docker container as files. /// - [ExcludeFromCodeCoverage] public class DockerSecretsSecretProvider : ISyncSecretProvider { private readonly KeyPerFileConfigurationProvider _provider; diff --git a/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs b/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs index 9b97e4dc..8d4b749b 100644 --- a/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs +++ b/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs @@ -12,7 +12,6 @@ namespace Microsoft.Extensions.Hosting /// /// Extensions on the to easily provide access to Docker secrets in the secret store. /// - [ExcludeFromCodeCoverage] public static class SecretStoreBuilderExtensions { /// diff --git a/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs b/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs index 6f334653..8c83cdba 100644 --- a/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs +++ b/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs @@ -10,7 +10,6 @@ namespace Arcus.Security.Providers.UserSecrets /// /// implementation that provides user secrets. /// - [ExcludeFromCodeCoverage] public class UserSecretsSecretProvider : ISyncSecretProvider { private readonly JsonConfigurationProvider _jsonProvider; diff --git a/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs index 9142edbd..ca4a3138 100644 --- a/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs +++ b/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using System.Threading.Tasks; using Arcus.Security.Core; using Arcus.Security.Tests.Unit.Core.Stubs; @@ -29,7 +26,10 @@ public async Task GetSecret_WithThrownCriticalException_FailsWithCriticalExcepti // Assert IServiceProvider serviceProvider = services.BuildServiceProvider(); var secretProvider = serviceProvider.GetRequiredService(); + Assert.Throws(() => secretProvider.GetSecret("Some.Secret")); + Assert.Throws(() => secretProvider.GetRawSecret("Some.Secret")); await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("Some.Secret")); + await Assert.ThrowsAsync(() => secretProvider.GetRawSecretAsync("Some.Secret")); } [Fact] @@ -48,7 +48,10 @@ public async Task GetSecret_WithThrownNonCriticalException_FailsWithSecretNotFou // Assert IServiceProvider serviceProvider = services.BuildServiceProvider(); var secretProvider = serviceProvider.GetRequiredService(); + Assert.Throws(() => secretProvider.GetSecret("Some.Secret")); + Assert.Throws(() => secretProvider.GetRawSecret("Some.Secret")); await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("Some.Secret")); + await Assert.ThrowsAsync(() => secretProvider.GetRawSecretAsync("Some.Secret")); } } } diff --git a/src/Arcus.Security.Tests.Unit/Core/NamedSecretProviderTests.cs b/src/Arcus.Security.Tests.Unit/Core/NamedSecretProviderTests.cs new file mode 100644 index 00000000..93585f30 --- /dev/null +++ b/src/Arcus.Security.Tests.Unit/Core/NamedSecretProviderTests.cs @@ -0,0 +1,34 @@ +using System; +using Arcus.Security.Core; +using Arcus.Security.Providers.AzureKeyVault; +using Arcus.Security.Tests.Unit.Core.Stubs; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Arcus.Security.Tests.Unit.Core +{ + public class NamedSecretProviderTests + { + [Fact] + public void GetCachedProvider_WithWrongCastType_Fails() + { + // Arrange + var services = new ServiceCollection(); + var name = "TestProvider"; + + // Act + services.AddSecretStore(stores => + { + stores.AddProvider( + new InMemoryCachedSecretProvider(("Secret.Name", "Secret.Value")), + options => options.Name = name); + }); + + // Assert + IServiceProvider serviceProvider = services.BuildServiceProvider(); + var secretProvider = serviceProvider.GetRequiredService(); + Assert.ThrowsAny( + () => secretProvider.GetCachedProvider(name)); + } + } +} diff --git a/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs b/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs index 24e75e27..329f6f62 100644 --- a/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs +++ b/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs @@ -8,7 +8,7 @@ namespace Arcus.Security.Tests.Unit.Core.Stubs /// /// Represents a that 'sabotage' the secret retrieval by throwing a user-defined exception. /// - public class SaboteurSecretProvider: ISecretProvider + public class SaboteurSecretProvider: ISyncSecretProvider { private readonly Exception _exception; @@ -48,5 +48,29 @@ public Task GetSecretAsync(string secretName) { throw _exception; } + + /// + /// Retrieves the secret value, based on the given name + /// + /// The name of the secret key + /// Returns the secret key. + /// Thrown when the is blank. + /// Thrown when the secret was not found, using the given name. + public string GetRawSecret(string secretName) + { + throw _exception; + } + + /// + /// Retrieves the secret value, based on the given name + /// + /// The name of the secret key + /// Returns a that contains the secret key + /// Thrown when the is blank. + /// Thrown when the secret was not found, using the given name. + public Secret GetSecret(string secretName) + { + throw _exception; + } } } From 691dd83d94adbda61d5b5d3a456a11bc32b0ecc5 Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Mon, 16 Jan 2023 11:14:21 +0100 Subject: [PATCH 12/12] pr-fix: update w/o unn usings --- .../Authentication/CertificateBasedAuthentication.cs | 1 - .../Authentication/ManagedServiceIdentityAuthentication.cs | 1 - .../Authentication/ServicePrincipalAuthentication.cs | 1 - .../DockerSecretsSecretProvider.cs | 1 - .../Extensions/SecretStoreBuilderExtensions.cs | 1 - .../UserSecretsSecretProvider.cs | 1 - 6 files changed, 6 deletions(-) diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs index 3c6b409c..3459761f 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/CertificateBasedAuthentication.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs index b86941a3..7600e528 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ManagedServiceIdentityAuthentication.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Azure.Identity; using Microsoft.Azure.KeyVault; diff --git a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs index 75532c3f..24ba25bb 100644 --- a/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs +++ b/src/Arcus.Security.Providers.AzureKeyVault/Authentication/ServicePrincipalAuthentication.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Security.Authentication; using System.Threading.Tasks; using Azure.Identity; diff --git a/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs b/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs index a64402de..a25cc585 100644 --- a/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs +++ b/src/Arcus.Security.Providers.DockerSecrets/DockerSecretsSecretProvider.cs @@ -2,7 +2,6 @@ using GuardNet; using Microsoft.Extensions.Configuration.KeyPerFile; using System; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; using Microsoft.Extensions.FileProviders; diff --git a/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs b/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs index 8d4b749b..27e6498a 100644 --- a/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs +++ b/src/Arcus.Security.Providers.DockerSecrets/Extensions/SecretStoreBuilderExtensions.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.IO; using Arcus.Security.Providers.DockerSecrets; using GuardNet; diff --git a/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs b/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs index 8c83cdba..ddcc8b6f 100644 --- a/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs +++ b/src/Arcus.Security.Providers.UserSecrets/UserSecretsSecretProvider.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Arcus.Security.Core; using GuardNet;