github ministackorg/ministack v1.5.0

4 hours ago

What's Changed

New Contributors

[1.5.0] — 2026-08-23

Added

  • IAM — opt-in request authorization (AUTH=true) — with AUTH=true MiniStack evaluates the caller's IAM policies before serving a request and answers 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 — the access key only identifies the principal — so this is authorization, not authentication. Off by default (AUTH=false), leaving existing allow-all behavior unchanged.
  • Concurrency — a blocking handler no longer stalls concurrent requests — the request-serving event loop is captured at startup and blocking service work runs on worker threads, with a helper that lets a worker thread re-enter an async handler safely; work is routed by whether it needs to call back into the server. Contributed by @Areson and @iot-rocket.
  • CloudFront — SaaS Manager (multi-tenant distributions) — connection groups and distribution tenants provision with ETag / If-Match concurrency, per-tenant WAF association, tenant invalidations, and domain tooling. A tenant requires a tenant-only distribution (InvalidAssociation), CNAMEs are unique across tenants and distribution aliases (CNAMEAlreadyExists), deleting a distribution or connection group that still has tenants is refused (ResourceInUse / CannotDeleteEntityWhileInUse), and both families are taggable; async deploy, DNS and certificate workflows resolve immediately. Contributed by @mjdavidson.
  • EC2 — instances can have a real box behind them (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 instead of returning true for any id. Contributed by @iot-rocket.
  • SSM — Run CommandSendCommand, GetCommandInvocation, ListCommands and DescribeInstanceInformation returned InvalidAction. Invocations are now asynchronous as on AWS: SendCommand answers Pending and the caller polls to a terminal state, AWS-RunShellScript runs in the instance's container so Status reflects the real exit code, and an instance with no agent answering is refused InvalidInstanceId. Contributed by @bandle.
  • S3 — Glacier and Deep Archive restore (RestoreObject) — an object in the GLACIER or DEEP_ARCHIVE storage class is now unreadable until restored: 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 InvalidObjectState, as on AWS. Reported by @mbenja086.

Changed

  • Docker — the full image is smaller — unused payload trimmed from the full variant. Reported by @Areson.

Fixed

  • IAM — a CloudFormation-provisioned policy no longer breaks the read APIs — stack-created policies and attachments wrote shapes the IAM API never produced (AttachedPolicies as {PolicyName, PolicyArn} 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.
  • Lambda — Node.js ESM handlers using top-level 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.
  • Cognito — 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 are now matched 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.
  • DynamoDB — an UpdateExpression alias is resolved before the key-attribute checkset #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.
  • RDS — 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.
  • S3 — a conditional delete of a key with no current object answers 404DeleteObject 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. Reverted and fixed from 1.4.21.
  • S3 — one canonical owner ID across every S3 APIListBuckets, 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.
  • EC2 — 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 with an opt-in-not-required status.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.