feat: add azure app configuration module#1200
feat: add azure app configuration module#1200tnc1997 wants to merge 3 commits intotestcontainers:developfrom
Conversation
✅ Deploy Preview for testcontainers-dotnet ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
...Testcontainers.AzureAppConfiguration.Tests/Testcontainers.AzureAppConfiguration.Tests.csproj
Outdated
Show resolved
Hide resolved
|
@tnc1997's container not support TLS and his module uses the insecure port of that container. As had been previously discussed,
The Azure SDK (and specifically The official CosmosDB emulator offers an endpoint for fetching the PEM certificate to make this requirement a little easier to deal with, however there are more issues in play such as the app config domain and scope/identity requirements which had also been discussed extensively. I worked very hard to [address these issues in my Testcontainers module](https://github.com/goldsam/azure-app-configuration-emulator/blob/9adc28f418b7ae9030c90f859f77fa137aa46311/src/AzureAppConfigurationEmulator.Test containers/AzureAppConfigurationEmulatorBuilder.cs#L71-L91), and was quite disappointed that you discarded that work. @tnc1997 I had spent a LOT of time contributing to your project throughout our discussions addressing these matters, so this feels like a bit of a slap in the face. |
Hi @goldsam, I appreciate your concerns. Firstly, the Azure SDK does not enforce TLS everywhere, for example the storage clients to name a few:
Secondly, a test has been added that shows that the Connecting to the emulator using HMAC authentication is the recommended approach, hence the .crt & .key var container = new AzureAppConfigurationBuilder()
.WithEnvironment("ASPNETCORE_HTTP_PORTS", "8080")
.WithEnvironment("ASPNETCORE_HTTPS_PORTS", "8081")
.WithEnvironment("Kestrel__Certificates__Default__Path", "/usr/local/share/azureappconfigurationemulator/emulator.crt")
.WithEnvironment("Kestrel__Certificates__Default__KeyPath", "/usr/local/share/azureappconfigurationemulator/emulator.key")
.WithResourceMapping("emulator.crt", "/usr/local/share/azureappconfigurationemulator/emulator.crt")
.WithResourceMapping("emulator.key", "/usr/local/share/azureappconfigurationemulator/emulator.key")
.Build();.pfx var container = new AzureAppConfigurationBuilder()
.WithEnvironment("ASPNETCORE_HTTP_PORTS", "8080")
.WithEnvironment("ASPNETCORE_HTTPS_PORTS", "8081")
.WithEnvironment("Kestrel__Certificates__Default__Password", "password")
.WithEnvironment("Kestrel__Certificates__Default__Path", "/root/.aspnet/https/aspnetapp.pfx")
.WithResourceMapping("aspnetapp.pfx", "/root/.aspnet/https/aspnetapp.pfx")
.Build(); |
4900ecd to
8fa5f1b
Compare
|
@NelsonBN |
|
Sorry, I'm having a bit of trouble following. I'm not familiar with these implementations, and it looks like Microsoft provides an Azure App Configuration Emulator. Is there any comparison of the features available? Of course, relying on an image that's maintained by the vendor and behaves like the production version is definitely what we're aiming for. I'm not saying one implementation is better than the other. |
|
This Pull Request was opened some time ago and since then Microsoft has released an official emulator for Azure App Configuration although it is currently missing some of the features that are available in the unofficial emulator. |
|
For reference the Microsoft implementation is "focusing on independent, open source, system agnostic configuration solution, suited for self-hosting and platform-agnostic environments, rather than a local (trimmed down) alternative of the Azure App Configuration Service. With that in mind, we looked at proprietary hosting/infra features like Microsoft Entra ID, Azure RBAC, Azure Private Endpoint, Azure Network Security, Customer Managed Keys, Geo-Replication, Copilot, etc. These either require Azure subscription, Azure dependency or entirely not feasible". The unofficial emulator aims to be a substitute for Azure App Configuration in local environments as opposed to a standalone configuration solution. |
# Conflicts: # Testcontainers.sln
✅ Deploy Preview for testcontainers-dotnet ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
WalkthroughThis PR introduces a new Testcontainers module for Azure App Configuration emulator. It adds builder, configuration, and container classes to integrate the emulator into test containers, along with project references, NuGet dependencies (Azure.Data.AppConfiguration v1.4.1), and integration tests demonstrating container functionality. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs (2)
26-26: Document HTTP-only endpoint limitation and extensibility.The container uses an HTTP-only endpoint by default. While your PR discussion notes that the emulator doesn't support TLS out-of-the-box and provides examples for configuring TLS via environment variables, consider adding XML documentation or inline comments to:
- Note that the default endpoint uses HTTP
- Reference how users can configure TLS (via
WithEnvironmentfor certificate paths)- Clarify that this aligns with the emulator's design (HMAC auth over HTTP is supported)
This would help users understand the security posture and customization options without needing to dig through PR comments.
23-30: Simplify with collection initializer syntax.The connection string format is correct for Azure App Configuration HMAC authentication. However, consider using collection initializer syntax to improve readability:
public string GetConnectionString() { - var properties = new Dictionary<string, string>(); - properties.Add("Endpoint", new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(AzureAppConfigurationBuilder.AzureAppConfigurationPort)).ToString()); - properties.Add("Id", _configuration.Credential); - properties.Add("Secret", _configuration.Secret); + var properties = new Dictionary<string, string> + { + ["Endpoint"] = new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(AzureAppConfigurationBuilder.AzureAppConfigurationPort)).ToString(), + ["Id"] = _configuration.Credential, + ["Secret"] = _configuration.Secret + }; return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value))); }src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs (1)
7-13: Consider documenting the image choice and version pinning.The PR discussion mentions trade-offs between this unofficial emulator and Microsoft's official one. Consider adding a brief XML doc comment on
AzureAppConfigurationImageexplaining:
- Why this specific emulator was chosen (more feature-complete per PR discussion)
- That version
1.0is pinned intentionallyThis helps future maintainers understand the decision context.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
Directory.Packages.propsTestcontainers.slnsrc/Testcontainers.AzureAppConfiguration/.editorconfigsrc/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cssrc/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cssrc/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cssrc/Testcontainers.AzureAppConfiguration/Testcontainers.AzureAppConfiguration.csprojsrc/Testcontainers.AzureAppConfiguration/Usings.cstests/Testcontainers.AzureAppConfiguration.Tests/.editorconfigtests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cstests/Testcontainers.AzureAppConfiguration.Tests/Testcontainers.AzureAppConfiguration.Tests.csprojtests/Testcontainers.AzureAppConfiguration.Tests/Usings.cs
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-17T17:58:43.958Z
Learnt from: diegosasw
Repo: testcontainers/testcontainers-dotnet PR: 1583
File: src/Testcontainers.KurrentDb/Testcontainers.KurrentDb.csproj:7-7
Timestamp: 2025-11-17T17:58:43.958Z
Learning: In the testcontainers-dotnet repository, JetBrains.Annotations should use version 2023.3.0 to maintain consistency with the main Testcontainers csproj, rather than always using the latest available version.
Applied to files:
src/Testcontainers.AzureAppConfiguration/Testcontainers.AzureAppConfiguration.csprojsrc/Testcontainers.AzureAppConfiguration/Usings.cstests/Testcontainers.AzureAppConfiguration.Tests/.editorconfigtests/Testcontainers.AzureAppConfiguration.Tests/Usings.cstests/Testcontainers.AzureAppConfiguration.Tests/Testcontainers.AzureAppConfiguration.Tests.csprojTestcontainers.slntests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cs
📚 Learning: 2025-11-08T09:04:00.045Z
Learnt from: HofmeisterAn
Repo: testcontainers/testcontainers-dotnet PR: 1509
File: tests/Testcontainers.Grafana.Tests/GrafanaContainerTest.cs:45-46
Timestamp: 2025-11-08T09:04:00.045Z
Learning: In xUnit.net test methods in the testcontainers-dotnet project, ConfigureAwait(true) is recommended and correct to use, as it ensures proper synchronization context capture for xUnit's test parallelism management. Do not suggest changing ConfigureAwait(true) to ConfigureAwait(false) in test methods.
Applied to files:
tests/Testcontainers.AzureAppConfiguration.Tests/Usings.cstests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cs
🧬 Code graph analysis (4)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs (2)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cs (6)
PublicAPI(4-69)AzureAppConfigurationConfiguration(12-16)AzureAppConfigurationConfiguration(22-26)AzureAppConfigurationConfiguration(32-36)AzureAppConfigurationConfiguration(42-46)AzureAppConfigurationConfiguration(53-58)src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs (2)
PublicAPI(4-31)AzureAppConfigurationContainer(13-17)
tests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cs (2)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs (9)
AzureAppConfigurationContainer(60-64)AzureAppConfigurationBuilder(18-22)AzureAppConfigurationBuilder(28-32)AzureAppConfigurationBuilder(42-46)AzureAppConfigurationBuilder(53-57)AzureAppConfigurationBuilder(67-75)AzureAppConfigurationBuilder(92-95)AzureAppConfigurationBuilder(98-101)AzureAppConfigurationBuilder(104-107)src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs (2)
AzureAppConfigurationContainer(13-17)GetConnectionString(23-30)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs (2)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs (10)
PublicAPI(4-108)AzureAppConfigurationContainer(60-64)AzureAppConfigurationBuilder(18-22)AzureAppConfigurationBuilder(28-32)AzureAppConfigurationBuilder(42-46)AzureAppConfigurationBuilder(53-57)AzureAppConfigurationBuilder(67-75)AzureAppConfigurationBuilder(92-95)AzureAppConfigurationBuilder(98-101)AzureAppConfigurationBuilder(104-107)src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cs (6)
PublicAPI(4-69)AzureAppConfigurationConfiguration(12-16)AzureAppConfigurationConfiguration(22-26)AzureAppConfigurationConfiguration(32-36)AzureAppConfigurationConfiguration(42-46)AzureAppConfigurationConfiguration(53-58)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cs (3)
src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs (1)
PublicAPI(4-108)src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs (1)
PublicAPI(4-31)src/Testcontainers/Builders/BuildConfiguration.cs (1)
BuildConfiguration(13-190)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: analyze (csharp)
🔇 Additional comments (17)
src/Testcontainers.AzureAppConfiguration/.editorconfig (1)
1-1: Standard EditorConfig root marker is appropriate.The
root = truedirective correctly marks this as the root EditorConfig file for the new module directory, ensuring editor conventions are scoped appropriately.tests/Testcontainers.AzureAppConfiguration.Tests/.editorconfig (1)
1-1: LGTM!Standard EditorConfig root marker.
src/Testcontainers.AzureAppConfiguration/Testcontainers.AzureAppConfiguration.csproj (1)
1-12: LGTM!Project configuration follows the repository conventions, including the correct JetBrains.Annotations version (2023.3.0) per repository standards.
tests/Testcontainers.AzureAppConfiguration.Tests/Usings.cs (1)
1-4: LGTM!Global usings are appropriate for the test project scope.
src/Testcontainers.AzureAppConfiguration/Usings.cs (1)
1-9: LGTM!Global usings are appropriate for a Testcontainers module implementation.
Testcontainers.sln (1)
27-28: LGTM!Solution file correctly wires the new Azure App Configuration module and test projects with proper build configurations and nesting.
Also applies to: 151-152, 813-820, 957-958
Directory.Packages.props (1)
40-40: Update Azure.Data.AppConfiguration to version 1.7.0.Version 1.4.1 is outdated. The latest available version is 1.7.0, with intermediate releases 1.5.0, 1.6.0, and 1.6.1 also available. Other Azure packages in this file (Identity 1.13.2, EventHubs 5.11.3, ServiceBus 7.20.1) are significantly newer, creating inconsistency in dependency versions.
⛔ Skipped due to learnings
Learnt from: diegosasw Repo: testcontainers/testcontainers-dotnet PR: 1583 File: src/Testcontainers.KurrentDb/Testcontainers.KurrentDb.csproj:7-7 Timestamp: 2025-11-17T17:58:43.958Z Learning: In the testcontainers-dotnet repository, JetBrains.Annotations should use version 2023.3.0 to maintain consistency with the main Testcontainers csproj, rather than always using the latest available version.tests/Testcontainers.AzureAppConfiguration.Tests/Testcontainers.AzureAppConfiguration.Tests.csproj (1)
3-3: Update target framework to match other test projects.This test project targets
net8.0while all other test projects in the repository targetnet10.0. Change<TargetFrameworks>net8.0</TargetFrameworks>to<TargetFramework>net10.0</TargetFramework>for consistency.⛔ Skipped due to learnings
Learnt from: diegosasw Repo: testcontainers/testcontainers-dotnet PR: 1583 File: src/Testcontainers.KurrentDb/Testcontainers.KurrentDb.csproj:7-7 Timestamp: 2025-11-17T17:58:43.958Z Learning: In the testcontainers-dotnet repository, JetBrains.Annotations should use version 2023.3.0 to maintain consistency with the main Testcontainers csproj, rather than always using the latest available version.tests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cs (1)
1-34: LGTM! Well-structured integration test.The test follows the established patterns in this repository:
- Proper
IAsyncLifetimeimplementation for container lifecycle- Correct use of
ConfigureAwait(true)for xUnit test methods (per repository conventions)- Clear AAA (Arrange-Act-Assert) structure
- Linux platform trait appropriately applied
The test effectively validates that the
ConfigurationClientcan interact with the emulator container via HMAC authentication.src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs (4)
42-57: LGTM! Proper fluent configuration with dual state management.The methods correctly:
- Merge into the configuration object (for
GetConnectionString()usage)- Set container environment variables (for emulator HMAC authentication)
The double-underscore notation (
Authentication__Schemes__Hmac__*) correctly maps to ASP.NET Core's hierarchical configuration binding.
78-89: LGTM! Proper validation guards.The validation correctly ensures both
CredentialandSecretare provided before building the container, preventing cryptic runtime failures.
92-107: LGTM! Standard builder pattern implementation.The
CloneandMergeoverrides correctly implement the immutable builder pattern consistent with other modules in this repository.
67-75: Wait strategy log message is correct.The
"Now listening on"message is the standard Kestrel startup output for ASP.NET Core applications and is confirmed to work with the emulator image. The test suite successfully starts the container with this configuration, validating the wait strategy.src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cs (4)
1-16: LGTM! Well-structured configuration class.The primary constructor with optional parameters enables flexible initialization while supporting the immutable configuration pattern used throughout this repository.
18-36: LGTM! Required constructors for builder pattern.These constructors support the
Clonemethods inAzureAppConfigurationBuilderand correctly delegate Docker resource configuration to the base class.
48-58: LGTM! Correct merge semantics.The merge constructor properly uses
BuildConfiguration.Combineto implement the "newer value wins" pattern, which is consistent with how other configuration classes in this repository handle immutable updates.
60-68: LGTM!Immutable properties with appropriate documentation.
|
Came here looking for a module to support AppConfig myself. +1 for the interest and need. fwiw, while I can appreciate a pre-existing emulator attempt from a 3rd party, I'd have to say I fall in the same camp of simply having a bias and preference for an emulator that is being provided by the actual resource/product development team themselves. For better or for worse feature comparison wise I would expect (or more hope) the product team would achieve feature parity -and- keep it in sync and maintain it. Like in my case we're now using the service bus emulator from MS. |
What does this PR do?
This change adds an Azure App Configuration module using Emulator for Azure App Configuration.
Why is it important?
This module allows developers to more easily integration test applications that are dependent on Azure App Configuration.
Related issues
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.