October 7, 2026 · v1.5.23
v1.5.23 adds SES v2 tenants and dedicated IP pools, SES receipt rules and identity notifications to SNS, IoT domain configurations, job templates and CreateCertificateFromCsr, CloudFormation support for IoT things, certificates and Signer profiles, AppConfig gradual rollouts with alarm rollback, API Gateway AWS integrations that target SQS, and multi-attribute DynamoDB GSI keys. DynamoDB Query and Scan now page at 1 MB and index queries no longer read the whole table, and the release fixes SQS FIFO delays, CloudWatch weighted metrics, closed DynamoDB streams, and Step Functions retries.
DEPLOYING, BAKING and COMPLETE on the strategy's schedule, a CloudWatch alarm in the environment's Monitors that goes to ALARM rolls the deployment back, and a concurrent or stale deployment returns ConflictException. Contributed by @Jolley71717.AWS integrations targeting SQS. a non-proxy integration whose URI is sqs:path/{account}/{queue} now renders its requestTemplates, sends the message to the queue and maps the reply through integrationResponses; other AWS service URIs still take the Lambda path. Contributed by @pingedbrain. Reported by @teruyukisuda.AWS::IoT::Thing, AWS::IoT::Certificate, AWS::IoT::ThingPrincipalAttachment and AWS::IoT::PolicyPrincipalAttachment failed with Unrecognized resource types; they now provision onto the IoT registry with AWS's Ref and Fn::GetAtt values. CreateCertificateFromCsr was added, and DescribeCertificate now reports certificateMode. Contributed by @iot-rocket.VALIDATION_FAILED before anything is provisioned. Contributed by @iot-rocket.CustomErrorResponses were stored but never applied; when the origin answers a configured ErrorCode, the data plane now returns ResponsePagePath with ResponseCode. Contributed by @skialpine.CustomMessage_AdminCreateUser trigger. AdminCreateUser now invokes the pool's CustomMessage Lambda before sending the invitation, and {username} expands to the email or phone number in pools with UsernameAttributes. Contributed by @kjdev.HASH or RANGE attributes failed every Query with "Query condition missed key schema element". Query now needs equality on every partition-key attribute and takes sort-key attributes left to right, only the last with a range condition. Reported by @jun-ut.CreateDomainConfiguration, DescribeDomainConfiguration, ListDomainConfigurations, UpdateDomainConfiguration, DeleteDomainConfiguration and AWS::IoT::DomainConfiguration. Contributed by @iot-rocket.CreateJobTemplate, DescribeJobTemplate, ListJobTemplates, DeleteJobTemplate, CreateJob with jobTemplateArn, and AWS::IoT::JobTemplate. Contributed by @iot-rocket.SetIdentityNotificationTopic stored topics that nothing published to; v1 sends now publish a Delivery, Bounce or Complaint notification per recipient, following the mailbox simulator. Contributed by @kjdev.CreateTenant, GetTenant, ListTenants, DeleteTenant, PutTenantSuppressionAttributes and the tenant resource association operations; a resource with associations cannot be deleted. Contributed by @AdrianAcala. Reported by @wparad.CreateDedicatedIpPool, GetDedicatedIpPool, ListDedicatedIpPools and DeleteDedicatedIpPool, with tags on the pool ARN. Reported by @wparad.CancelSigningProfile. AWS::Signer::SigningProfile and AWS::Signer::ProfilePermission provision, and AddProfilePermission, ListProfilePermissions, RemoveProfilePermission and CancelSigningProfile are routed. Contributed by @iot-rocket.AUTH=true, management requests were checked against SDK operation names; they now use apigateway:GET, POST, PUT, PATCH and DELETE on the requested resource path, so scoped grants and stage denies apply. Contributed by @AdrianAcala.GetLatestConfiguration and StopDeployment. a poll returned the full configuration every time, and StopDeployment marked any deployment ROLLED_BACK. An unchanged poll now returns an empty body, and StopDeployment follows the documented states. Contributed by @Jolley71717.Values/Counts and StatisticValues. values were stored once per count and statistic sets as their average, so SampleCount, Sum, Minimum and Maximum were wrong. They now aggregate weighted, and percentiles are omitted for negative values and for statistic sets that are not one repeated value. Contributed by @DimQ1.AUTH=true, authorization now includes existing and requested tags, and ARN-based tagging APIs authorize the supplied ARN instead of *. Contributed by @AdrianAcala.RESET_REQUIRED users cannot sign in with a password. after AdminResetUserPassword, password and SRP sign-in with the old password succeeded; they now return PasswordResetRequiredException. Contributed by @prandogabriel.Limit, every matching item came back in one response with no LastEvaluatedKey; a page now stops at 1 MB of data read and returns LastEvaluatedKey. Contributed by @DimQ1.Query read every item in the table and every write recounted it; index partitions and ItemCount are now kept per write. Contributed by @DimQ1.ClientRequestToken expires after 10 minutes. transaction tokens were kept forever; after 10 minutes a reused token is a new request. Contributed by @DimQ1.AUTH=true, TransactWriteItems and TransactGetItems were checked as non-existent IAM actions on the first table; each item is now checked as PutItem, UpdateItem, DeleteItem, ConditionCheckItem or GetItem on its own table. Contributed by @drakeo338. Reported by @Zordrak.MODIFY record, and a disabled or deleted stream vanished. No record is written now, and a closed stream stays readable for 24 hours as DISABLED. Contributed by @DimQ1.DescribeEndpoint hosts. https://<endpointAddress> failed hostname verification under USE_SSL=1; the certificate now carries the IoT data and credentials hosts. Contributed by @iot-rocket.SubscribeToShard keeps its position across retention pruning. removing expired records could skip newly appended ones. Contributed by @AdrianAcala.invoked_function_arn keeps the alias or version invoked. Contributed by @jayjanssen.CreateGlobalCluster dropped Tags; they are now stored and returned in TagList. Contributed by @jayjanssen.generatedFields. it was always empty; it now holds the AUTO_INCREMENT id. Contributed by @skialpine.FAILED; it is now found in its owner's account, and its bucket policy must grant the replication role. Contributed by @pingedbrain.BucketAlreadyOwnedByYou (409). Contributed by @DimQ1.Content-Length or a malformed aws-chunked upload was stored as a partial object; it now returns IncompleteBody (400). Contributed by @DimQ1.SendEmail validation. an address without a domain returns InvalidParameterValue "Missing final '@domain'", and an unknown configuration set returns ConfigurationSetDoesNotExist. Contributed by @DimQ1.SendRawEmail relay sends one Message-ID. a client Message-ID was kept next to MiniStack's. Contributed by @kjdev.MaxNumberOfMessages. FIFO queues ignored DelaySeconds and accepted per-message delays, and MaxNumberOfMessages was clamped. A FIFO message now waits the queue delay, a nonzero per-message delay returns InvalidParameterValue, and MaxNumberOfMessages outside 1–10 returns InvalidParameterValue. Contributed by @DimQ1.DelaySeconds applies to messages from other services. deliveries from SNS, EventBridge, S3 notifications and Lambda were visible at once. Contributed by @DimQ1.PutParameter validation. a parameter without Type, a name starting with aws or ssm, and Tags with Overwrite were accepted; they are now refused, and an overwrite without Type keeps the stored type. Contributed by @fabio-andre-rodrigues. Reported by @jin-gizmo.$$.State.RetryCount. it resolved to null; it now counts a state's retries, and a Task's Parameters are evaluated for each attempt. Contributed by @skialpine.MaxAttempts was skipped, so a later States.ALL retried anyway. Contributed by @skialpine.StopExecution keeps its error and cause. DescribeExecution returned neither; it now returns both. Contributed by @skialpine.StopExecution succeeds. stopping an already-aborted execution returned ValidationException; it now returns the original stopDate. Contributed by @jayjanssen.docker pull ministackorg/ministack:1.5.23 docker run -d -p 4566:4566 ministackorg/ministack:1.5.23
Or pin in compose.yaml:
services:
ministack:
image: ministackorg/ministack:1.5.23
ports:
- "4566:4566"
Issues and PRs welcome on GitHub. Discussion on r/ministack.