Skip to content

feat(sdk-dotnet): add static Envilder facade with sync and async API#167

Merged
macalbert merged 35 commits intomainfrom
macalbert/feat/dotnet-sdk-facade
Apr 19, 2026
Merged

feat(sdk-dotnet): add static Envilder facade with sync and async API#167
macalbert merged 35 commits intomainfrom
macalbert/feat/dotnet-sdk-facade

Conversation

@macalbert
Copy link
Copy Markdown
Owner

@macalbert macalbert commented Apr 18, 2026

Summary

Adds a static Envilder facade to the .NET SDK providing one-liner and fluent APIs for resolving and injecting secrets, along with synchronous GetSecret/ResolveSecrets paths. Also encapsulates internal factory classes across both .NET and Python SDKs, aligns documentation, and improves cross-provider validation.

Changes

.NET SDK — Facade & Sync API

  • Static Envilder class with Load, ResolveFile, LoadAsync, ResolveFileAsync
  • Environment-based routing overloads (Load(env, mapping), ResolveFile(env, mapping))
  • FromMapFile(path) fluent builder → EnvilderBuilder with WithProvider, WithProfile, WithVaultUrlResolve/Inject/ResolveAsync/InjectAsync
  • ISecretProvider.GetSecret(name) — new sync interface method
  • AwsSsmSecretProvider.GetSecret (sync via Task.Run) and AzureKeyVaultSecretProvider.GetSecret (native sync)
  • EnvilderClient.ResolveSecrets(mapFile) — sync secret resolution
  • SecretValidationExtensions.ValidateSecrets() — opt-in validation
  • SecretProviderFactory made internal; AddEnvilder extensions simplified to (path, options?)
  • Cross-provider validation (profile+Azure → error, vaultUrl+AWS → error)
  • EnvilderConfigurationProvider.Load() uses sync ResolveSecrets instead of sync-over-async

Python SDK — Encapsulation

  • SecretProviderFactory renamed to _SecretProviderFactory (private by convention)
  • Removed from public __all__ re-exports
  • Cross-provider validation added

AWS Region Resolution (both SDKs)

  • No-profile path delegates to native SDK default chain (no manual us-east-1 fallback)
  • Profile path respects AWS_SHARED_CREDENTIALS_FILE env var

Documentation & Examples

  • .NET SDK README with full API reference, examples, and IConfiguration/DI integration
  • Python SDK README aligned with current API
  • Website .NET code snippet fixed with correct using namespaces
  • .NET examples updated to Envilder@0.2.* package reference
  • SDK changelogs aligned with manifest versions (0.2.0 / 0.3.2)
  • copilot-instructions updated for _SecretProviderFactory and facade API

Infrastructure

  • Central NuGet package management (Directory.Packages.props)
  • xUnit v3 migration with AwesomeAssertions
  • .editorconfig with tabs/LF enforcement
  • netstandard2.0 target framework

Testing

  • 46 .NET unit tests (facade, builder, validation, env routing, sync paths, configuration provider)
  • 11 E2E acceptance tests (LocalStack + Lowkey Vault) covering all public facade methods
  • 56 Python unit tests
  • Acceptance tests for both SDKs (LocalStack for AWS, Lowkey Vault for Azure)

Checklist

  • dotnet build — 0 errors, 0 warnings
  • dotnet test (unit) — 46 passed
  • dotnet format --verify-no-changes — pass
  • black --check + isort --check + mypy --strict — pass
  • Website builds (9 pages)
  • Pre-commit hooks pass (biome, python-format-check, dotnet-format)

Summary by CodeRabbit

  • New Features

    • Added static Envilder facade to .NET SDK with one-liner methods (Load, ResolveFile) for simplified secret resolution.
    • Added fluent builder API (FromMapFile() with configuration methods) for advanced scenarios.
    • Added secret validation extension to validate resolved secrets are non-empty.
    • Added validate_secrets() function and SecretValidationError to Python SDK.
    • Simplified DI and configuration integration—no longer requires passing secret providers explicitly.
  • Improvements

    • Enhanced AWS credential and region resolution behavior.
    • Python method renamed: from_file()from_map_file() for clarity.

