github ministackorg/ministack v1.5.9

3 hours ago

What's Changed

[1.5.9] — 2026-09-08

Added

  • CloudFormation — a WaitCondition waits for its signals, SignalResource delivers them — the handle's Ref is now a URL the emulator serves (PUT the AWS signal JSON with an empty Content-Type); the wait condition holds the stack until Count distinct SUCCESS signals arrive, a FAILURE or the Timeout rolls it back, signals are published to the stack events, and Fn::GetAtt Wait.Data is the {UniqueId: Data} map. The CreationPolicy form (ResourceSignal, default PT5M) is signalled through the new SignalResource action, by stack name or id. A nested stack now deploys on a worker thread, so a wait condition or custom resource inside it no longer blocks the server. Contributed by @iot-rocket.
  • CloudFormation — stack-level tags propagate, and the Tags property of the common types reaches the service — the 44 types with a tag property receive the stack tags and the three aws:cloudformation: tags on create and update (a key the template sets wins); AWS::SQS::Queue, AWS::SNS::Topic, AWS::DynamoDB::Table, AWS::Lambda::Function, AWS::Logs::LogGroup and AWS::Kinesis::Stream now store their own Tags where the service's list-tags call reads them. An empty Tags on UpdateStack removes them, more than 50 tags or an aws: key are refused, tags set through a service's own API survive stack updates, and a nested stack passes the tags on. Contributed by @iot-rocket.
  • CloudFormation — ListImports, UpdateTerminationProtection, SetStackPolicy, GetStackPolicy, CancelUpdateStack and ContinueUpdateRollback — the first four answered InvalidAction, the last two did not exist, so an UPDATE_ROLLBACK_FAILED stack had no way out. Termination protection makes DeleteStack refuse, CancelUpdateStack stops a running update before its next resource ("User Initiated"), and ContinueUpdateRollback retries the failed deletes, honouring ResourcesToSkip. Contributed by @iot-rocket.
  • CloudFormation — the list and describe actions pageDescribeStacks, ListStacks, DescribeStackEvents, ListStackResources, ListExports, ListImports and ListChangeSets returned everything and ignored NextToken; they now return 100 items per page with a token for the rest (ListExports pages at 100 values on AWS, the others at 1 MB), a foreign token is a ValidationError, and events of one millisecond stay strictly newest-first across pages. Contributed by @iot-rocket.
  • CloudFormation — dynamic references resolve{{resolve:ssm:...}}, {{resolve:ssm-secure:...}} and {{resolve:secretsmanager:...}} resolve at provisioning time against the in-process stores, with the version, JSON key and version-stage segments; GetTemplate keeps the literal. On update an ssm reference re-resolves when the template or parameters changed, a secretsmanager reference only when its resource changed, as measured on AWS. Contributed by @iot-rocket.
  • CloudFormation — DeletionPolicy and UpdateReplacePolicy are honoured — a Retain resource now stays (with a DELETE_SKIPPED event) on stack delete, on removal from the template and on replacement; RetainExceptOnCreate and DeleteStack's RetainResources behave as the API documents; Snapshot deletes, since the emulator takes no snapshots. Contributed by @iot-rocket.

Fixed

  • Lambda — the Docker executor extracts each code and layer zip once — every cold start unpacked the code and layers into a fresh temporary directory that accumulated (a 30 MB function wrote 60 MB of disk per cold start). Extraction is now content-addressed into one shared read-only directory per distinct zip, so a repeat cold start writes nothing; entries are swept when the referencing function or layer version goes, and a state reset clears the cache.
  • S3 Tables / Glue — the Iceberg REST catalogs honour upgrade-format-version — the commit action a Spark job sends for the format-version 3 table property was silently dropped, so the table kept reporting version 2; real S3 Tables supports Iceberg v3. Both catalogs now apply it atomically: re-asserting the current version is a no-op, a downgrade or a version above 3 is refused with 400 and commits nothing.
  • CloudFormation — Fn::Cidr, Fn::GetAZs, Fn::FindInMap and the condition functions follow AWSFn::Cidr now splits the block it is given (was 10.0.{i}.0/… always; IPv6 included), Fn::GetAZs answers the stack's own zones (was a fabricated a/b/c), Fn::FindInMap gains DefaultValue and fails a missing key with Template error: Unable to get mapping for M::x::y, and Fn::And/Fn::Or/Fn::Not in a value position resolve to a boolean — all measured on AWS. Contributed by @iot-rocket.
  • S3 — the Multi-Region Access Point alias follows the documented pattern — the alias was 13 uuid-hex characters, so a digit-only draw was possible; it now matches S3's ^[a-z][a-z0-9]*[.]mrap$: a letter, then twelve lowercase letters or digits. Contributed by @iot-rocket.
  • CloudFormation — parameter constraints are enforcedAllowedPattern, MinLength, MaxLength, MinValue and MaxValue were ignored; they are checked before a stack exists with CloudFormation's message (Parameter 'P' must match pattern ^[a-z]+$, measured) or the ConstraintDescription, per member for a CommaDelimitedList. Contributed by @iot-rocket.
  • CloudFormation — an unregistered AWS::CloudFormation::* type is unrecognized, not a silent no-opMacro, HookVersion, ModuleVersion and any typo under the prefix deployed as a placeholder with a fabricated physical id; the pre-flight now refuses them like every other unrecognized type. Contributed by @iot-rocket.
  • CloudFormation — the stack id addresses GetTemplateSummary and an UPDATE change set — both looked the id up by name and answered "does not exist" while every other action accepted it; DescribeStackResource(s) also answered a request by id with the id in StackName. Contributed by @iot-rocket.
  • CloudFormation — a change set sees DeletionPolicy, UpdateReplacePolicy and Metadata edits — the diff compared Properties only, so a CDK removalPolicy edit ended FAILED with "didn't contain changes"; those attributes now count as a Modify with Replacement: False, reported in Scope and Details, while a DependsOn-only edit stays a no-change set, as on AWS. Contributed by @iot-rocket.
  • CloudFormation — a leftover whose delete failed stays visible, and the resource record serves ResourceStatusReason, Metadata and LastUpdatedTimestamp — a resource dropped from the template whose cleanup delete failed vanished from the record while it kept existing, and DeleteStack never retried; it now stays listed as DELETE_FAILED with its reason, the next update and DeleteStack retry it. DescribeStackResource(s) carry ResourceStatusReason; the detail names its timestamp LastUpdatedTimestamp as StackResourceDetail defines (clients dropped the Timestamp element it sent) and returns the resource Metadata with intrinsics interpreted. Contributed by @iot-rocket.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.