From b9a214a358659d47d97ee18abd478ce5c175f07c Mon Sep 17 00:00:00 2001 From: Pravin Pushkar Date: Fri, 18 Aug 2023 11:11:39 +0530 Subject: [PATCH 01/13] secret store component Signed-off-by: Pravin Pushkar --- .../Dapr.PluggableComponents.Protos.csproj | 7 +- .../Components/SecretStores/ISecretStore.cs | 37 +++++++++ .../SecretStores/SecretStoreBulkGetRequest.cs | 37 +++++++++ .../SecretStoreBulkGetResponse.cs | 20 +++++ .../SecretStores/SecretStoreGetRequest.cs | 37 +++++++++ .../SecretStores/SecretStoreGetResponse.cs | 79 +++++++++++++++++++ 6 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs create mode 100644 src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs create mode 100644 src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs create mode 100644 src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs create mode 100644 src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs diff --git a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj index db90760..1aeeae6 100644 --- a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj +++ b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj @@ -1,8 +1,8 @@ - + v1 - v1.11.0 + master https://raw.githubusercontent.com/dapr/dapr/$(ProtosTag)/dapr/proto/components/$(ProtosVersion) $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework)\Protos $(ProtosRootDir)\dapr\proto\components\$(ProtosVersion) @@ -13,6 +13,7 @@ + @@ -44,4 +45,4 @@ DestinationFolder="$(ProtosComponentsDir)" /> - + \ No newline at end of file diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs b/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs new file mode 100644 index 0000000..497e206 --- /dev/null +++ b/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +namespace Dapr.PluggableComponents.Components.SecretStores; + +/// +/// Represents a secret store Dapr Pluggable Component. +/// +public interface ISecretStore : IPluggableComponent +{ + /// + /// Called to get secret. + /// + /// Properties related to the secret to be retrieved. + /// The token to monitor for cancellation requests. + /// A representing the asynchronous operation, resulting in the retrieved secret, if any. + Task GetAsync(SecretStoreGetRequest request, CancellationToken cancellationToken = default); + + /// + /// Called to get bulk secret. + /// + /// Properties related to the secret to be retrieved. + /// The token to monitor for cancellation requests. + /// A representing the asynchronous operation, resulting in the retrieved secret, if any. + Task BulkGetAsync(SecretStoreBulkGetRequest request, CancellationToken cancellationToken = default); + +} diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs new file mode 100644 index 0000000..0964a39 --- /dev/null +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using Dapr.Proto.Components.V1; + +namespace Dapr.PluggableComponents.Components.SecretStores; + + +/// +/// Represents properties associated with a request to retrieve all secrets from a secret store. +/// +/// The secret that should be retrieved. +public sealed record SecretStoreBulkGetRequest() +{ + /// + /// Gets the metadata associated with the request. + /// + public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); + + internal static SecretStoreBulkGetRequest FromGetRequest(BulkGetSecretRequest request) + { + return new SecretStoreBulkGetRequest() + { + Metadata = request.Metadata + }; + } +} diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs new file mode 100644 index 0000000..ae31359 --- /dev/null +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using Dapr.PluggableComponents.Utilities; +using Dapr.Proto.Components.V1; +using Google.Protobuf; + +namespace Dapr.PluggableComponents.Components.SecretStores; + + diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs new file mode 100644 index 0000000..523da3d --- /dev/null +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using Dapr.Proto.Components.V1; + +namespace Dapr.PluggableComponents.Components.SecretStores; + +/// +/// Represents properties associated with a request to retrieve a secret from a secret store. +/// +/// The secret that should be retrieved. +public sealed record SecretStoreGetRequest(string secretName) +{ + /// + /// Gets the metadata associated with the request. + /// + public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); + + internal static SecretStoreGetRequest FromGetRequest(GetSecretRequest request) + { + return new SecretStoreGetRequest(request.Key) + { + Metadata = request.Metadata + }; + } +} + diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs new file mode 100644 index 0000000..fff3781 --- /dev/null +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs @@ -0,0 +1,79 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using Dapr.PluggableComponents.Utilities; +using Dapr.Proto.Components.V1; +using Google.Protobuf; + +namespace Dapr.PluggableComponents.Components.SecretStores; + +/// +/// Represents properties associated with a response to retrieving secret from a secret store. +/// +public sealed record SecretStoreGetResponse +{ + /// + /// Gets or sets the key's value. + /// + /// + /// If omitted, defaults to an empty array. + /// + public IReadOnlyDictionary Data = new Dictionary(); + + + + /// + /// Gets or sets the metadata associated with the request. + /// + /// + /// If omitted, defaults to an empty dictionary. + /// + public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); + + internal static GetSecretResponse ToGetResponse(SecretStoreGetResponse? response) + { + var grpcResponse = new GetSecretResponse(); + + // NOTE: in case of not found, you should not return any error. + + if (response != null) + { + grpcResponse.Data.Add(response.Data); + } + + return grpcResponse; + } + + /*internal static BulksecretItem ToBulksecretItem(string key, secretStoreGetResponse? response) + { + var secretItem = new BulksecretItem + { + Key = key + }; + + if (response != null) + { + secretItem.ContentType = response.ContentType ?? String.Empty; + secretItem.Data = ByteString.CopyFrom(response.Data); + secretItem.Etag = response.ETag != null ? new Etag { Value = response.ETag } : null; + + secretItem.Metadata.Add(response.Metadata); + } + else + { + secretItem.Error = "Unable to fetch the item."; + } + + return secretItem; + }*/ +} From 3df1de5426f257957d55a1185013f0376f133b5f Mon Sep 17 00:00:00 2001 From: Pravin Pushkar Date: Fri, 18 Aug 2023 14:05:44 +0530 Subject: [PATCH 02/13] take -2 Signed-off-by: Pravin Pushkar --- Dapr.PluggableComponents.Complete.sln | 7 ++ .../LocalEnvSecretStoreSample.csproj | 15 +++ samples/LocalEnvSecretStoreSample/Program.cs | 6 + .../appsettings.Development.json | 8 ++ .../appsettings.json | 9 ++ samples/dotnet | 0 .../DaprPluggableComponentsServiceBuilder.cs | 51 ++++++++ .../Dapr.PluggableComponents.Protos.csproj | 10 +- .../Adaptors/SecretStoreAdaptor.cs | 119 ++++++++++++++++++ .../SecretStores/SecretStoreBulkGetRequest.cs | 2 +- .../SecretStoreBulkGetResponse.cs | 17 +++ 11 files changed, 236 insertions(+), 8 deletions(-) create mode 100644 samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj create mode 100644 samples/LocalEnvSecretStoreSample/Program.cs create mode 100644 samples/LocalEnvSecretStoreSample/appsettings.Development.json create mode 100644 samples/LocalEnvSecretStoreSample/appsettings.json create mode 100644 samples/dotnet create mode 100644 src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs diff --git a/Dapr.PluggableComponents.Complete.sln b/Dapr.PluggableComponents.Complete.sln index b06cf97..e793979 100644 --- a/Dapr.PluggableComponents.Complete.sln +++ b/Dapr.PluggableComponents.Complete.sln @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordBindingSample", "sam EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.PluggableComponents.Tests", "src\Dapr.PluggableComponents.Tests\Dapr.PluggableComponents.Tests.csproj", "{C9027B0B-A589-4E92-AB32-34B8961C479B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LocalEnvSecretStoreSample", "samples\LocalEnvSecretStoreSample\LocalEnvSecretStoreSample.csproj", "{FB79E8DE-3AA9-47E0-9EA6-627DCAFC6068}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -60,6 +62,10 @@ Global {C9027B0B-A589-4E92-AB32-34B8961C479B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9027B0B-A589-4E92-AB32-34B8961C479B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C9027B0B-A589-4E92-AB32-34B8961C479B}.Release|Any CPU.Build.0 = Release|Any CPU + {FB79E8DE-3AA9-47E0-9EA6-627DCAFC6068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB79E8DE-3AA9-47E0-9EA6-627DCAFC6068}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB79E8DE-3AA9-47E0-9EA6-627DCAFC6068}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB79E8DE-3AA9-47E0-9EA6-627DCAFC6068}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {E54270BE-EF83-47BE-B29C-29BC89701099} = {8E8203A7-A0B9-4F48-9CD4-DE9A0D3B73FB} @@ -69,5 +75,6 @@ Global {A6565BA8-E05C-4B4E-A908-C4B86232F9AB} = {6F4E950F-E4CD-4FA4-BA3D-528F0022C03B} {BCE0E3E4-60D9-4947-9E1A-300640BE5FBF} = {6F4E950F-E4CD-4FA4-BA3D-528F0022C03B} {C9027B0B-A589-4E92-AB32-34B8961C479B} = {8E8203A7-A0B9-4F48-9CD4-DE9A0D3B73FB} + {FB79E8DE-3AA9-47E0-9EA6-627DCAFC6068} = {6F4E950F-E4CD-4FA4-BA3D-528F0022C03B} EndGlobalSection EndGlobal diff --git a/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj new file mode 100644 index 0000000..222b9e0 --- /dev/null +++ b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj @@ -0,0 +1,15 @@ + + + + net7.0 + enable + enable + + + + + + + + + diff --git a/samples/LocalEnvSecretStoreSample/Program.cs b/samples/LocalEnvSecretStoreSample/Program.cs new file mode 100644 index 0000000..bc8438c --- /dev/null +++ b/samples/LocalEnvSecretStoreSample/Program.cs @@ -0,0 +1,6 @@ +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapGet("/", () => "Hello World!"); + +app.Run(); diff --git a/samples/LocalEnvSecretStoreSample/appsettings.Development.json b/samples/LocalEnvSecretStoreSample/appsettings.Development.json new file mode 100644 index 0000000..ff66ba6 --- /dev/null +++ b/samples/LocalEnvSecretStoreSample/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/LocalEnvSecretStoreSample/appsettings.json b/samples/LocalEnvSecretStoreSample/appsettings.json new file mode 100644 index 0000000..4d56694 --- /dev/null +++ b/samples/LocalEnvSecretStoreSample/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/samples/dotnet b/samples/dotnet new file mode 100644 index 0000000..e69de29 diff --git a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs index 0d2bdbb..07a895f 100644 --- a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs +++ b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs @@ -14,6 +14,7 @@ using Dapr.PluggableComponents.Adaptors; using Dapr.PluggableComponents.Components.Bindings; using Dapr.PluggableComponents.Components.PubSub; +using Dapr.PluggableComponents.Components.SecretStores; using Dapr.PluggableComponents.Components.StateStore; namespace Dapr.PluggableComponents; @@ -181,6 +182,51 @@ public DaprPluggableComponentsServiceBuilder RegisterStateStore(Com #endregion + #region Secret Store Registration + + /// + /// Registers a singleton secret store with this service. + /// + /// The type of secret store to register. + /// The current instance. + /// + /// A single instance of the secret store will be created to service all configured Dapr components. + /// + /// Only a single secret store type can be associated with a given service. + /// + public DaprPluggableComponentsServiceBuilder RegisterSecretStore() where TSecretStore : class, ISecretStore + { + this.AddComponent(); + + this.AddRelatedSecretStoreServices(); + + return this; + } + + /// + /// Registers a secret store with this service. + /// + /// The type of secret store to register. + /// A factory method called when creating new secret store instances. + /// The current instance. + /// + /// The factory method will be called once for each configured Dapr component; the returned instance will be + /// associated with that Dapr component and methods invoked when the component receives requests. + /// + /// Only a single secret store type can be associated with a given service. + /// + public DaprPluggableComponentsServiceBuilder RegisterSecretStore(ComponentProviderDelegate secretStoreFactory) + where TSecretStore : class, ISecretStore + { + this.AddComponent(secretStoreFactory); + + this.AddRelatedSecretStoreServices(); + + return this; + } + + #endregion + private void AddComponent() where TComponentType : class where TComponentImpl : class, TComponentType @@ -236,4 +282,9 @@ private void AddRelatedStateStoreServices() where TStateStore : cla this.AddRelatedService(); } } + + private void AddRelatedSecretStoreServices() where TSecretStore : class + { + this.AddRelatedService(); + } } diff --git a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj index 1aeeae6..605263f 100644 --- a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj +++ b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj @@ -23,7 +23,7 @@ - + @@ -37,12 +37,8 @@ - - + + \ No newline at end of file diff --git a/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs b/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs new file mode 100644 index 0000000..8542689 --- /dev/null +++ b/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs @@ -0,0 +1,119 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using Dapr.Client.Autogen.Grpc.v1; +using Dapr.PluggableComponents.Components; +using Dapr.PluggableComponents.Components.SecretStores; +using Dapr.PluggableComponents.Utilities; +using Dapr.Proto.Components.V1; +using Google.Protobuf; +using Grpc.Core; +using Microsoft.Extensions.Logging; +using static Dapr.Proto.Components.V1.SecretStore; + +namespace Dapr.PluggableComponents.Adaptors; + +/// +/// Represents the gRPC protocol adaptor for a state store Dapr Pluggable Component. +/// +/// +/// An instances of this class is created for every request made to the component. +/// +public class SecretStoreAdaptor : SecretStoreBase +{ + private readonly ILogger logger; + private readonly IDaprPluggableComponentProvider componentProvider; + + /// + /// Creates a new instance of the class. + /// + /// A logger used for internal purposes. + /// A means to obtain the Dapr Pluggable Component associated with this adapter instance. + /// If any parameter is null. + public SecretStoreAdaptor(ILogger logger, IDaprPluggableComponentProvider componentProvider) + { + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + this.componentProvider = componentProvider ?? throw new ArgumentNullException(nameof(componentProvider)); + } + + + /// + public override async Task BulkGet(BulkGetSecretRequest request, ServerCallContext context) + { + this.logger.LogDebug("Bulk get request for secret"); + + var secretStore = this.GetSecretStore(context); + + return null; + } + + /// + public override async Task Features(FeaturesRequest request, ServerCallContext context) + { + this.logger.LogDebug("Features request"); + + var response = new FeaturesResponse(); + + if (this.GetSecretStore(context) is IPluggableComponentFeatures features) + { + var featuresResponse = await features.GetFeaturesAsync(context.CancellationToken); + + response.Features.AddRange(featuresResponse); + } + + return response; + } + + /// + public override async Task Get(GetSecretRequest request, ServerCallContext context) + { + this.logger.LogDebug("Get request for key {key}", request.Key); + + var response = await this.GetSecretStore(context).GetAsync( + SecretStoreGetRequest.FromGetRequest(request), + context.CancellationToken); + + return SecretStoreGetResponse.ToGetResponse(response); + } + + /// + public async override Task Init(Proto.Components.V1.SecretStoreInitRequest request, ServerCallContext context) + { + this.logger.LogDebug("Init request"); + + await this.GetSecretStore(context).InitAsync( + Components.MetadataRequest.FromMetadataRequest(request.Metadata), + context.CancellationToken); + + return new SecretStoreInitResponse(); + } + + /// + public override async Task Ping(PingRequest request, ServerCallContext context) + { + this.logger.LogDebug("Ping request"); + + if (this.GetSecretStore(context) is IPluggableComponentLiveness ping) + { + await ping.PingAsync(context.CancellationToken); + } + + return new PingResponse(); + } + + private ISecretStore GetSecretStore(ServerCallContext context) + { + return this.componentProvider.GetComponent(context); + } +} + diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs index 0964a39..ceb8ed0 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs @@ -20,7 +20,7 @@ namespace Dapr.PluggableComponents.Components.SecretStores; /// Represents properties associated with a request to retrieve all secrets from a secret store. /// /// The secret that should be retrieved. -public sealed record SecretStoreBulkGetRequest() +public sealed record SecretStoreBulkGetRequest { /// /// Gets the metadata associated with the request. diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs index ae31359..423330e 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs @@ -17,4 +17,21 @@ namespace Dapr.PluggableComponents.Components.SecretStores; +public sealed record SecretStoreBulkGetResponse +{ + //public IReadOnlyDictionary> responseData = new Dictionary>(); + public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); + + internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse? response) + { + var grpcResponse = new BulkGetSecretResponse(); + + if (response != null) + { + grpcResponse.Data.ToDictionary(r => r.Key, r => r.Value.Secrets.ToDictionary(s => s.Key, s => s.Value)); + } + return grpcResponse; + } +} + From c7ef3620136470a6d2da32c1be199b9ec3086252 Mon Sep 17 00:00:00 2001 From: Pravin Pushkar Date: Fri, 18 Aug 2023 16:17:11 +0530 Subject: [PATCH 03/13] Sample app Signed-off-by: Pravin Pushkar --- .../LocalEnvSecretStoreSample.csproj | 13 ++++- samples/LocalEnvSecretStoreSample/Program.cs | 20 +++++-- .../Services/LocalEnvSecretStore.cs | 54 +++++++++++++++++++ .../DaprPluggableComponentsServiceBuilder.cs | 4 +- 4 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs diff --git a/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj index 222b9e0..efd1bce 100644 --- a/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj +++ b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj @@ -6,10 +6,19 @@ enable - - + + + + + + + + + + + diff --git a/samples/LocalEnvSecretStoreSample/Program.cs b/samples/LocalEnvSecretStoreSample/Program.cs index bc8438c..549f66d 100644 --- a/samples/LocalEnvSecretStoreSample/Program.cs +++ b/samples/LocalEnvSecretStoreSample/Program.cs @@ -1,6 +1,18 @@ -var builder = WebApplication.CreateBuilder(args); -var app = builder.Build(); +using Dapr.PluggableComponents; +using LocalEnvSecretStoreSample.Services; -app.MapGet("/", () => "Hello World!"); +var app = DaprPluggableComponentsApplication.Create(); -app.Run(); +app.RegisterService( + "local.env-pluggable", + serviceBuilder => + { + serviceBuilder.RegisterSecretStore( + context => + { + Console.WriteLine("Creating secret store for instance '{0}' on socket '{1}'...", context.InstanceId, context.SocketPath); + return new LocalEnvSecretStore(context.ServiceProvider.GetRequiredService>()); + }); + }); + +app.Run(); \ No newline at end of file diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs new file mode 100644 index 0000000..674eaf6 --- /dev/null +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -0,0 +1,54 @@ +using Dapr.PluggableComponents.Components; +using Dapr.PluggableComponents.Components.SecretStores; + +namespace LocalEnvSecretStoreSample.Services; + +internal sealed class LocalEnvSecretStore : ISecretStore +{ + private readonly ILogger logger; + + public LocalEnvSecretStore(ILogger logger) + { + this.logger = logger; + } + + #region ISecretStore Members + + public Task GetAsync(SecretStoreGetRequest request, CancellationToken cancellationToken = default) + { + this.logger.LogInformation("Get request for secret {key}", request.secretName); + + SecretStoreGetResponse? response = null; + string data = Environment.GetEnvironmentVariable(request.secretName); + if (data == null) + { + data = ""; + } + Dictionary resp = new Dictionary(); + resp.Add(request.secretName, data); + response = new SecretStoreGetResponse + { + Data = resp + }; + + return Task.FromResult(response); + } + + public Task BulkGetAsync(SecretStoreBulkGetRequest request, CancellationToken cancellationToken = default) + { + this.logger.LogInformation("Get request for all secrets"); + + SecretStoreBulkGetResponse? response = null; + //this.logger.LogInformation(Environment.GetEnvironmentVariables()); + + + return Task.FromResult(response); + } + + public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + #endregion +} diff --git a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs index 07a895f..0355ca4 100644 --- a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs +++ b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs @@ -196,7 +196,7 @@ public DaprPluggableComponentsServiceBuilder RegisterStateStore(Com /// public DaprPluggableComponentsServiceBuilder RegisterSecretStore() where TSecretStore : class, ISecretStore { - this.AddComponent(); + this.AddComponent(); this.AddRelatedSecretStoreServices(); @@ -218,7 +218,7 @@ public DaprPluggableComponentsServiceBuilder RegisterSecretStore() public DaprPluggableComponentsServiceBuilder RegisterSecretStore(ComponentProviderDelegate secretStoreFactory) where TSecretStore : class, ISecretStore { - this.AddComponent(secretStoreFactory); + this.AddComponent(secretStoreFactory); this.AddRelatedSecretStoreServices(); From a4b4db6897bf8d98eadfff3346a85a143c3d7a82 Mon Sep 17 00:00:00 2001 From: Pravin Pushkar Date: Tue, 22 Aug 2023 22:35:50 +0530 Subject: [PATCH 04/13] Fix bulk get Signed-off-by: Pravin Pushkar --- .../LocalEnvSecretStoreSample.csproj | 2 +- .../Services/LocalEnvSecretStore.cs | 12 +++++++--- samples/dotnet | 0 .../DaprPluggableComponentsServiceBuilder.cs | 6 ----- .../Adaptors/SecretStoreAdaptor.cs | 21 ++++++++--------- .../SecretStoreBulkGetResponse.cs | 10 +++++--- .../SecretStores/SecretStoreGetResponse.cs | 23 ------------------- 7 files changed, 27 insertions(+), 47 deletions(-) delete mode 100644 samples/dotnet diff --git a/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj index efd1bce..ead26fe 100644 --- a/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj +++ b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj @@ -1,7 +1,7 @@ - net7.0 + net6.0 enable enable diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs index 674eaf6..531aa36 100644 --- a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -39,9 +39,15 @@ public Task BulkGetAsync(SecretStoreBulkGetRequest r this.logger.LogInformation("Get request for all secrets"); SecretStoreBulkGetResponse? response = null; - //this.logger.LogInformation(Environment.GetEnvironmentVariables()); - - + Dictionary resp = new Dictionary(); + foreach (string key in Environment.GetEnvironmentVariables().Keys) + { + resp.Add(key, Environment.GetEnvironmentVariable(key)); + } + response = new SecretStoreBulkGetResponse + { + Data = resp + }; return Task.FromResult(response); } diff --git a/samples/dotnet b/samples/dotnet deleted file mode 100644 index e69de29..0000000 diff --git a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs index 0355ca4..780f45a 100644 --- a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs +++ b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs @@ -197,9 +197,6 @@ public DaprPluggableComponentsServiceBuilder RegisterStateStore(Com public DaprPluggableComponentsServiceBuilder RegisterSecretStore() where TSecretStore : class, ISecretStore { this.AddComponent(); - - this.AddRelatedSecretStoreServices(); - return this; } @@ -219,9 +216,6 @@ public DaprPluggableComponentsServiceBuilder RegisterSecretStore(C where TSecretStore : class, ISecretStore { this.AddComponent(secretStoreFactory); - - this.AddRelatedSecretStoreServices(); - return this; } diff --git a/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs b/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs index 8542689..c0737a0 100644 --- a/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs +++ b/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs @@ -46,17 +46,6 @@ public SecretStoreAdaptor(ILogger logger, IDaprPluggableComp this.componentProvider = componentProvider ?? throw new ArgumentNullException(nameof(componentProvider)); } - - /// - public override async Task BulkGet(BulkGetSecretRequest request, ServerCallContext context) - { - this.logger.LogDebug("Bulk get request for secret"); - - var secretStore = this.GetSecretStore(context); - - return null; - } - /// public override async Task Features(FeaturesRequest request, ServerCallContext context) { @@ -86,6 +75,16 @@ public override async Task Get(GetSecretRequest request, Serv return SecretStoreGetResponse.ToGetResponse(response); } + /// + public override async Task BulkGet(BulkGetSecretRequest request, ServerCallContext context) + { + this.logger.LogDebug("Bulk get request for secret"); + + var secretStore = this.GetSecretStore(context); + var response = await secretStore.BulkGetAsync(SecretStoreBulkGetRequest.FromGetRequest(request), context.CancellationToken); + return SecretStoreBulkGetResponse.ToBulkGetResponse(response); + } + /// public async override Task Init(Proto.Components.V1.SecretStoreInitRequest request, ServerCallContext context) { diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs index 423330e..9e6828e 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs @@ -19,16 +19,20 @@ namespace Dapr.PluggableComponents.Components.SecretStores; public sealed record SecretStoreBulkGetResponse { - //public IReadOnlyDictionary> responseData = new Dictionary>(); + public IReadOnlyDictionary Data = new Dictionary(); public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse? response) { var grpcResponse = new BulkGetSecretResponse(); - if (response != null) { - grpcResponse.Data.ToDictionary(r => r.Key, r => r.Value.Secrets.ToDictionary(s => s.Key, s => s.Value)); + foreach (var item in response.Data) + { + var secretItem = new SecretResponse(); + secretItem.Secrets.Add(item.Key, item.Value); + grpcResponse.Data.Add(item.Key, secretItem); + } } return grpcResponse; } diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs index fff3781..fe6894b 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs @@ -53,27 +53,4 @@ internal static GetSecretResponse ToGetResponse(SecretStoreGetResponse? response return grpcResponse; } - - /*internal static BulksecretItem ToBulksecretItem(string key, secretStoreGetResponse? response) - { - var secretItem = new BulksecretItem - { - Key = key - }; - - if (response != null) - { - secretItem.ContentType = response.ContentType ?? String.Empty; - secretItem.Data = ByteString.CopyFrom(response.Data); - secretItem.Etag = response.ETag != null ? new Etag { Value = response.ETag } : null; - - secretItem.Metadata.Add(response.Metadata); - } - else - { - secretItem.Error = "Unable to fetch the item."; - } - - return secretItem; - }*/ } From ebe30bc9fee818931df568338f759feb5deefe74 Mon Sep 17 00:00:00 2001 From: Pravin Pushkar Date: Tue, 22 Aug 2023 22:50:06 +0530 Subject: [PATCH 05/13] Fix Review comments Signed-off-by: Pravin Pushkar --- .../Services/LocalEnvSecretStore.cs | 6 +++--- .../Components/SecretStores/ISecretStore.cs | 4 ++-- .../SecretStores/SecretStoreBulkGetResponse.cs | 1 - .../Components/SecretStores/SecretStoreGetRequest.cs | 4 ++-- .../Components/SecretStores/SecretStoreGetResponse.cs | 9 --------- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs index 531aa36..3fc7122 100644 --- a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -16,16 +16,16 @@ public LocalEnvSecretStore(ILogger logger) public Task GetAsync(SecretStoreGetRequest request, CancellationToken cancellationToken = default) { - this.logger.LogInformation("Get request for secret {key}", request.secretName); + this.logger.LogInformation("Get request for secret {key}", request.SecretName); SecretStoreGetResponse? response = null; - string data = Environment.GetEnvironmentVariable(request.secretName); + string data = Environment.GetEnvironmentVariable(request.SecretName); if (data == null) { data = ""; } Dictionary resp = new Dictionary(); - resp.Add(request.secretName, data); + resp.Add(request.SecretName, data); response = new SecretStoreGetResponse { Data = resp diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs b/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs index 497e206..a1956a9 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs @@ -24,7 +24,7 @@ public interface ISecretStore : IPluggableComponent /// Properties related to the secret to be retrieved. /// The token to monitor for cancellation requests. /// A representing the asynchronous operation, resulting in the retrieved secret, if any. - Task GetAsync(SecretStoreGetRequest request, CancellationToken cancellationToken = default); + Task GetAsync(SecretStoreGetRequest request, CancellationToken cancellationToken = default); /// /// Called to get bulk secret. @@ -32,6 +32,6 @@ public interface ISecretStore : IPluggableComponent /// Properties related to the secret to be retrieved. /// The token to monitor for cancellation requests. /// A representing the asynchronous operation, resulting in the retrieved secret, if any. - Task BulkGetAsync(SecretStoreBulkGetRequest request, CancellationToken cancellationToken = default); + Task BulkGetAsync(SecretStoreBulkGetRequest request, CancellationToken cancellationToken = default); } diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs index 9e6828e..0910f81 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs @@ -20,7 +20,6 @@ namespace Dapr.PluggableComponents.Components.SecretStores; public sealed record SecretStoreBulkGetResponse { public IReadOnlyDictionary Data = new Dictionary(); - public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse? response) { diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs index 523da3d..1155f9f 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs @@ -18,8 +18,8 @@ namespace Dapr.PluggableComponents.Components.SecretStores; /// /// Represents properties associated with a request to retrieve a secret from a secret store. /// -/// The secret that should be retrieved. -public sealed record SecretStoreGetRequest(string secretName) +/// The secret that should be retrieved. +public sealed record SecretStoreGetRequest(string SecretName) { /// /// Gets the metadata associated with the request. diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs index fe6894b..5e1070e 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs @@ -31,15 +31,6 @@ public sealed record SecretStoreGetResponse public IReadOnlyDictionary Data = new Dictionary(); - - /// - /// Gets or sets the metadata associated with the request. - /// - /// - /// If omitted, defaults to an empty dictionary. - /// - public IReadOnlyDictionary Metadata { get; init; } = new Dictionary(); - internal static GetSecretResponse ToGetResponse(SecretStoreGetResponse? response) { var grpcResponse = new GetSecretResponse(); From 56ee09b9758c3d454477bdb0b3b6f7c72b32667d Mon Sep 17 00:00:00 2001 From: Pravin Pushkar Date: Wed, 23 Aug 2023 23:31:50 +0530 Subject: [PATCH 06/13] Addressed review comments Signed-off-by: Pravin Pushkar --- .../LocalEnvSecretStoreSample.csproj | 4 -- .../Services/LocalEnvSecretStore.cs | 19 ++++++-- .../Dapr.PluggableComponents.Protos.csproj | 2 +- .../SecretStoreBulkGetResponse.cs | 13 +++-- .../SecretStores/SecretStoreGetResponse.cs | 4 +- .../SecretStores/SecretStoreResponse.cs | 47 +++++++++++++++++++ 6 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreResponse.cs diff --git a/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj index ead26fe..928a1c5 100644 --- a/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj +++ b/samples/LocalEnvSecretStoreSample/LocalEnvSecretStoreSample.csproj @@ -6,10 +6,6 @@ enable - - - - diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs index 3fc7122..ae7b279 100644 --- a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -1,4 +1,5 @@ -using Dapr.PluggableComponents.Components; +using System; +using Dapr.PluggableComponents.Components; using Dapr.PluggableComponents.Components.SecretStores; namespace LocalEnvSecretStoreSample.Services; @@ -39,14 +40,24 @@ public Task BulkGetAsync(SecretStoreBulkGetRequest r this.logger.LogInformation("Get request for all secrets"); SecretStoreBulkGetResponse? response = null; - Dictionary resp = new Dictionary(); + SecretStoreResponse? secretStoreResponse = null; + Dictionary? resp = null; + Dictionary bulkResp = new Dictionary(); foreach (string key in Environment.GetEnvironmentVariables().Keys) { - resp.Add(key, Environment.GetEnvironmentVariable(key)); + resp = new Dictionary + { + {key, Environment.GetEnvironmentVariable(key) } + }; + secretStoreResponse = new SecretStoreResponse + { + Data = resp + }; + bulkResp.Add(key, secretStoreResponse); } response = new SecretStoreBulkGetResponse { - Data = resp + Data = bulkResp }; return Task.FromResult(response); } diff --git a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj index 605263f..abd27ae 100644 --- a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj +++ b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs index 0910f81..901396b 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs @@ -19,18 +19,21 @@ namespace Dapr.PluggableComponents.Components.SecretStores; public sealed record SecretStoreBulkGetResponse { - public IReadOnlyDictionary Data = new Dictionary(); + public IReadOnlyDictionary Data { get; init; } = new Dictionary(); - internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse? response) + internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse response) { var grpcResponse = new BulkGetSecretResponse(); if (response != null) { foreach (var item in response.Data) { - var secretItem = new SecretResponse(); - secretItem.Secrets.Add(item.Key, item.Value); - grpcResponse.Data.Add(item.Key, secretItem); + var secretResp = new SecretResponse(); + foreach (var sec in item.Value.Data) + { + secretResp.Secrets.Add(sec.Key, sec.Value); + grpcResponse.Data.Add(sec.Key, secretResp); + } } } return grpcResponse; diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs index 5e1070e..1a64b97 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs @@ -28,10 +28,10 @@ public sealed record SecretStoreGetResponse /// /// If omitted, defaults to an empty array. /// - public IReadOnlyDictionary Data = new Dictionary(); + public IReadOnlyDictionary Data { get; init; } = new Dictionary(); - internal static GetSecretResponse ToGetResponse(SecretStoreGetResponse? response) + internal static GetSecretResponse ToGetResponse(SecretStoreGetResponse response) { var grpcResponse = new GetSecretResponse(); diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreResponse.cs new file mode 100644 index 0000000..7b3af5c --- /dev/null +++ b/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreResponse.cs @@ -0,0 +1,47 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using Dapr.PluggableComponents.Utilities; +using Dapr.Proto.Components.V1; +using Google.Protobuf; +namespace Dapr.PluggableComponents.Components.SecretStores; + +/// +/// Represents properties associated with a response to retrieving bulk secret from a secret store. +/// +public sealed record SecretStoreResponse +{ + /// + /// Gets or sets the key's value. + /// + /// + /// If omitted, defaults to an empty array. + /// + public IReadOnlyDictionary Data { get; init; } = new Dictionary(); + + + internal static SecretResponse ToGetResponse(SecretStoreResponse response) + { + var grpcResponse = new SecretResponse(); + + // NOTE: in case of not found, you should not return any error. + + if (response != null) + { + grpcResponse.Secrets.Add(response.Data); + } + + return grpcResponse; + } +} + From df79cef832af04158b444f31bd8a04e03bc2ba5f Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Sat, 19 Oct 2024 23:19:30 -0700 Subject: [PATCH 07/13] Renaming. Signed-off-by: Phillip Hoff --- .../Services/LocalEnvSecretStore.cs | 9 ++++----- .../DaprPluggableComponentsServiceBuilder.cs | 2 +- .../Adaptors/SecretStoreAdaptor.cs | 4 +--- .../{SecretStores => SecretStore}/ISecretStore.cs | 2 +- .../SecretStoreBulkGetRequest.cs | 3 +-- .../SecretStoreBulkGetResponse.cs | 2 +- .../SecretStoreGetRequest.cs | 2 +- .../SecretStoreGetResponse.cs | 2 +- .../{SecretStores => SecretStore}/SecretStoreResponse.cs | 2 +- 9 files changed, 12 insertions(+), 16 deletions(-) rename src/Dapr.PluggableComponents/Components/{SecretStores => SecretStore}/ISecretStore.cs (96%) rename src/Dapr.PluggableComponents/Components/{SecretStores => SecretStore}/SecretStoreBulkGetRequest.cs (91%) rename src/Dapr.PluggableComponents/Components/{SecretStores => SecretStore}/SecretStoreBulkGetResponse.cs (96%) rename src/Dapr.PluggableComponents/Components/{SecretStores => SecretStore}/SecretStoreGetRequest.cs (96%) rename src/Dapr.PluggableComponents/Components/{SecretStores => SecretStore}/SecretStoreGetResponse.cs (96%) rename src/Dapr.PluggableComponents/Components/{SecretStores => SecretStore}/SecretStoreResponse.cs (96%) diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs index ae7b279..6435ed7 100644 --- a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -1,6 +1,5 @@ -using System; -using Dapr.PluggableComponents.Components; -using Dapr.PluggableComponents.Components.SecretStores; +using Dapr.PluggableComponents.Components; +using Dapr.PluggableComponents.Components.SecretStore; namespace LocalEnvSecretStoreSample.Services; @@ -20,7 +19,7 @@ public Task GetAsync(SecretStoreGetRequest request, Canc this.logger.LogInformation("Get request for secret {key}", request.SecretName); SecretStoreGetResponse? response = null; - string data = Environment.GetEnvironmentVariable(request.SecretName); + string? data = Environment.GetEnvironmentVariable(request.SecretName); if (data == null) { data = ""; @@ -47,7 +46,7 @@ public Task BulkGetAsync(SecretStoreBulkGetRequest r { resp = new Dictionary { - {key, Environment.GetEnvironmentVariable(key) } + {key, Environment.GetEnvironmentVariable(key) ?? String.Empty } }; secretStoreResponse = new SecretStoreResponse { diff --git a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs index 780f45a..addb11f 100644 --- a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs +++ b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs @@ -14,7 +14,7 @@ using Dapr.PluggableComponents.Adaptors; using Dapr.PluggableComponents.Components.Bindings; using Dapr.PluggableComponents.Components.PubSub; -using Dapr.PluggableComponents.Components.SecretStores; +using Dapr.PluggableComponents.Components.SecretStore; using Dapr.PluggableComponents.Components.StateStore; namespace Dapr.PluggableComponents; diff --git a/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs b/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs index c0737a0..b4ed315 100644 --- a/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs +++ b/src/Dapr.PluggableComponents/Adaptors/SecretStoreAdaptor.cs @@ -13,10 +13,8 @@ using Dapr.Client.Autogen.Grpc.v1; using Dapr.PluggableComponents.Components; -using Dapr.PluggableComponents.Components.SecretStores; -using Dapr.PluggableComponents.Utilities; +using Dapr.PluggableComponents.Components.SecretStore; using Dapr.Proto.Components.V1; -using Google.Protobuf; using Grpc.Core; using Microsoft.Extensions.Logging; using static Dapr.Proto.Components.V1.SecretStore; diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs b/src/Dapr.PluggableComponents/Components/SecretStore/ISecretStore.cs similarity index 96% rename from src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs rename to src/Dapr.PluggableComponents/Components/SecretStore/ISecretStore.cs index a1956a9..4a8ae7e 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/ISecretStore.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/ISecretStore.cs @@ -11,7 +11,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -namespace Dapr.PluggableComponents.Components.SecretStores; +namespace Dapr.PluggableComponents.Components.SecretStore; /// /// Represents a secret store Dapr Pluggable Component. diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetRequest.cs similarity index 91% rename from src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs rename to src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetRequest.cs index ceb8ed0..58cdb58 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetRequest.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetRequest.cs @@ -13,13 +13,12 @@ using Dapr.Proto.Components.V1; -namespace Dapr.PluggableComponents.Components.SecretStores; +namespace Dapr.PluggableComponents.Components.SecretStore; /// /// Represents properties associated with a request to retrieve all secrets from a secret store. /// -/// The secret that should be retrieved. public sealed record SecretStoreBulkGetRequest { /// diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs similarity index 96% rename from src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs rename to src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs index 901396b..26fc456 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs @@ -15,7 +15,7 @@ using Dapr.Proto.Components.V1; using Google.Protobuf; -namespace Dapr.PluggableComponents.Components.SecretStores; +namespace Dapr.PluggableComponents.Components.SecretStore; public sealed record SecretStoreBulkGetResponse { diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetRequest.cs similarity index 96% rename from src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs rename to src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetRequest.cs index 1155f9f..12a658d 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetRequest.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetRequest.cs @@ -13,7 +13,7 @@ using Dapr.Proto.Components.V1; -namespace Dapr.PluggableComponents.Components.SecretStores; +namespace Dapr.PluggableComponents.Components.SecretStore; /// /// Represents properties associated with a request to retrieve a secret from a secret store. diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs similarity index 96% rename from src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs rename to src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs index 1a64b97..3046147 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs @@ -15,7 +15,7 @@ using Dapr.Proto.Components.V1; using Google.Protobuf; -namespace Dapr.PluggableComponents.Components.SecretStores; +namespace Dapr.PluggableComponents.Components.SecretStore; /// /// Represents properties associated with a response to retrieving secret from a secret store. diff --git a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs similarity index 96% rename from src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreResponse.cs rename to src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs index 7b3af5c..6179b6e 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStores/SecretStoreResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs @@ -14,7 +14,7 @@ using Dapr.PluggableComponents.Utilities; using Dapr.Proto.Components.V1; using Google.Protobuf; -namespace Dapr.PluggableComponents.Components.SecretStores; +namespace Dapr.PluggableComponents.Components.SecretStore; /// /// Represents properties associated with a response to retrieving bulk secret from a secret store. From 391e8b677729a619babce791fd14faabc4894962 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Sun, 20 Oct 2024 23:00:55 -0700 Subject: [PATCH 08/13] Start adding tests. --- .../DaprPluggableComponentsServiceBuilder.cs | 2 +- .../Dapr.PluggableComponents.Protos.csproj | 2 +- .../Adaptors/AdaptorFixture.cs | 6 ++ .../Adaptors/SecretStoreAdaptorTests.cs | 81 +++++++++++++++++++ .../SecretStore/SecretStoreBulkGetResponse.cs | 27 ++++--- .../SecretStore/SecretStoreGetResponse.cs | 10 +-- .../SecretStore/SecretStoreResponse.cs | 12 +-- 7 files changed, 112 insertions(+), 28 deletions(-) create mode 100644 src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs diff --git a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs index addb11f..7e524e2 100644 --- a/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs +++ b/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceBuilder.cs @@ -204,7 +204,7 @@ public DaprPluggableComponentsServiceBuilder RegisterSecretStore() /// Registers a secret store with this service. /// /// The type of secret store to register. - /// A factory method called when creating new secret store instances. + /// A factory method called when creating new secret store instances. /// The current instance. /// /// The factory method will be called once for each configured Dapr component; the returned instance will be diff --git a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj index f8f0e39..9b68e40 100644 --- a/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj +++ b/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj @@ -2,7 +2,7 @@ v1 - master + v1.14.4 https://raw.githubusercontent.com/dapr/dapr/$(ProtosTag)/dapr/proto/components/$(ProtosVersion) $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework)\Protos $(ProtosRootDir)\dapr\proto\components\$(ProtosVersion) diff --git a/src/Dapr.PluggableComponents.Tests/Adaptors/AdaptorFixture.cs b/src/Dapr.PluggableComponents.Tests/Adaptors/AdaptorFixture.cs index aa516d8..f8bcd3b 100644 --- a/src/Dapr.PluggableComponents.Tests/Adaptors/AdaptorFixture.cs +++ b/src/Dapr.PluggableComponents.Tests/Adaptors/AdaptorFixture.cs @@ -14,6 +14,7 @@ using Dapr.PluggableComponents.Components; using Dapr.PluggableComponents.Components.Bindings; using Dapr.PluggableComponents.Components.PubSub; +using Dapr.PluggableComponents.Components.SecretStore; using Dapr.PluggableComponents.Components.StateStore; using Grpc.Core; using Microsoft.Extensions.Logging; @@ -75,6 +76,11 @@ public static AdaptorFixture CreateStateStore(IS return new AdaptorFixture((logger, componentProvider) => new StateStoreAdaptor(logger, componentProvider), mockComponent); } + public static AdaptorFixture CreateSecretStore(ISecretStore? mockComponent = null) + { + return new AdaptorFixture((logger, componentProvider) => new SecretStoreAdaptor(logger, componentProvider), mockComponent); + } + public static async Task TestInitAsync( Func> adaptorFactory, Func, Client.Autogen.Grpc.v1.MetadataRequest, Task> initCall) diff --git a/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs new file mode 100644 index 0000000..527bc78 --- /dev/null +++ b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs @@ -0,0 +1,81 @@ +// ------------------------------------------------------------------------ +// Copyright 2023 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using Dapr.Client.Autogen.Grpc.v1; +using Dapr.PluggableComponents.Adaptors; +using Dapr.PluggableComponents.Components.SecretStore; +using NSubstitute; +using Xunit; + +namespace Dapr.PluggableComponents.Tests.Adaptors; + +public sealed class SecretStoreAdaptorTests +{ + [Fact] + public Task InitTests() + { + return AdaptorFixture.TestInitAsync( + () => AdaptorFixture.CreateSecretStore(), + (fixture, metadataRequest) => fixture.Adaptor.Init(new Proto.Components.V1.SecretStoreInitRequest { Metadata = metadataRequest }, fixture.Context)); + } + + [Fact] + public Task PingTests() + { + return AdaptorFixture.TestPingAsync( + AdaptorFixture.CreateSecretStore, + fixture => fixture.Adaptor.Ping(new PingRequest(), fixture.Context)); + } + + [Fact] + public async Task GetSecret() + { + using var fixture = AdaptorFixture.CreateSecretStore(Substitute.For()); + + string key1 = "key1"; + string key2 = "key2"; + + string value1 = "value1"; + string value2 = "value2"; + + fixture.MockComponent + .GetAsync(Arg.Any(), Arg.Any()) + .Returns( + new SecretStoreGetResponse + { + Secrets = new Dictionary + { + { key1, value1 }, + { key2, value2 } + } + }); + + var getRequest = new Proto.Components.V1.GetSecretRequest(); + + getRequest.Key = key1; + + var response = await fixture.Adaptor.Get( + getRequest, + fixture.Context); + + Assert.Contains(response.Data, item => item.Key == key1 && item.Value == value1); + Assert.Contains(response.Data, item => item.Key == key2 && item.Value == value2); + + await fixture + .MockComponent + .Received(1) + .GetAsync(Arg.Is( + requests => requests.SecretName == key1), + Arg.Is(cancellationToken => cancellationToken == fixture.Context.CancellationToken)); + } +} diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs index 26fc456..6f6c377 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs @@ -17,25 +17,32 @@ namespace Dapr.PluggableComponents.Components.SecretStore; +/// +/// Represents properties associated with a response to retrieving all secrets from a secret store. +/// public sealed record SecretStoreBulkGetResponse { - public IReadOnlyDictionary Data { get; init; } = new Dictionary(); + /// + /// Gets the groups of secrets. + /// + public IReadOnlyDictionary Groups { get; init; } = new Dictionary(); internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse response) { - var grpcResponse = new BulkGetSecretResponse(); - if (response != null) + BulkGetSecretResponse grpcResponse = new(); + + foreach (var item in response.Groups) { - foreach (var item in response.Data) + SecretResponse secretResp = new(); + + foreach (var sec in item.Value.Data) { - var secretResp = new SecretResponse(); - foreach (var sec in item.Value.Data) - { - secretResp.Secrets.Add(sec.Key, sec.Value); - grpcResponse.Data.Add(sec.Key, secretResp); - } + secretResp.Secrets.Add(sec.Key, sec.Value); } + + grpcResponse.Data.Add(item.Key, secretResp); } + return grpcResponse; } } diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs index 3046147..dbcb509 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs @@ -23,13 +23,9 @@ namespace Dapr.PluggableComponents.Components.SecretStore; public sealed record SecretStoreGetResponse { /// - /// Gets or sets the key's value. + /// Gets the secrets. /// - /// - /// If omitted, defaults to an empty array. - /// - public IReadOnlyDictionary Data { get; init; } = new Dictionary(); - + public IReadOnlyDictionary Secrets { get; init; } = new Dictionary(); internal static GetSecretResponse ToGetResponse(SecretStoreGetResponse response) { @@ -39,7 +35,7 @@ internal static GetSecretResponse ToGetResponse(SecretStoreGetResponse response) if (response != null) { - grpcResponse.Data.Add(response.Data); + grpcResponse.Data.Add(response.Secrets); } return grpcResponse; diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs index 6179b6e..b579d11 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs @@ -14,6 +14,7 @@ using Dapr.PluggableComponents.Utilities; using Dapr.Proto.Components.V1; using Google.Protobuf; + namespace Dapr.PluggableComponents.Components.SecretStore; /// @@ -24,22 +25,15 @@ public sealed record SecretStoreResponse /// /// Gets or sets the key's value. /// - /// - /// If omitted, defaults to an empty array. - /// public IReadOnlyDictionary Data { get; init; } = new Dictionary(); - - + internal static SecretResponse ToGetResponse(SecretStoreResponse response) { var grpcResponse = new SecretResponse(); // NOTE: in case of not found, you should not return any error. - if (response != null) - { - grpcResponse.Secrets.Add(response.Data); - } + grpcResponse.Secrets.Add(response.Data); return grpcResponse; } From 8be32417df0a58c476cada2331b5870f2151bd3c Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Mon, 21 Oct 2024 23:42:43 -0700 Subject: [PATCH 09/13] Add bulk get test. --- .../Adaptors/SecretStoreAdaptorTests.cs | 60 ++++++++++++++++++- .../SecretStore/SecretStoreBulkGetResponse.cs | 6 +- .../SecretStore/SecretStoreGetRequest.cs | 4 +- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs index 527bc78..45b9c8b 100644 --- a/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs +++ b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs @@ -42,6 +42,8 @@ public async Task GetSecret() { using var fixture = AdaptorFixture.CreateSecretStore(Substitute.For()); + string key = "key"; + string key1 = "key1"; string key2 = "key2"; @@ -62,7 +64,7 @@ public async Task GetSecret() var getRequest = new Proto.Components.V1.GetSecretRequest(); - getRequest.Key = key1; + getRequest.Key = key; var response = await fixture.Adaptor.Get( getRequest, @@ -75,7 +77,61 @@ await fixture .MockComponent .Received(1) .GetAsync(Arg.Is( - requests => requests.SecretName == key1), + requests => requests.Key == key), + Arg.Is(cancellationToken => cancellationToken == fixture.Context.CancellationToken)); + } + + [Fact] + public async Task GetBulkSecrets() + { + using var fixture = AdaptorFixture.CreateSecretStore(Substitute.For()); + + string key = "key"; + + string key1 = "key1"; + string key2 = "key2"; + + string value1 = "value1"; + string value2 = "value2"; + + fixture.MockComponent + .BulkGetAsync(Arg.Any(), Arg.Any()) + .Returns( + new SecretStoreBulkGetResponse + { + Keys = new Dictionary + { + { + key, + new SecretStoreResponse + { + Data = new Dictionary + { + { key1, value1 }, + { key2, value2 } + } + } + } + } + }); + + var getRequest = new Proto.Components.V1.BulkGetSecretRequest(); + + var response = await fixture.Adaptor.BulkGet( + getRequest, + fixture.Context); + + Assert.Contains(response.Data, item => item.Key == key); + + var secretResponse = response.Data[key]; + + Assert.Contains(secretResponse.Secrets, item => item.Key == key1 && item.Value == value1); + Assert.Contains(secretResponse.Secrets, item => item.Key == key2 && item.Value == value2); + + await fixture + .MockComponent + .Received(1) + .BulkGetAsync(Arg.Any(), Arg.Is(cancellationToken => cancellationToken == fixture.Context.CancellationToken)); } } diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs index 6f6c377..d4823a5 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs @@ -11,9 +11,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -using Dapr.PluggableComponents.Utilities; using Dapr.Proto.Components.V1; -using Google.Protobuf; namespace Dapr.PluggableComponents.Components.SecretStore; @@ -25,13 +23,13 @@ public sealed record SecretStoreBulkGetResponse /// /// Gets the groups of secrets. /// - public IReadOnlyDictionary Groups { get; init; } = new Dictionary(); + public IReadOnlyDictionary Keys { get; init; } = new Dictionary(); internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse response) { BulkGetSecretResponse grpcResponse = new(); - foreach (var item in response.Groups) + foreach (var item in response.Keys) { SecretResponse secretResp = new(); diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetRequest.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetRequest.cs index 12a658d..f73d94a 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetRequest.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetRequest.cs @@ -18,8 +18,8 @@ namespace Dapr.PluggableComponents.Components.SecretStore; /// /// Represents properties associated with a request to retrieve a secret from a secret store. /// -/// The secret that should be retrieved. -public sealed record SecretStoreGetRequest(string SecretName) +/// The key for the secrets that should be retrieved. +public sealed record SecretStoreGetRequest(string Key) { /// /// Gets the metadata associated with the request. From 007b653f43687b31df26bb30b5215b13ba382774 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 22 Oct 2024 00:00:41 -0700 Subject: [PATCH 10/13] Fixup linter, build errors. Signed-off-by: Phillip Hoff --- .../Services/LocalEnvSecretStore.cs | 10 +++++----- .../Adaptors/SecretStoreAdaptorTests.cs | 8 ++++---- .../SecretStore/SecretStoreBulkGetResponse.cs | 3 +-- .../Components/SecretStore/SecretStoreResponse.cs | 3 +-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs index 6435ed7..72f791a 100644 --- a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -16,19 +16,19 @@ public LocalEnvSecretStore(ILogger logger) public Task GetAsync(SecretStoreGetRequest request, CancellationToken cancellationToken = default) { - this.logger.LogInformation("Get request for secret {key}", request.SecretName); + this.logger.LogInformation("Get request for secret {key}", request.Key); SecretStoreGetResponse? response = null; - string? data = Environment.GetEnvironmentVariable(request.SecretName); + string? data = Environment.GetEnvironmentVariable(request.Key); if (data == null) { data = ""; } Dictionary resp = new Dictionary(); - resp.Add(request.SecretName, data); + resp.Add(request.Key, data); response = new SecretStoreGetResponse { - Data = resp + Secrets = resp }; return Task.FromResult(response); @@ -56,7 +56,7 @@ public Task BulkGetAsync(SecretStoreBulkGetRequest r } response = new SecretStoreBulkGetResponse { - Data = bulkResp + Keys = bulkResp }; return Task.FromResult(response); } diff --git a/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs index 45b9c8b..9bc1d31 100644 --- a/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs +++ b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs @@ -43,7 +43,7 @@ public async Task GetSecret() using var fixture = AdaptorFixture.CreateSecretStore(Substitute.For()); string key = "key"; - + string key1 = "key1"; string key2 = "key2"; @@ -87,7 +87,7 @@ public async Task GetBulkSecrets() using var fixture = AdaptorFixture.CreateSecretStore(Substitute.For()); string key = "key"; - + string key1 = "key1"; string key2 = "key2"; @@ -122,9 +122,9 @@ public async Task GetBulkSecrets() fixture.Context); Assert.Contains(response.Data, item => item.Key == key); - + var secretResponse = response.Data[key]; - + Assert.Contains(secretResponse.Secrets, item => item.Key == key1 && item.Value == value1); Assert.Contains(secretResponse.Secrets, item => item.Key == key2 && item.Value == value2); diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs index d4823a5..9ed8aba 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs @@ -40,9 +40,8 @@ internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetRespon grpcResponse.Data.Add(item.Key, secretResp); } - + return grpcResponse; } } - diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs index b579d11..7311ddc 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs @@ -26,7 +26,7 @@ public sealed record SecretStoreResponse /// Gets or sets the key's value. /// public IReadOnlyDictionary Data { get; init; } = new Dictionary(); - + internal static SecretResponse ToGetResponse(SecretStoreResponse response) { var grpcResponse = new SecretResponse(); @@ -38,4 +38,3 @@ internal static SecretResponse ToGetResponse(SecretStoreResponse response) return grpcResponse; } } - From 84eb2c20e809cd5266d665b96d2fc978cf6ece85 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 22 Oct 2024 00:04:38 -0700 Subject: [PATCH 11/13] Make linter happy (happier?). Signed-off-by: Phillip Hoff --- samples/LocalEnvSecretStoreSample/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/LocalEnvSecretStoreSample/Program.cs b/samples/LocalEnvSecretStoreSample/Program.cs index 549f66d..931645d 100644 --- a/samples/LocalEnvSecretStoreSample/Program.cs +++ b/samples/LocalEnvSecretStoreSample/Program.cs @@ -1,4 +1,4 @@ -using Dapr.PluggableComponents; +using Dapr.PluggableComponents; using LocalEnvSecretStoreSample.Services; var app = DaprPluggableComponentsApplication.Create(); @@ -15,4 +15,4 @@ }); }); -app.Run(); \ No newline at end of file +app.Run(); From 2047feca7d0f9de02731139743cb866974cfb2d6 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Thu, 24 Oct 2024 23:12:42 -0700 Subject: [PATCH 12/13] Updates per PR feedback. Signed-off-by: Phillip Hoff --- .../Services/LocalEnvSecretStore.cs | 72 ++++++++++--------- .../Adaptors/SecretStoreAdaptorTests.cs | 6 +- .../SecretStore/SecretStoreBulkGetResponse.cs | 4 +- .../SecretStore/SecretStoreGetResponse.cs | 1 - .../SecretStore/SecretStoreResponse.cs | 40 ----------- 5 files changed, 43 insertions(+), 80 deletions(-) delete mode 100644 src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs index 72f791a..f73e3fc 100644 --- a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -1,5 +1,6 @@ using Dapr.PluggableComponents.Components; using Dapr.PluggableComponents.Components.SecretStore; +using System.Collections; namespace LocalEnvSecretStoreSample.Services; @@ -18,47 +19,37 @@ public Task GetAsync(SecretStoreGetRequest request, Canc { this.logger.LogInformation("Get request for secret {key}", request.Key); - SecretStoreGetResponse? response = null; - string? data = Environment.GetEnvironmentVariable(request.Key); - if (data == null) - { - data = ""; - } - Dictionary resp = new Dictionary(); - resp.Add(request.Key, data); - response = new SecretStoreGetResponse - { - Secrets = resp - }; - - return Task.FromResult(response); + return Task.FromResult( + new SecretStoreGetResponse + { + Secrets = new Dictionary + { + { request.Key, Environment.GetEnvironmentVariable(request.Key) ?? String.Empty } + } + }); } public Task BulkGetAsync(SecretStoreBulkGetRequest request, CancellationToken cancellationToken = default) { this.logger.LogInformation("Get request for all secrets"); - SecretStoreBulkGetResponse? response = null; - SecretStoreResponse? secretStoreResponse = null; - Dictionary? resp = null; - Dictionary bulkResp = new Dictionary(); - foreach (string key in Environment.GetEnvironmentVariables().Keys) - { - resp = new Dictionary + return Task.FromResult( + new SecretStoreBulkGetResponse { - {key, Environment.GetEnvironmentVariable(key) ?? String.Empty } - }; - secretStoreResponse = new SecretStoreResponse - { - Data = resp - }; - bulkResp.Add(key, secretStoreResponse); - } - response = new SecretStoreBulkGetResponse - { - Keys = bulkResp - }; - return Task.FromResult(response); + Keys = + Environment + .GetEnvironmentVariables() + .ToDictionary() + .ToDictionary( + kvp => kvp.Key, + kvp => new SecretStoreGetResponse + { + Secrets = new Dictionary + { + { kvp.Key, kvp.Value ?? String.Empty } + } + }) + }); } public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) @@ -68,3 +59,16 @@ public Task InitAsync(MetadataRequest request, CancellationToken cancellationTok #endregion } + +internal static class DictionaryExtensions +{ + public static IEnumerable> ToDictionary(this IDictionary dictionary) + { + var enumerator = dictionary.GetEnumerator(); + + while (enumerator.MoveNext()) + { + yield return new KeyValuePair((TKey)enumerator.Key, (TValue?)enumerator.Value); + } + } +} \ No newline at end of file diff --git a/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs index 9bc1d31..34360d1 100644 --- a/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs +++ b/src/Dapr.PluggableComponents.Tests/Adaptors/SecretStoreAdaptorTests.cs @@ -99,13 +99,13 @@ public async Task GetBulkSecrets() .Returns( new SecretStoreBulkGetResponse { - Keys = new Dictionary + Keys = new Dictionary { { key, - new SecretStoreResponse + new SecretStoreGetResponse { - Data = new Dictionary + Secrets = new Dictionary { { key1, value1 }, { key2, value2 } diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs index 9ed8aba..af3dd89 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreBulkGetResponse.cs @@ -23,7 +23,7 @@ public sealed record SecretStoreBulkGetResponse /// /// Gets the groups of secrets. /// - public IReadOnlyDictionary Keys { get; init; } = new Dictionary(); + public IReadOnlyDictionary Keys { get; init; } = new Dictionary(); internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetResponse response) { @@ -33,7 +33,7 @@ internal static BulkGetSecretResponse ToBulkGetResponse(SecretStoreBulkGetRespon { SecretResponse secretResp = new(); - foreach (var sec in item.Value.Data) + foreach (var sec in item.Value.Secrets) { secretResp.Secrets.Add(sec.Key, sec.Value); } diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs index dbcb509..adad4f4 100644 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs +++ b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreGetResponse.cs @@ -13,7 +13,6 @@ using Dapr.PluggableComponents.Utilities; using Dapr.Proto.Components.V1; -using Google.Protobuf; namespace Dapr.PluggableComponents.Components.SecretStore; diff --git a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs b/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs deleted file mode 100644 index 7311ddc..0000000 --- a/src/Dapr.PluggableComponents/Components/SecretStore/SecretStoreResponse.cs +++ /dev/null @@ -1,40 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2023 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using Dapr.PluggableComponents.Utilities; -using Dapr.Proto.Components.V1; -using Google.Protobuf; - -namespace Dapr.PluggableComponents.Components.SecretStore; - -/// -/// Represents properties associated with a response to retrieving bulk secret from a secret store. -/// -public sealed record SecretStoreResponse -{ - /// - /// Gets or sets the key's value. - /// - public IReadOnlyDictionary Data { get; init; } = new Dictionary(); - - internal static SecretResponse ToGetResponse(SecretStoreResponse response) - { - var grpcResponse = new SecretResponse(); - - // NOTE: in case of not found, you should not return any error. - - grpcResponse.Secrets.Add(response.Data); - - return grpcResponse; - } -} From 9d197a185b3d1f8535bfc60f470f164c96aab7c4 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Fri, 25 Oct 2024 09:28:52 -0700 Subject: [PATCH 13/13] Satisfy linter. Signed-off-by: Phillip Hoff --- .../Services/LocalEnvSecretStore.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs index f73e3fc..eba5788 100644 --- a/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs +++ b/samples/LocalEnvSecretStoreSample/Services/LocalEnvSecretStore.cs @@ -1,6 +1,6 @@ -using Dapr.PluggableComponents.Components; +using System.Collections; +using Dapr.PluggableComponents.Components; using Dapr.PluggableComponents.Components.SecretStore; -using System.Collections; namespace LocalEnvSecretStoreSample.Services; @@ -71,4 +71,4 @@ internal static class DictionaryExtensions yield return new KeyValuePair((TKey)enumerator.Key, (TValue?)enumerator.Value); } } -} \ No newline at end of file +}