Copilot AI review requested due to automatic review settings April 18, 2026 07:54
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a public .NET facade (Envilder) and fluent builder for synchronous and asynchronous secret resolution/injection; requires sync ISecretProvider.GetSecret and adds sync provider implementations; internalizes SecretProviderFactory with cross-provider validation and AWS credential/region behavior changes; introduces secret validation helpers, tests, docs, and .NET central build/package settings.

Changes

Cohort / File(s) Summary
Facade & Builder
src/sdks/dotnet/Application/Envilder.cs, src/sdks/dotnet/Application/EnvilderBuilder.cs
New public static Envilder facade and fluent EnvilderBuilder with sync/async ResolveFile/Load, env-routing overloads, and builder overrides plus terminal Resolve/ResolveAsync/Inject/InjectAsync.
Client & Validation
src/sdks/dotnet/Application/EnvilderClient.cs, src/sdks/dotnet/Application/SecretValidationExtensions.cs
Added sync ResolveSecrets(ParsedMapFile), changed InjectIntoEnvironment to accept IEnumerable<KeyValuePair<string,string>>, and added SecretValidationException + ValidateSecrets extension.
Domain & Providers (.NET)
src/sdks/dotnet/Domain/Ports/ISecretProvider.cs, src/sdks/dotnet/Infrastructure/Aws/AwsSsmSecretProvider.cs, src/sdks/dotnet/Infrastructure/Azure/AzureKeyVaultSecretProvider.cs
Interface now requires string? GetSecret(string); AWS/Azure providers implement blocking sync GetSecret (60s CTS bridge), with input validation and 404/ParameterNotFound → null mapping.
Factory & DI/Config (.NET)
src/sdks/dotnet/Infrastructure/SecretProviderFactory.cs, src/sdks/dotnet/Infrastructure/Configuration/ConfigurationBuilderExtensions.cs, src/sdks/dotnet/Infrastructure/DependencyInjection/ServiceCollectionExtensions.cs
Made SecretProviderFactory internal; added cross-provider validation; AWS client creation now defers to SDK defaults when no profile and honors AWS_SHARED_CREDENTIALS_FILE for profiles; AddEnvilder overloads now accept EnvilderOptions? and create providers internally (removed caller-supplied ISecretProvider).
Configuration Source
src/sdks/dotnet/Infrastructure/Configuration/EnvilderConfigurationProvider.cs, src/sdks/dotnet/Infrastructure/Configuration/EnvilderConfigurationSource.cs
Switched to sync ResolveSecrets in provider load; reformatting only otherwise.
Tests — .NET
tests/sdks/dotnet/...
Added/updated unit and acceptance tests for facade, builder, sync client/provider methods, secret validation, and SecretProviderFactory acceptance tests; many tests refactored to new AddEnvilder overloads and sync provider contract.
Tooling & Project files (.NET)
src/sdks/dotnet/Envilder.csproj, src/sdks/dotnet/.editorconfig, tests/sdks/dotnet/.editorconfig, src/sdks/dotnet/Directory.Build.props, src/sdks/dotnet/Directory.Packages.props, test project files
Bumped .NET package version, added InternalsVisibleTo, introduced EditorConfig files and centralized Directory.*.props for package versions and build/analyzer settings.
Python: factory, facade & validation
src/sdks/python/envilder/infrastructure/secret_provider_factory.py, src/sdks/python/envilder/application/envilder_facade.py, src/sdks/python/envilder/application/secret_validation.py, src/sdks/python/envilder/__init__.py
Renamed factory to _SecretProviderFactory (internalized), added cross-provider validation, removed manual region resolution in no-profile AWS path (use boto3.Session()), renamed facade entry to from_map_file, and added SecretValidationError + validate_secrets (exported).
Python packaging & docs
src/sdks/python/pyproject.toml, docs/changelogs/sdk-python.md
Bumped Python package version and documented factory/public-surface & AWS region/profile behavior changes.
Docs & Website
docs/changelogs/sdk-dotnet.md, src/sdks/dotnet/README.md, website components & i18n (src/website/src/components/..., src/website/src/i18n/*)
Changelog and README updated for facade/builder/validation; website samples and translations updated; minor component typing and UI changes.
Formatting & Misc
many *.cs, test and domain files
Widespread indentation/whitespace reformatting (tabs vs spaces) and trailing-newline adjustments in multiple files; non-functional formatting edits.

Sequence Diagram

sequenceDiagram
    participant User
    participant Envilder as Envilder (Facade)
    participant FS as File System
    participant Parser as MapFileParser
    participant Factory as SecretProviderFactory
    participant Client as EnvilderClient
    participant Provider as ISecretProvider

    User->>Envilder: ResolveFile(filePath)
    Envilder->>FS: Read file contents
    FS-->>Envilder: File content
    Envilder->>Parser: Parse map file
    Parser-->>Envilder: ParsedMapFile
    Envilder->>Factory: Create provider (config, options)
    Factory-->>Envilder: ISecretProvider
    Envilder->>Client: new EnvilderClient(provider)
    Envilder->>Client: ResolveSecrets(mapFile)
    Client->>Provider: GetSecret(name) for each mapping
    Provider-->>Client: secret / null
    Client-->>Envilder: Dictionary<string,string>
    Envilder-->>User: IReadOnlyDictionary<string,string>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: adding a static Envilder facade with sync and async APIs to the .NET SDK.
Description check ✅ Passed The description comprehensively covers objectives, changes across .NET and Python SDKs, testing, and checklist items, and aligns with the provided template structure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch macalbert/feat/dotnet-sdk-facade

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Add static Envilder class with one-liner ResolveFile/Load methods and
fluent FromFile builder with WithProvider/WithProfile/WithVaultUrl
overrides. Add sync GetSecret to ISecretProvider and implementations.
Includes unit tests, fluent chaining tests, and LocalStack acceptance
tests. Bump version to 0.2.0.
@macalbert macalbert force-pushed the macalbert/feat/dotnet-sdk-facade branch from 4dff1de to 8b5eedb Compare April 18, 2026 07:56
gemini-code-assist[bot]

This comment was marked as resolved.

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 18, 2026 08:06
devin-ai-integration[bot]

This comment was marked as resolved.

This comment was marked as resolved.

@macalbert macalbert self-assigned this Apr 18, 2026
@macalbert macalbert added bug Something isn't working enhancement New feature or request and removed bug Something isn't working labels Apr 18, 2026
- Remove redundant _resolve_region_from_env() from Python profile path
- Isolate AWS_PROFILE/AWS_REGION in acceptance test fixtures (Python + .NET)
Copilot AI review requested due to automatic review settings April 18, 2026 09:01

This comment was marked as resolved.

- Change InjectIntoEnvironment to accept IEnumerable<KeyValuePair>
  eliminating fragile Dictionary casts in Envilder and EnvilderBuilder
- Add input validation to sync GetSecret on AWS SSM and Azure providers
- Add cancellationToken.ThrowIfCancellationRequested() to ReadFileAsync
  and ResolveFileAsync (netstandard2.0 has no cancelable ReadToEndAsync)
- Add null check for envMapping in ResolveEnvSource
- Add XML documentation to ISecretProvider.GetSecret
- Document breaking change in changelog (ISecretProvider new method)

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

- Add .NET SDK examples for resolving and injecting secrets
- Add Python SDK examples for loading, resolving, and environment-based routing
- Update changelogs to reflect security fixes and dependency updates
- Correct paths and naming conventions in documentation
@macalbert macalbert added bug Something isn't working documentation Improvements or additions to documentation dependencies refactor labels Apr 18, 2026
coderabbitai[bot]

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 18, 2026 23:28

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 18, 2026 23:58

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 19, 2026 00:37

This comment was marked as resolved.

- Move SecretProviderFactory internalization to Breaking changelog section
- Use Mapping instead of Dict for validate_secrets mypy strict compat
- Add missing AAA markers in Python validation tests
- Narrow except clause to ValueError in localstack container
- Guard Directory.Delete with Directory.Exists in test teardown
@macalbert macalbert merged commit 7b2520a into main Apr 19, 2026
14 of 15 checks passed
@macalbert macalbert deleted the macalbert/feat/dotnet-sdk-facade branch April 19, 2026 00:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working dependencies documentation Improvements or additions to documentation enhancement New feature or request refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants