Skip to content

feat(sdk): add Python SDK with Makefile and CI workflow - #157

Merged
macalbert merged 25 commits into
mainfrom
feat/python-sdk
Apr 14, 2026
Merged

feat(sdk): add Python SDK with Makefile and CI workflow#157
macalbert merged 25 commits into
mainfrom
feat/python-sdk

Conversation

@macalbert

@macalbert macalbert commented Apr 14, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a Python SDK for Envilder that mirrors the .NET SDK architecture, enabling Python applications to load secrets directly from AWS SSM Parameter Store or Azure Key Vault using the shared map-file format. Includes a root Makefile for SDK development workflows, a GitHub Actions CI workflow, and a PyPI publish workflow using trusted publishers.

Changes

Python SDK (src/sdks/python/)

  • Domain layer: ISecretProvider Protocol, SecretProviderType enum, dataclasses (MapFileConfig, EnvilderOptions, ParsedMapFile)
  • Application layer: MapFileParser with $config section support, EnvilderClient with resolve_secrets() and inject_into_environment()
  • Infrastructure: AwsSsmSecretProvider (boto3), AzureKeyVaultSecretProvider, SecretProviderFactory with options override
  • Tooling: black (line-length 79), isort (black profile), mypy strict, py.typed marker
  • Public API exports in __init__.py
  • project.urls metadata for PyPI page links

Tests (tests/sdks/python/)

  • 21 unit tests + 8 acceptance tests (29 total, 0 warnings)
  • Container wrappers following xxtemplatexx pattern: LocalStackContainer, LowkeyVaultContainer with explicit start()/stop() lifecycle and HTTP health checks
  • Dogfooding: LocalStackContainer uses the SDK itself to resolve LOCALSTACK_AUTH_TOKEN from real AWS SSM via secrets-map.json
  • TestContainers with LocalStack (AWS SSM) and Lowkey Vault (Azure Key Vault)

Makefile

  • Per-stack targets: check-sdk-python, format-sdk-python, test-sdk-python
  • .NET targets: check-sdk-dotnet, format-sdk-dotnet, build-sdk-dotnet, test-sdk-dotnet
  • Composite targets: check-sdk, format-sdk, build-sdk, test-sdk

CI (.github/workflows/tests-python-sdk.yml)

  • Python 3.10 + 3.13 matrix on ubuntu-24.04
  • Steps: install (uv), format + type check, unit tests, acceptance tests (Docker)
  • AWS credential assumption for SDK dogfooding

