What's Changed
New Contributors
- @mattwang44 made their first contribution in #451
- @ksjoberg made their first contribution in #459
- @weeco made their first contribution in #456
- @hzhou0 made their first contribution in #465
[1.3.14] — 2026-04-24
Added
DOCKER_NETWORKenv var unifies container networking across RDS / EKS / ElastiCache / Lambda — a single knob that replaces the old$HOSTNAMEauto-detection (which silently failed under docker-compose) and subsumes the legacyLAMBDA_DOCKER_NETWORK. When set, RDS and ElastiCache also switchEndpoint.Addressto the routable container IP instead oflocalhost, so Lambda containers on the same network can actually reach them.LAMBDA_DOCKER_NETWORKis still accepted as a fallback for backwards compatibility. Contributed by @bognari.LAMBDA_DOCKER_FLAGSenv var for Lambda container customisation — matches LocalStack's convention for injectingdocker runflags into Lambda containers. Supports-e/--env,-v/--volume,--dns,--network,--cap-add,-m/--memory,--shm-size,--tmpfs,--add-host,--privileged,--read-only. Unblocks TLS-proxy / custom-CA / routed-dev-network setups used in local Kubernetes environments. Default unset → behaviour identical to AWS. Contributed by @hzhou0.MINISTACK_IMAGE_PREFIXroutes nested images through a private registry — Testcontainers'hub.image.name.prefixnow propagates to every nested real-infra image (RDS postgres/mysql/mariadb, ElastiCache redis/memcached, EKS k3s, Lambda runtime images underpublic.ecr.aws/lambda/*). Air-gapped and proxy-only environments no longer need to accept docker.io pulls for real-infra containers. The Java Testcontainers module forwards the prefix automatically. Reported by @TJ-developer.- Testcontainers Java module reaps orphaned MiniStack containers and volumes on
stop()— RDS / ECS / EKS / ElastiCache nested containers spawned on the host engine are no longer leaked after the test run, closing a long-standing Podman-visible leak. The reaper labels all sidecar resourcesministack=<service>and removes them via the DockerClient regardless of the host engine (Docker or Podman). - Secrets Manager
ListSecretshonoursIncludePlannedDeletion— soft-deleted secrets are now returned when the flag is set, withDeletedDatepopulated on each entry per the AWSSecretListEntryspec. Unblocks clients that polllist-secrets --include-planned-deletionto confirm a soft delete. Contributed by @weeco.
Fixed
- S3 zero-byte
PutObjectchecksum mismatch with Java SDK v2 — the aws-chunked decoder mishandled zero-byte streaming PUTs (a single terminator chunk0;chunk-signature=…\r\n\r\n): it correctly broke the loop onchunk_size == 0but then fell through without replacing the body, leaving the raw chunked framing as the "body" bytes. The computed ETag (0cabc165…, MD5 of the wrapper) mismatched the client's expected ETag (d41d8cd9…, MD5 of empty content), and Java SDK v2 surfaced aRetryableException: Data read has a different checksum than expected. Reported by @JoeHale. Contributed by @AdigaAkhil. - SNS HTTP subscription confirmation silently skipped — the handler imported
aiohttpat call time, butaiohttpwas never a declared dependency and wasn't in the Docker image, so every HTTP subscribe delivered anaiohttp not installed — subscription confirmation skippedlog and no POST. Replaced withurllib.requestwrapped inasyncio.to_thread, honouring the no-new-deps rule. Userinfo in URLs (http://user:pass@host/…) is promoted toAuthorization: Basicper real AWS SNS behaviour. Reported by @anghel93. - RDS
DescribeDBInstancesSigV4 JSON protocol — Java and Go SDKs that negotiate the JSON variant (rather than Query) were hitting the fallback handler;DescribeDBInstancesnow speaks both shapes. Aurora-clusterDBClusterMembersmembership is populated correctly when instances are created inside a cluster. - Lambda RIE container log isolation — warm RIE containers accumulate stdout/stderr across every invocation; without a
sincefilter the response bundled every prior invocation's logs, ballooningLogResultunpredictably and makingLogType=Taildebugging useless.container.logs(since=invoke_time)now returns only the current invocation's lines, matching real Lambda. Contributed by @ksjoberg. - Lambda RIE retry loop no longer waits 100ms on the first attempt — the
time.sleep(0.1)was at the top of the retry loop, costing every RIE invocation a 100ms floor even when the container was already listening. Sleep is now paid only onURLError/ConnectionRefusedErrorretries. Hot-path savings: ~100ms per warm RIE invoke. Contributed by @ksjoberg. - Lambda warm-pool container memory probe halves in latency —
container.stats(stream=False)withoutone_shot=Truecollects two stat samples 1 second apart to compute CPU deltas, which MiniStack doesn't need (we only readmemory_stats.max_usage). Addedone_shot=Trueper the Docker API docs; saves ~1 second per_probe_peak_memory_mbcall. Contributed by @ksjoberg. - Lambda slash-form Python handler paths —
Handler: "pkg/sub/mod.fn"(common in cookiecutter Lambda templates) now resolves the same way AWS'sawslambdaricbootstrap does (modname.replace("/", ".")). Contributed by @ksjoberg.
Changed
aiohttpremoved from SNS HTTP delivery path — replaced with stdliburllib.request.urlopenwrapped inasyncio.to_thread. Honours MiniStack's no-new-deps rule (Docker image size, idle RAM, attack surface). Back-compat preserved — same call sites, same logging shape.- Server bumps asyncio default executor to 64 threads on startup — lifespan hook installs a
ThreadPoolExecutor(max_workers=64)before the first request. The Python default (6 threads on 2-core CI runners) could stall concurrent Lambda cold-starts behind blocking work, causing intermittent test-side urlopen timeouts. Override withMINISTACK_WORKER_THREADS.