:full Docker image, S3 vhost on any endpoint, Lambda routing sweep, STS session identityApril 28, 2026 · v1.3.17
1.3.17 fixes a cluster of routing and integration gaps. The :full Docker image with DuckDB / psycopg2 / pymysql lands so Athena and native database drivers stop fighting Alpine's musl wheels. S3 virtual-hosted routing now works against any endpoint hostname (not just localhost), unblocking AWS SDK for JavaScript v3 and Docker Compose service-name setups. Lambda's path-based routing was only matching /2015-03-31/functions — every other API version (EventInvokeConfig, ProvisionedConcurrency, FunctionUrl, Layers, Tags, Runtime) silently fell through to S3 for unsigned clients. CloudFormation Lambdas backed by S3 finally fetch their code instead of returning a mock. STS GetCallerIdentity now reflects the assumed role. And GetWebIdentityToken joins the STS surface for OIDC dev flows.
ministackorg/ministack:full — DuckDB-backed Athena, no source buildsThe default image is Alpine-based, which keeps it small (~110 MB) but also keeps it free of manylinux-only wheels. DuckDB and psycopg2-binary ship manylinux but not musllinux; on Alpine they fall back to slow source builds or silently disable themselves. Athena's DuckDB engine has been hitting that pain since the engine landed.
1.3.17 publishes a Debian/glibc variant alongside the regular image:
docker pull ministackorg/ministack:full
It's a functional superset of the regular image — same SFTP support, same env-var contract, same healthcheck — plus duckdb, psycopg2-binary, and pymysql. The :full tag tracks the latest release; pinned variants are also published as :1.3.17-full and :1.3-full. The regular :latest and :1.3.17 tags are unchanged. Closes the long-standing Athena-on-Alpine gap raised by @arischow.
The full image self-identifies via /_ministack/health:
{ "edition": "full", "version": "1.3.17", "services": { ... } }
S3 virtual-hosted-style URLs are the default for AWS SDK for JavaScript v3 and Terraform AWS provider v4+. The bucket is the first label of the Host header: Host: mybucket.s3.us-east-1.amazonaws.com. Against MiniStack the SDK drops in your endpoint, so the Host arrives as Host: mybucket.localhost:4566 — or, when you point the SDK at the Docker Compose service name, Host: mybucket.ministack:4566.
Before 1.3.17 the regex that detected S3 vhost was anchored to _MINISTACK_HOST (default localhost), so anything else fell through to S3 path-style with the wrong bucket. JS SDK v3 setups using a Compose service name silently broke; reported by @mgius-ae.
The replacement validates the first label against the AWS bucket-naming rules (3–63 chars, lowercase + digits + dots + hyphens, alphanum start/end, no .., not IPv4) and accepts any tail — so vhost works against localhost, ministack, custom DNS, or s3.amazonaws.com without configuration. Verified against 40 host-header cases including IPv6 brackets, mixed-case headers, control characters, and length boundaries.
/2015-03-31/functionsThe path-based service detector only matched the original Lambda API version date. Every other version date silently fell through to S3 when the request didn't carry a SigV4 Authorization header:
/2019-09-25/functions/.../event-invoke-config — PutFunctionEventInvokeConfig / GetFunctionEventInvokeConfig/2019-09-30/functions/.../provisioned-concurrency — PutProvisionedConcurrencyConfig/2021-10-31/functions/.../url — CreateFunctionUrlConfig/2018-10-31/layers/... — PublishLayerVersion via the alternate path/2015-03-31/event-source-mappings — CreateEventSourceMapping and friends/2015-03-31/tags/... — Lambda-resource TagResource / UntagResource/2016-08-19/account-settings — GetAccountSettings/2018-06-01/runtime/... — the Lambda Runtime API itself, called unsigned by Lambda containers/2020-04-22/code-signing-configs/... — CreateCodeSigningConfigboto3 always signs and routed via the SigV4 credential scope (which encodes the service name), so most users never noticed. But raw HTTP / curl / Lambda Runtime traffic missed. The detector now matches ^/{date}/{lambda-resource}/... for every documented Lambda resource.
A quiet showstopper for CDK users. The CloudFormation provisioner for AWS::Lambda::Function accepted Code.S3Bucket / Code.S3Key and stored them as metadata on the function record — but never actually fetched the bytes. Every CFN-deployed Lambda backed by S3 had code_zip = None and returned a hardcoded "Mock response - no code deployed" on invocation. Inline ZipFile was unaffected; the S3 path simply never worked.
1.3.17 fixes the provisioner to actually call the Lambda S3 helper — the same one CreateFunction and UpdateFunctionCode already used. Contributed by @hiddengearz. Pairs with the S3ObjectVersion threading that landed in 1.3.16 — together they make CDK Code.fromBucket(..., objectVersion=...) a fully working path.
Two STS fixes that matter for any test harness asserting on identity:
GetCallerIdentity now returns the assumed-role ARN. Before 1.3.17 it always returned arn:aws:iam::000000000000:root, regardless of which credentials made the call — so tests that obtain temporary credentials via AssumeRole and then verify the assumed role could never confirm the role. The handler now extracts the AccessKeyId from the SigV4 Authorization header and looks it up in a session map populated at AssumeRole / AssumeRoleWithWebIdentity time, returning the matching arn:aws:sts::{account}:assumed-role/{role}/{session} and {role-id}:{session} UserId. Contributed by @hectormauer.
GetWebIdentityToken action added. Implements the AWS-spec validation: SigningAlgorithm is required and must be RS256 or ES384; Audience.member.N is required, 1–10 items × 1–1000 chars; DurationSeconds is bounded 60–3600 (default 300). Returns a parseable JWT with the expected claims (sub, aud, iss, iat, exp) for OIDC dev flows. The signature is HS256 — sufficient for emulator workloads that inspect claims, not for clients that verify against AWS JWKS. Requested by @anghel93.
AssumeRole / AssumeRoleWithWebIdentity returned arn:aws:iam::...:assumed-role/... for the assumed-role principal. Real AWS uses the sts service in the ARN: arn:aws:sts::...:assumed-role/{role}/{session}. Any IAM-policy Condition: aws:PrincipalArn checking against the sts shape would mismatch.PutIntegration returned HTTP 200 instead of 201. AWS CLI prints the resource on 201; on 200 it's silent. Affects scripts that branched on stderr.StartReplay started in RUNNING state instead of STARTING. Real AWS goes STARTING → RUNNING → COMPLETED. The background thread already transitioned RUNNING → COMPLETED, just was skipping the initial STARTING.Subscribe returned PendingConfirmation as the SubscriptionArn for HTTP/email pending subscriptions. Real AWS returns lowercase pending confirmation (with the space). String-matching clients fell through.arn:aws:states:::states:startExecution starts the nested execution and returns ExecutionArn / StartDate instead of echoing the request payload. arn:aws:states:::aws-sdk:sfn:startExecution now accepts AWS Step Functions' PascalCase integration parameters (StateMachineArn, Input, Name) by translating them to MiniStack's lower-camel Step Functions API shape. Existing .sync and .waitForTaskToken paths preserved. Contributed by @jayjanssen.AWS_REGION, AWS_DEFAULT_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_LAMBDA_FUNCTION_VERSION, and AWS_LAMBDA_LOG_STREAM_NAME were missing from the warm-worker path even though the Docker path already set them. Functions calling boto3.client(...), X-Ray tracers, CloudWatch metric emitters, and code branching on $LATEST vs published versions ran with an inconsistent environment compared to AWS. Contributed by @hiddengearz.# Regular image (Alpine, ~110 MB) docker pull ministackorg/ministack:1.3.17 # Full image (Debian + DuckDB + psycopg2 + pymysql, ~360 MB) docker pull ministackorg/ministack:1.3.17-full # pip pip install -U ministack
Full changelog: CHANGELOG.md.
Shipped by the MiniStack community. Contributions credited throughout. GitHub · r/ministack