pytest · Testcontainers · uv · LocalStack · LocalStack for Azure
uv run pytestBefore you run:
envilder.jsonmapsLOCALSTACK_AUTH_TOKENto the SSM key/envilder/development/localstack/authToken, so that key must hold your LocalStack token in your AWS account, and you need the AWS CLI installed and logged in (aws configureoraws sso login). See Store your LocalStack token.
flowchart LR
subgraph cloud["☁️ Your AWS account"]
token[("SSM<br/>LOCALSTACK_AUTH_TOKEN")]
end
subgraph docker["🐳 Docker, started by Testcontainers"]
localstack["LocalStack<br/><i>emulated SSM</i>"]
azurelocal["LocalStack for Azure<br/><i>emulated Key Vault</i>"]
end
token -- "Envilder.resolve_file('envilder.json')" --> localstack
token -- "same token" --> azurelocal
aws["🧪 test_aws_ssm.py"] --> localstack
azure["🧪 test_azure_key_vault.py"] --> azurelocal
Three tests, two stories (see the root README):
| Test | Proves |
|---|---|
Should_ActivateLicense_When_LocalStackStartsWithTokenResolvedByEnvilder |
Envilder fetched the real token and LocalStack accepted it |
Should_ResolveSecretFromSsm_When_MapFilePointsToIt |
Envilder resolves envilder.test.aws.json against SSM |
Should_ResolveSecretFromKeyVault_When_MapFilePointsToIt |
Envilder resolves envilder.test.azure.json against Key Vault |
test_aws_ssm.py: thelocalstackfixture is the whole integration in two statements,Envilder.resolve_file(...)andcontainer.env.update(secrets). Then come the first two tests. In the second, look at theActblock: that is everything Envilder does.test_azure_key_vault.pyis the same test against Key Vault. Itssecretsfixture resolves the same token, and the emulator plumbing lives inlocalstack_azure.py, so skim it. The test itself only changes the map file and the client.
Your app resolves a map file in one call, and Envilder builds the cloud client for you:
secrets = Envilder.resolve_file("envilder.test.aws.json")The tests need that client aimed at an emulator, so they build it themselves and hand it to Envilder:
sut = EnvilderClient(AwsSsmSecretProvider(ssm))
secrets = sut.resolve_secrets(map_file)Everything after that line is the same code your app runs.
You won't need these against real clouds:
| What | Why |
|---|---|
aws_access_key_id="test", … |
LocalStack accepts any credentials |
LOCALSTACK_AUTH_TOKEN |
LocalStack for Azure needs the same token as the AWS emulator, resolved with Envilder |
a free host port bound to the same container port, GATEWAY_LISTEN, LOCALSTACK_HOST |
vault URLs embed the gateway port, so both ports must match |
ClientSecretCredential("any-app", "dummy") with disable_instance_discovery=True |
the emulator accepts a placeholder service principal (all-zero tenant and subscription) on https://azure.localhost.localstack.cloud:<port> |
| resource group and vault created through ARM | the emulator starts empty, so the test creates the vault and uses the returned vaultUri |
IDENTITY_ENDPOINT / IDENTITY_HEADER |
a tiny local token endpoint lets DefaultAzureCredential work through managed identity, as on an App Service; competing AZURE_* variables are cleared while it runs |
TLS verification and Key Vault challenge resource verification stay enabled: the emulator serves a trusted certificate on *.vault.azure.localhost.localstack.cloud.