github ministackorg/ministack v1.4.3

12 hours ago

What's Changed

New Contributors

[1.4.3] — 2026-07-18

Added

  • IoT — device shadow operationsGetThingShadow, UpdateThingShadow, and DeleteThingShadow on the iot-data endpoint (classic and named shadows via ?name=) previously returned InvalidRequestException: Unsupported iot-data path: .../shadow. Shadows now store desired/reported state: updates deep-merge into the stored document (a null value removes the field), bump the version, and stamp per-attribute metadata timestamps (only the attributes an update touches are re-stamped); the /accepted response echoes only the sections sent, while GetThingShadow returns the full document including the computed state.delta and its metadata.delta. A stale version in an update is rejected with a 409, deleting a shadow keeps its version (as on real AWS, it is not reset), and reading or deleting a nonexistent shadow returns ResourceNotFoundException. Shadows are account-scoped and persisted with the rest of the IoT state. Contributed by @maximoosemine.
  • IoT — MQTT publishes are routed through topic rules to Lambda — an MQTT/iot-data publish is now matched against each account's topic rules by the rule's FROM '<topic filter>' clause (with +/# wildcards), and every matching enabled rule's lambda actions are invoked asynchronously with the message payload as the event (SELECT *). Basic Ingest is supported: a publish to $aws/rules/<ruleName> is delivered straight to that rule's actions and bypasses pub/sub. Disabled rules are skipped. Contributed by @maximoosemine.
  • API Gateway v2 — AWS::ApiGatewayV2::Authorizer CloudFormation support — deploying a stack with a JWT authorizer on an HTTP API previously failed with Unsupported resource type: AWS::ApiGatewayV2::Authorizer and rolled the stack back, even though the same authorizer already worked via the raw API and Terraform. A provisioner now maps the CFN properties onto the existing authorizer store (Ref returns the authorizer id, Fn::GetAtt AuthorizerId supported, per the CFN resource reference), and AWS::ApiGatewayV2::Route carries AuthorizerId/AuthorizationScopes through (previously dropped) so the route is actually enforced. Contributed by @ryan-bennett.

Changed

  • EventBridge, ECS, and Firehose — region-isolated state — continuing the multi-region work, three more services move their state to account+region scope: EventBridge (event buses, rules, targets, archives, replays, connections, API destinations, and endpoints; replays run under the region they were started in, and S3→EventBridge notifications dispatch in the bucket's region), ECS (clusters, task definitions and their revisions, services, tasks, capacity providers, account settings, and attributes), and Firehose (delivery streams, with Kinesis-source ingest kept within the stream's account and region). Same-name resources in different regions no longer collide, cross-region lookups return the same errors real AWS returns, and legacy persisted state migrates by recovering each record's region from its stored ARNs (ECS bumps its on-disk state format to v3). Contributed by @Areson.

Fixed

  • Cognito — ListUsers status filter matched against the wrong fieldFilter='status = "Enabled"'/"Disabled" was compared against UserStatus (the confirmation-state enum: CONFIRMED, FORCE_CHANGE_PASSWORD, UNCONFIRMED, etc.), which never equals the literal string "Enabled"/"Disabled". As a result, filtering by status always returned an empty list, regardless of how many users existed or their actual enabled/disabled state. status now correctly reflects the account's Enabled boolean toggled by AdminEnableUser/AdminDisableUser, matching real AWS Cognito's ListUsers Filter semantics. Contributed by @jey-mfv.
  • Cognito — PreTokenGeneration triggerSource reflects the call path — every issued token reported TokenGeneration_Authentication; refresh flows (REFRESH_TOKEN_AUTH and the /oauth2/token refresh_token grant) now send TokenGeneration_RefreshTokens, and the managed-login authorization_code grant sends TokenGeneration_HostedAuth, matching the trigger-sources table in the Cognito developer guide. Contributed by @kjdev.
  • Cognito — PreSignUp_ExternalProvider trigger fires on federated sign-up — SAML/OIDC federation callbacks persisted new users without ever invoking the pool's PreSignUp Lambda, which real Cognito always fires immediately before creating a federated user. The trigger now runs fail-closed (a throwing Lambda blocks the sign-up with UserLambdaValidationException and the user is never persisted), and its autoVerifyEmail/autoVerifyPhone overrides are applied to the created user. Federated users keep UserStatus: EXTERNAL_PROVIDER as on real AWS (autoConfirmUser does not change a federated user's status). Contributed by @kjdev.
  • EventBridge Pipes — cross-region source or target rejected — a pipe whose source or target ARN is in a different region than the pipe is now rejected before any state is written (surfaced through CloudFormation as CREATE_FAILED), matching AWS, where a pipe's source and target are same-region. Global and malformed ARNs are still accepted as before. Contributed by @Areson.
  • Lambda — Node warm-worker invoke no longer fails on fd 1 writesfs.writeSync / fs.write on stdout bypassed the existing process.stdout.write redirect to stderr, so sync loggers (e.g. pino with { sync: true }) could emit on the JSON-line protocol channel and surface false Runtime.HandlerError / Unknown error responses even when the handler succeeded. The Node worker bootstrap now redirects fd 1 through fs.writeSync / fs.write, and the warm-worker stdout reader accepts only protocol lines whose status is ok or error. Contributed by @vvaide. Reported by @kofuk.
  • Lambda — X-Amz-Log-Result honors LogType — the execution-log header was attached to every synchronous invoke; per the Invoke API reference it is returned only when LogType=Tail, carrying the last 4 KB of the execution log base64-encoded. Both now match. Contributed by @Sanjays2402. Reported by @w-zx.
  • Lambda — event source mappings pace failed-invoke retries per ESM — a failing ESM was retried at full poll-loop speed whenever another busy ESM kept the loop awake, and a burst on a healthy ESM was throttled to one batch per tick. The poll loop now keeps draining while work is being processed and each failing ESM backs off independently; failure semantics are unchanged (SQS messages redrive after the visibility timeout, stream shards retry the same batch). Contributed by @squirmy.
  • S3 — a versioned delete with an explicit VersionId permanently removes that versionDeleteObject and DeleteObjects addressed with a VersionId reported success but never touched the version store, so ListObjectVersions still returned every version and delete marker (DeleteObject even appended a new marker, driving the count up). Both paths now purge the exact version/marker and reconcile the current version; a delete without a VersionId still creates a delete marker as before. Contributed by @asleeponduty.
  • S3 — versioned object reads preserve Content-TypeGetObject with a VersionId always returned application/octet-stream, even when that version was written with an explicit content type. PutObject version records now retain their own content type, and versioned reads return it while preserving the existing fallback for older records. Contributed by @vvaide. Reported by @aaronsteed.
  • S3 — CreateBucket applies and validates request-body Tags — the <Tags> container in a CreateBucket body was ignored (only LocationConstraint was parsed), so tags supplied at creation were silently dropped and a follow-up GetBucketTagging returned NoSuchTagSet while S3 Control ListTagsForResource returned an empty list. Create-time tags are now stored and returned by both, validated before the bucket is created (key 1-128 chars, value 0-256, the reserved aws: prefix rejected with InvalidTag, at most 50 tags, and a duplicate key returns a 500 InternalError); an invalid tag set leaves no bucket behind. Contributed by @nirajsapkota.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.