Publish (.github/workflows/publish-pypi.yml)

  • Triggers on push to main when src/sdks/python/** changes
  • Version bump detection (compares pyproject.toml vs published PyPI version)
  • Uses PyPI trusted publisher (OIDC) — no API tokens
  • Builds with uv build, publishes via pypa/gh-action-pypi-publish
  • Creates sdk-python/vX.Y.Z git tag + GitHub release

Testing

  • make check-sdk-python passes (black, isort, mypy strict)
  • make test-sdk-python passes (29/29, 0 warnings)

Setup Required

  • Configure trusted publisher on PyPI for envilder package (owner: macalbert, repo: envilder, workflow: publish-pypi.yml, environment: pypi)
  • Create pypi environment in GitHub repo settings

Summary by CodeRabbit

  • New Features

    • Introduced a Python SDK for resolving secrets from AWS SSM and Azure Key Vault via map-file configuration.
    • Added EnvilderClient with secret resolution and environment injection.
    • Runtime override support for provider, profile, and vault URL.
  • Documentation

    • Added Python SDK README, installation, usage examples, and updated architecture and changelog.
  • Tests

    • Added comprehensive unit and acceptance tests (LocalStack & Lowkey Vault).
  • Chores

    • Python packaging/tooling configuration added.

Add Python SDK mirroring the .NET SDK architecture:

- Domain layer: ISecretProvider Protocol, SecretProviderType enum, dataclasses

- Application layer: MapFileParser ( support), EnvilderClient

- Infrastructure: AwsSsmSecretProvider (boto3), AzureKeyVaultSecretProvider

- SecretProviderFactory with options override

- 21 unit tests (pytest, Should_* naming) + 8 acceptance tests (TestContainers)

- Tooling: black, isort, mypy strict, py.typed marker

Add root Makefile with per-stack targets (check/format/build/test)

Add tests-python-sdk.yml workflow (Python 3.10 + 3.13 matrix)
Copilot AI review requested due to automatic review settings April 14, 2026 16:54
@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@macalbert has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 32 minutes and 1 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 32 minutes and 1 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eb354071-58d8-4f94-a69a-ba125d04b961

📥 Commits

Reviewing files that changed from the base of the PR and between 100eaaf and 12b5e3b.

⛔ Files ignored due to path filters (1)
  • Makefile is excluded by none and included by none
📒 Files selected for processing (15)
  • src/sdks/python/envilder/infrastructure/aws/aws_ssm_secret_provider.py
  • src/sdks/python/envilder/infrastructure/secret_provider_factory.py
  • tests/sdks/python/application/test_envilder_client.py
  • tests/sdks/python/application/test_map_file_parser.py
  • tests/sdks/python/containers/__init__.py
  • tests/sdks/python/containers/localstack_container.py
  • tests/sdks/python/containers/lowkey_vault_container.py
  • tests/sdks/python/end_to_end/test_consumer_experience.py
  • tests/sdks/python/fixtures/localstack_fixture.py
  • tests/sdks/python/fixtures/lowkey_vault_fixture.py
  • tests/sdks/python/infrastructure/aws/test_aws_ssm_acceptance.py
  • tests/sdks/python/infrastructure/aws/test_aws_ssm_secret_provider.py
  • tests/sdks/python/infrastructure/azure/test_azure_key_vault_acceptance.py
  • tests/sdks/python/infrastructure/azure/test_azure_key_vault_secret_provider.py
  • tests/sdks/python/infrastructure/test_secret_provider_factory.py

Walkthrough

Adds a new synchronous Python SDK for Envilder: domain models, application logic (map-file parsing and client), AWS/Azure secret providers, provider factory with runtime overrides, packaging/tests, containers/fixtures for acceptance tests, and documentation/tooling configuration.

Changes

Cohort / File(s) Summary
Package entry & exports
src/sdks/python/envilder/__init__.py, src/sdks/python/envilder/application/__init__.py, src/sdks/python/envilder/domain/__init__.py, src/sdks/python/envilder/infrastructure/__init__.py, src/sdks/python/envilder/domain/ports/__init__.py
Adds package initializers and explicit __all__ exports to surface SDK public API.
Domain models & contracts
src/sdks/python/envilder/domain/map_file_config.py, src/sdks/python/envilder/domain/parsed_map_file.py, src/sdks/python/envilder/domain/envilder_options.py, src/sdks/python/envilder/domain/secret_provider_type.py, src/sdks/python/envilder/domain/ports/secret_provider.py
Introduces dataclasses (MapFileConfig, ParsedMapFile, EnvilderOptions), SecretProviderType enum, and ISecretProvider protocol.
Application logic
src/sdks/python/envilder/application/map_file_parser.py, src/sdks/python/envilder/application/envilder_client.py
Implements MapFileParser.parse() and _deserialize_config(), and EnvilderClient with resolve_secrets and inject_into_environment.
Infrastructure - AWS
src/sdks/python/envilder/infrastructure/aws/aws_ssm_secret_provider.py, src/sdks/python/envilder/infrastructure/aws/__init__.py
Adds AwsSsmSecretProvider wrapping boto3 SSM client with input validation and ClientError handling for missing parameters.
Infrastructure - Azure
src/sdks/python/envilder/infrastructure/azure/azure_key_vault_secret_provider.py, src/sdks/python/envilder/infrastructure/azure/__init__.py
Adds AzureKeyVaultSecretProvider wrapping Azure SecretClient with input validation and ResourceNotFound handling.
Secret provider factory
src/sdks/python/envilder/infrastructure/secret_provider_factory.py
Adds SecretProviderFactory.create() with options override support; constructs AWS or Azure providers, resolves AWS region from env, and handles profile/credential assembly.
Packaging & tooling
src/sdks/python/pyproject.toml, tests/sdks/python/pyproject.toml
Adds Python package metadata, runtime and dev dependencies, and tooling (black/isort/mypy) plus pytest config for tests.
Documentation & changelog
src/sdks/python/README.md, docs/architecture/README.md, docs/requirements-installation.md, docs/CHANGELOG.md
Adds Python SDK README, architecture notes, installation prerequisites, and changelog entry.
Tests - unit & integration
tests/sdks/python/application/*, tests/sdks/python/infrastructure/*, tests/sdks/python/infrastructure/aws/*, tests/sdks/python/infrastructure/azure/*, tests/sdks/python/infrastructure/test_secret_provider_factory.py
Adds unit and acceptance tests covering parser, client, providers, and factory with mocked and container-backed scenarios.
Tests - acceptance containers & fixtures
tests/sdks/python/containers/*, tests/sdks/python/fixtures/*, tests/sdks/python/end_to_end/*, tests/sdks/python/secrets-map.json, tests/sdks/python/conftest.py, tests/sdks/python/.gitignore
Adds LocalStack and Lowkey Vault container helpers, pytest fixtures, end-to-end acceptance tests, test secrets map, and test gitignore.
Housekeeping
src/sdks/python/.gitkeep (removed), tests/sdks/python/.gitkeep (removed), tests/sdks/dotnet/Envilder.Tests.csproj
Removes placeholder .gitkeep files and updates a .NET test dependency version range.

Sequence Diagram(s)

sequenceDiagram
    participant App as Consumer
    participant Parser as MapFileParser
    participant Factory as SecretProviderFactory
    participant Client as EnvilderClient
    participant Provider as ISecretProvider

    App->>Parser: parse(json_content)
    Parser-->>App: ParsedMapFile(config, mappings)
    App->>Factory: create(config, options?)
    Factory-->>App: ISecretProvider (AwsSsm or AzureKeyVault)
    App->>Client: EnvilderClient(provider)
    App->>Client: resolve_secrets(ParsedMapFile)
    loop for each mapping
        Client->>Provider: get_secret(path)
        Provider-->>Client: secret_value or None
    end
    Client-->>App: dict[str, str] (only found secrets)
    App->>Client: inject_into_environment(secrets)
    Client->>Client: os.environ[k]=v
Loading
sequenceDiagram
    participant Factory as SecretProviderFactory
    participant Env as Environment
    participant Boto as boto3.Session
    participant SSM as AWS SSM
    participant Provider as AwsSsmSecretProvider

    Factory->>Env: read AWS_REGION / AWS_DEFAULT_REGION
    alt options/config selects AWS with profile
        Factory->>Boto: Session(profile_name, region_name?)
    else
        Factory->>Boto: Session(region_name?)
    end
    Boto-->>Factory: session
    Factory->>SSM: session.client('ssm')
    Factory-->>Provider: AwsSsmSecretProvider(ssm_client)
Loading
sequenceDiagram
    participant Factory as SecretProviderFactory
    participant Cred as DefaultAzureCredential
    participant Vault as SecretClient
    participant Provider as AzureKeyVaultSecretProvider

    Factory->>Factory: determine vault_url from config/options
    Factory->>Cred: DefaultAzureCredential()
    Cred-->>Factory: credential
    Factory->>Vault: SecretClient(vault_url, credential)
    Vault-->>Factory: client
    Factory-->>Provider: AzureKeyVaultSecretProvider(client)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested labels

documentation, feature, python-sdk

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 and specifically identifies the main change: addition of a Python SDK along with Makefile and CI workflow configuration.
Description check ✅ Passed The PR description is comprehensive and well-structured with detailed sections covering changes, testing, and setup requirements, exceeding the template expectations.

✏️ 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 feat/python-sdk

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.

gemini-code-assist[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 14, 2026 17:22

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

🐛 1 issue in files not directly in the diff

🐛 py.typed marker file placed outside package directory, won't be included in distribution (src/sdks/python/py.typed:1)

The PEP 561 py.typed marker file is at src/sdks/python/py.typed (the project root) instead of src/sdks/python/envilder/py.typed (inside the package directory). Hatchling only includes files from discovered package directories (envilder/), so this file won't be included in the built wheel/sdist. Consumers installing the package from PyPI won't get PEP 561 typed package recognition — type checkers like mypy will treat the package as untyped, despite the pyproject.toml declaring "Typing :: Typed" in classifiers and the documentation listing strict typing as a key feature.

View 8 additional findings in Devin Review.

Open in Devin Review

This comment was marked as resolved.

@macalbert macalbert self-assigned this Apr 14, 2026
@macalbert macalbert added sdk-python enhancement New feature or request labels Apr 14, 2026
coderabbitai[bot]

This comment was marked as resolved.

- Guard top-level JSON type in MapFileParser (reject non-object)
- Case-insensitive provider parsing in map file config
- Add name validation to AzureKeyVaultSecretProvider
- Narrow exception handling in SecretProviderFactory
- Move py.typed to envilder/ package dir (PEP 561)
- Remove unused ssl import from lowkey_vault_container
- Simplify exception handling in container wrappers
- Remove lambda assignments in tests (Ruff E731)
- Remove unused imports from e2e tests
- Gate AWS creds on version_changed in publish workflow
- Narrow permissions in test report job
- Fix matrix output aggregation in CI workflow
- Remove duplicate Makefile dotnet targets
- Add tests for JSON guard and mixed-case provider
Copilot AI review requested due to automatic review settings April 14, 2026 21:24

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 14, 2026 21:57

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 14, 2026 22:41

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

…tant

- Fix test reporter glob to match versioned XML filenames
- Wrap cd commands in subshells for isort and black checks
- Remove unused _FALLBACK_REGION constant
Copilot AI review requested due to automatic review settings April 14, 2026 23:08

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 14, 2026 23:39

This comment was marked as resolved.

@macalbert
macalbert merged commit afb7e6a into main Apr 14, 2026
12 checks passed
@macalbert
macalbert deleted the feat/python-sdk branch April 14, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request sdk-python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants