August 23, 2026 · v1.5.0
v1.5.0 is a feature release. IAM gains opt-in request authorization: set AUTH=true and MiniStack evaluates the caller's policies before serving a request. CloudFront adds SaaS Manager multi-tenant distributions, EC2 can boot a real container behind an instance and SSM Run Command runs commands on it, S3 gains Glacier and Deep Archive restore, and a concurrency change keeps a blocking handler from stalling other requests. Around that, IAM, S3, RDS, Cognito, DynamoDB and Lambda fixes.
AUTH=true). MiniStack has always accepted any credentials and authorized every call. With AUTH=true it now evaluates the caller's IAM policies before serving a request and returns 403 AccessDenied (User: {arn} is not authorized to perform: {action}) when they do not allow it — across control-plane and data-plane paths (S3 object access, execute-api:Invoke, lambda:InvokeFunctionUrl, and per-service actions resolved from the botocore model). SigV4 signatures are still not validated, so the access key only identifies the principal: this is authorization, not authentication. Off by default, so existing allow-all flows are unchanged.If-Match concurrency, per-tenant WAF association, tenant invalidations, and domain tooling (DNS verification, managed certificates, domain-conflict checks). A tenant requires a tenant-only distribution (InvalidAssociation), CNAMEs are unique across tenants and distribution aliases (CNAMEAlreadyExists), and deleting a distribution or connection group that still has tenants is refused (ResourceInUse). Shapes verified against the CloudFront botocore model. Contributed by @mjdavidson.RegisterImage). RunInstances returned a running record and booted nothing. RegisterImage now takes a container reference in ImageLocation and returns an ami- id whose launch boots that image as a container, its IP becoming the instance's address, so ssm:SendCommand can report a real exit code. Such an AMI is instance-store backed (StopInstances / StartInstances answer UnsupportedOperation); registering is the only opt-in, so with nothing registered EC2 never reaches for Docker. RebootInstances also now rejects an unknown id with InvalidInstanceID.NotFound. Reported by @iot-rocket.SendCommand, GetCommandInvocation, ListCommands and DescribeInstanceInformation returned InvalidAction. Invocations are now asynchronous as on AWS — SendCommand answers Pending and the caller polls to a terminal state — and AWS-RunShellScript runs in the instance's container so Status reflects the real exit code. Pairs with EC2 RegisterImage to run commands on a real box. Contributed by @bandle.RestoreObject). An object in the GLACIER or DEEP_ARCHIVE storage class is now unreadable until restored: a GET/HEAD is refused 403 InvalidObjectState, RestoreObject runs an asynchronous restore, and x-amz-restore reports the ongoing request then the restored copy's expiry. GLACIER_IR stays readable and a RestoreObject against it fails ObjectAlreadyInActiveTierError, as on AWS.full image is smaller. Unused payload was trimmed from the full variant.AttachedPolicies as dicts, Versions as a list), so GetAccountAuthorizationDetails, ListAttachedRolePolicies and ListPolicyVersions errored or never matched. They now go through the IAM module, so one shape reaches every reader, AWS::IAM::ManagedPolicy honours its Roles / Users / Groups, and both resource types return the Fn::GetAtt attributes CloudFormation documents. Reported by @iot-rocket.AccessDenied is serialized in the caller's wire protocol. The authorization path formatted every denial as Query-API XML, but a service that also answers JSON or smithy-rpc-v2-cbor (CloudWatch and others) needs the error in that protocol with the correct xmlns; denials are now formatted per the service's botocore protocol.await load correctly. A handler whose module graph contains a top-level await throws Node's ERR_REQUIRE_ASYNC_MODULE, which fell through to an uncaught RuntimeError; both Node bootstraps now treat it like ERR_REQUIRE_ESM and fall back to dynamic import(). Contributed by @ryan-bennett.ListUsers Filter matches values case-insensitively. Every comparison was an exact string match, so email = "user@example.com" missed a profile stored as User@Example.com; values now match case-insensitively for email, phone_number, name, sub and the other profile attributes, while username and status stay case-sensitive per the API reference. Contributed by @ppettitau.UpdateExpression alias is resolved before the key-attribute check. set #pk = :pk with #pk mapped to a non-key attribute was wrongly refused with Cannot update attribute pk. This attribute is part of the key; the check now reads the alias-resolved roots, so only a path that resolves to the partition or sort key is rejected. Reported by @ppettitau.DescribeDBInstances honors SDK Filters. Clients serialize filters as Filters.Filter.N with Values.Value.N, but only the internal Filters.member.N form was parsed, so filters such as db-cluster-id were ignored; both wire forms are now parsed. Contributed by @jayjanssen.DeleteObject with If-Match returned 204 for a key that was absent or hidden by a delete marker, so a compare-and-swap delete reported success it never did; the condition is now evaluated against the current version only — no current object answers NoSuchKey, a differing ETag PreconditionFailed, and a matching ETag or If-Match: * deletes. Contributed by @gaul.ListBuckets, GetBucketAcl, GetObjectAcl and object listings returned the account id (or a placeholder) and disagreed with one another; they now return a single stable opaque 64-character hex canonical ID, as real S3 does. Reported by @jin-gizmo.DescribeAvailabilityZones reports the zone-group fields. Each zone was missing groupName, networkBorderGroup and optInStatus, so a consumer that reads them (Terraform's aws_availability_zones data source) saw them absent; standard zones now report them.docker pull ministackorg/ministack:1.5.0 docker run -d -p 4566:4566 ministackorg/ministack:1.5.0
Or pin in compose.yaml:
services:
ministack:
image: ministackorg/ministack:1.5.0
ports:
- "4566:4566"
Issues and PRs welcome on GitHub. Discussion on r/ministack.