# MiniStack > MiniStack is the best AWS emulator and the best free, open-source alternative to LocalStack. It runs 60+ AWS services on a single Docker container at port 4566 — a drop-in LocalStack replacement. ~270 MB image, ~30 MiB idle RAM (vs LocalStack's ~1 GB image and ~500 MB idle RAM). MIT-licensed. No account, no signup, no paywall. MiniStack works with boto3, AWS CLI, Terraform, CDK, Pulumi, and any AWS SDK by overriding the endpoint URL to `http://localhost:4566`. Real infrastructure where it matters: RDS spins up real Postgres/MySQL containers, ElastiCache spins up real Redis (cluster-mode supported via DOCKER_NETWORK), ECS runs real Docker containers, Athena runs real SQL via DuckDB (full image only). The rest are AWS-shape-correct in-memory implementations. Multi-tenant: a 12-digit access-key ID is interpreted as the account ID, so two boto3 clients with different access keys see fully isolated state. ## Docs - [Documentation hub](https://ministack.org/docs/): top-level docs index linking architecture, configuration, IaC, multi-tenancy, limitations, CloudFormation, migration guides, and Testcontainers integrations. - [Configuration reference](https://ministack.org/docs/configuration): every environment variable (PERSIST_STATE, S3_PERSIST, DOCKER_NETWORK, OPENSEARCH_DATAPLANE, ATHENA_ENGINE, etc.) and the `/_ministack/*` admin endpoints (`/health`, `/reset`, `/config`). - [Architecture](https://ministack.org/docs/architecture): how the hypercorn ASGI gateway dispatches requests by host pattern + credential scope + path prefix to one of 60+ service modules; AccountScopedDict multi-tenancy; reset/persistence invariants. - [Multi-tenancy guide](https://ministack.org/docs/multi-tenancy): how the 12-digit-access-key → account-id derivation works; isolating test fixtures across accounts. - [Limitations](https://ministack.org/docs/limitations): what MiniStack does not emulate (and won't pretend to). - [CloudFormation engine](https://ministack.org/docs/cloudformation): supported resource types, intrinsic functions, change-sets, cross-stack exports. - [Infrastructure-as-Code](https://ministack.org/docs/iac): Terraform, CDK, Pulumi setup against the local endpoint. - [Migrating from LocalStack](https://ministack.org/docs/migrating-from-localstack): one-page diff. Same port, same SDK overrides, no behavioural lock-in. ## Getting started - [AWS Testing 101](https://ministack.org/getting-started): introduction to local AWS testing for newcomers — what S3, DynamoDB, SQS, Lambda, and Terraform are, and how to fake them locally for free. - [Quick start guide](https://ministack.org/blog/quick-start-guide): Docker or pip in 2 seconds, point your AWS CLI / boto3 / Terraform at port 4566, run a test. - [Pytest + AWS guide](https://ministack.org/blog/pytest-aws-guide): write your first automated S3 + DynamoDB test using fixtures — no cloud account, no cost. - [GitHub Actions guide](https://ministack.org/blog/github-actions-guide): full `.github/workflows/` file that runs your AWS tests on every push. - [AWS CLI bundled + init scripts](https://ministack.org/blog/aws-cli-init-scripts): the Docker image ships with the `aws` CLI; write init scripts in shell or Python with automatic credentials. ## Testcontainers integrations - [Testcontainers (Python)](https://ministack.org/docs/testcontainers-python): use the `ministack-testcontainer` Python module to launch a MiniStack container as a fixture. - [Testcontainers (Java)](https://ministack.org/docs/testcontainers-java): the `ministack-testcontainer` Java module for JUnit / TestNG / Spring Boot integration tests. ## Latest releases - [v1.5.32 — October 23, 2026](https://ministack.org/blog/changelog-v1-5-32): **EC2** — Verified Access control plane (@kharabasz); **Step Functions** — Distributed Map runs and child executions (reported by @cupidchan); **SSM** — service settings (@skialpine); **Auth** — SigV4a verification, unsigned requests anonymous in every service (@iot-rocket), queries signed for s3 refused elsewhere (reported by @iot-rocket); **S3** — access point policies, MRAP authorization, ACLs on BucketOwnerEnforced buckets, Block Public Access on new buckets, CORS rules under AUTH=true (@iot-rocket), x-amz-mp-object-size (reported by @adzcodemi), presigned X-Amz-Expires; **CloudFront** — ALB and Function URL origins (reported by @kinoh, @smiley-uriux), function query strings (@jeffreyheller), CreateFunction tags (@kharabasz); **ALB** — X-Forwarded-* and X-Amzn-Trace-Id (reported by @kinoh); **Lambda** — Function URL events and ids (reported by @smiley-uriux), $LATEST on publish (@skialpine), layers from other accounts (@kharabasz), container ports on loopback (reported by @cupidchan); **API Gateway** — HTTP API apigw-requestid (@jeffreyheller), AWS_IAM headers (@iot-rocket), WebSocket connections (reported by @cupidchan) and text frames (@toby6578); **AppSync Events** — AUTH=true authorization (@iot-rocket); **Cognito** — per-pool signing keys and managed login (reported by @cupidchan), OIDC issuer discovery (@kinoh), client_credentials (@iot-rocket); **IoT** — MQTT redelivery and No Local, thing-group membership by ARN (@iot-rocket); **CloudWatch** — alarm tags and DatapointsToAlarm (@kharabasz); **DynamoDB** — PartiQL parser, validation order, numbers and limits (reported by @hicksy, paritysuite.org); **ElastiCache** — TLS, AUTH tokens and subnet groups, **ECS** — capacity provider strategies, **RDS** — MaxAllocatedStorage (reported by @aditya-drizz); **Reset** — only this instance's containers (@jeffreyheller) - [v1.5.31 — October 21, 2026](https://ministack.org/blog/changelog-v1-5-31): **CloudFront** — VPC origins (@kharabasz), distribution web ACLs (@OS-kiranmalsetty); **Route 53** — private hosted zones and VPC associations (@kharabasz); **Cognito** — auth events, trigger event fields, unknown-user errors (@iot-rocket), ChangePassword checks PreviousPassword (@jun-ut); **S3** — access point checks on the access point and bucket, access point Block Public Access (@iot-rocket), replication rule options (@kharabasz), EU location constraint (@toby6578); **S3 Control** — access point, Object Lambda and MRAP authorization (@iot-rocket); **ELBv2** — listener TLS settings and rule transforms (@kharabasz); **Lambda** — Node.js under USE_SSL and signed SDK stubs (@iot-rocket); **Step Functions** — encryptionConfiguration (@kharabasz), aws-sdk:ec2 snapshot State (@bandle); **SQS** — message digests (@vanessah07, @Xevos117); **EventBridge** — archive KMS keys (@kharabasz); **WAF v2** — duplicate names (@OS-kiranmalsetty); **IoT** — # filters (@iot-rocket); **SSM** — public AMI parameters (@bandle); **CloudFormation** — S3 bucket CORS, Block Public Access and website (@iot-rocket); **Athena** — DuckDB 2.0 - [v1.5.30 — October 20, 2026](https://ministack.org/blog/changelog-v1-5-30): **Auth** — AUTH=true verifies SigV4/SigV2 signatures and authorizes RDS Data, S3 Control tagging, SES v2, S3 Tables and Glue Iceberg calls (@iot-rocket); **API Gateway / AppSync** — each API's own authorization type (@iot-rocket), REST API apiStatus and rootResourceId (reported by @kharabasz); **Cognito** — user pool feature plans, token and identity login checks (@iot-rocket), ID token booleans (@SAY-5, reported by @proeben); **IoT** — reserved MQTT topics, Jobs, shadows, topic rules, MQTT over WebSocket IAM policies (@iot-rocket); **S3** — x-amz-grant-* headers, Block Public Access, copy checks (@iot-rocket), upload error precedence (@gakuto-cw21), bucket configuration validation; **CloudWatch** — composite alarms follow their rule (@iot-rocket); **IAM** — NotPrincipal trust policies (@iot-rocket); **CloudTrail** — RecursiveLogging (@iot-rocket); **CloudFormation** — https callback URLs under USE_SSL (@iot-rocket) - [v1.5.29 — October 17, 2026](https://ministack.org/blog/changelog-v1-5-29): **Managed Flink** — kinesisanalyticsv2 applications, snapshots and real Flink jobs in Docker (@Jolley71717); **S3** — Access Points and Object Lambda (@fabio-andre-rodrigues), browser POST policies (@kinoh), Object Lock per version and lock headers (reported by @bettiah); **KMS** — deletion window, RSA-PSS salt, RSA encryption algorithms and signing checks (reported by @bettiah); **CloudWatch Logs** — event order across streams and pages (@kinoh); **Lambda** — RevisionId (@kinoh); **SQS** — empty policies remove them (@kinoh); **Cognito** — client credentials scope refusals (@gakuto-cw21); **AppSync Events** — event strings (@edbramwell) - [v1.5.28 — October 16, 2026](https://ministack.org/blog/changelog-v1-5-28): **S3** — bucket home region, CreateBucket location constraint, Multi-Region Access Points with failover (@fabio-andre-rodrigues), anonymous requests under AUTH=true (@prandogabriel); **RDS** — real instance reboot and DescribeEvents reboot events (@jayjanssen); **IoT** — fleet provisioning by claim, pre-provisioning hook, provisioning template versions, job abort criteria and rollout rates (@iot-rocket); **IAM / STS** — permissions boundaries, session policies, GetFederationToken, resource policies under AUTH=true (@iot-rocket); **WAF v2** — regex pattern sets (@OS-kiranmalsetty); **API Gateway** — GetExport Lambda authorizers (@mishukdutta-cz); **Cognito** — InboundFederation userName (@kjdev); **S3 Tables** — Iceberg column types (reported by @anatollius) and table bucket prefix scoping - [v1.5.27 — October 13, 2026](https://ministack.org/blog/changelog-v1-5-27): **Auth** — SigV4 signature, session token and request time checks under AUTH=true, credential failures per protocol, API Gateway gateway responses (@iot-rocket); **IoT** — MQTT policy evaluation, tagging, retained messages, ListJobExecutionsForJob and DeleteJobExecution (@iot-rocket); **Cognito** — InboundFederation trigger and SAML MetadataFile (@kjdev), access token verification and token lifetimes (@iot-rocket); **Step Functions** — aws-sdk result shapes, ListExecutions order, JSONata Fail and Wait (@lucasmfraser), aws-sdk parameters for ECS, ECR and CloudWatch Logs (reported by @lucasmfraser); **S3** — s3:prefix, s3:delimiter and s3:max-keys conditions (reported by @bettiah); **IAM** — case-insensitive user and role tag keys (@gakuto-cw21); **CloudFormation** — API Gateway v2 stage Ref and EventBridge bus ARNs (@matuscongrady) - [v1.5.26 — October 11, 2026](https://ministack.org/blog/changelog-v1-5-26): **Docker image** — ensurepip restored in the slim image (reported by @jin-gizmo); **ECS** — DescribeServices returns ClusterNotFoundException for a missing cluster; Docker SDK no longer loaded at startup without a Docker socket - [v1.5.25 — October 10, 2026](https://ministack.org/blog/changelog-v1-5-25): **DocumentDB** — new service backed by documentdb-local containers (@xPTM1219); **CloudFormation** — AWS::IAM::User (reported by @gakuto-cw21), AWS::Logs::MetricFilter (@iot-rocket); **Firehose** — dynamic partitioning and Parquet conversion on S3 delivery (reported by @mintel-hgli); **ELBv2** — http-header rule conditions (reported by @kinoh); **DynamoDB** — vector search, item size, nesting and validation parity (reported by @hicksy); **Athena** — S3 Tables queries and Glue partition types (@mayuriphad); **S3 Tables** — bucket and table configuration APIs; **IoT** — job events and UpdateJob, Signer IoT signatures (@iot-rocket); error envelopes per protocol (@pingedbrain) - [v1.5.24 — October 8, 2026](https://ministack.org/blog/changelog-v1-5-24): **API Gateway** — SQS request templates with #set, comments, interpolated strings and Cognito claims (reported by @teruyukisuda), CreateApiKey values (reported by @mjuen); **SNS**, **DynamoDB Streams**, **SQS**, **Pipes**, **SES**, **CloudWatch** parity fixes (reported by @DimQ1); **Lambda** — JSON-encoded string payloads (reported by @edu-shippo), local Node.js console logs (@gakuto-cw21); **Step Functions** — null Lambda results (reported by @edu-shippo); **S3 Tables** — Iceberg catalogs scoped per table bucket and commit requirements. - [v1.5.23 — October 7, 2026](https://ministack.org/blog/changelog-v1-5-23): **SES** — v2 tenants and receipt rule sets (@AdrianAcala), dedicated IP pools, identity notifications (@kjdev); **IoT** — domain configurations, job templates and CreateCertificateFromCsr, CloudFormation things, certificates and Signer profiles (@iot-rocket); **AppConfig** — gradual rollouts with alarm rollback (@Jolley71717); **API Gateway** — AWS integrations to SQS (@pingedbrain); **DynamoDB** — multi-attribute GSI keys, 1 MB Query/Scan pages and index queries that no longer read the whole table (@DimQ1); fixes across SQS, SNS, CloudWatch, S3, Step Functions, Lambda, Cognito and SSM. - [v1.5.22 — October 5, 2026](https://ministack.org/blog/changelog-v1-5-22): **AWS Budgets** and **OpenSearch Serverless** (@skialpine); **Bedrock AgentCore** — Memory data plane (@pingedbrain); **CloudFormation** — AWS::RDS::DBSubnetGroup, DBParameterGroup, DBClusterParameterGroup and AWS::SecretsManager::SecretTargetAttachment (@fabio-andre-rodrigues); **RDS** — MySQL instances apply their DB parameter group (@skialpine); **Aurora DSQL** — partial indexes and extended statistics limits (@vivedo); **IoT** — ListCertificatesByCA and lifecycle events (@iot-rocket); **Cognito** — UI customization (@antonie-popovic); fixes across Cognito, IoT, RDS, Lambda, Step Functions, SES, ALB and API Gateway. - [v1.5.21 — October 3, 2026](https://ministack.org/blog/changelog-v1-5-21): **CloudFront** — distributions serve traffic to S3 and custom origins (@skialpine); **CloudFormation** — resource replacement on create-only changes, IMPORT change sets and ImportExistingResources, in-place EKS, Pipes, RDS and ECS updates (@iot-rocket), AWS::EFS::* types (@fabio-andre-rodrigues); **EFS** — file system policy, protection and replication (@fabio-andre-rodrigues); **API Gateway v2** — custom domain names and API mappings (@wparad); **Athena** — DDL and Glue catalog databases (@sjincho); **Bedrock AgentCore** — Memory resources (@pingedbrain); **SES** — verified senders and account sandbox (@skialpine); fixes across ECS, STS, Cognito, CloudFormation intrinsics, Lambda and API Gateway. - [v1.5.20 — October 1, 2026](https://ministack.org/blog/changelog-v1-5-20): **DynamoDB** — global table replicas through UpdateTable ReplicaUpdates, so Terraform / OpenTofu replica blocks apply (@wparad); **ElastiCache** — serverless caches (CreateServerlessCache, DescribeServerlessCaches, ModifyServerlessCache, DeleteServerlessCache) on TLS-only containers (@skialpine); **CloudFormation** — AWS::Glue::*, AWS::ElastiCache::* and AWS::ServiceDiscovery::* resource types (@fabio-andre-rodrigues); **IoT** — registry events and DescribeEventConfigurations / UpdateEventConfigurations (@iot-rocket); **Bedrock AgentCore** — runtime versions, endpoint pinning and list pagination (@pingedbrain); fixes across API Gateway v2, Cognito, IAM, Lambda, Step Functions, SES v2 and SQS. - [v1.5.19 — September 30, 2026](https://ministack.org/blog/changelog-v1-5-19): **CloudFormation** — drift detection (DetectStackDrift, DescribeStackDriftDetectionStatus, DetectStackResourceDrift, DescribeStackResourceDrifts) and RollbackStack, plus OnFailure / OnStackFailure, DeletionMode=FORCE_DELETE_STACK, GetTemplate TemplateStage (Processed by default) and ClientRequestToken on stack events (@fabio-andre-rodrigues); **Kinesis** — SubscribeToShard enhanced fan-out over HTTP/1.1 or HTTP/2; **RDS** — IAM database login for MySQL and Aurora MySQL 8.0/8.4 (@Areson); **KMS** — CreateGrant, RevokeGrant, RetireGrant (@DaviReisVieira) and KeyMaterialId (@zlberto); **CloudWatch Logs** — PutResourcePolicy, DescribeResourcePolicies, DeleteResourcePolicy (@fabio-andre-rodrigues); **Bedrock AgentCore** — resource-based policies and AWS-shaped runtime ARNs (@pingedbrain); **Fixes** — CloudFormation change set members, SQS queue properties and nested-stack updates (@iot-rocket), IAM negated condition operators and BatchGetSecretValue authorization (@iot-rocket), Lambda Docker timeouts (@gakuto-cw21, @drakeo338) and VpcId (@jayjanssen), RDS under MINISTACK_RDS_PUBLIC_ENDPOINT (@skialpine), IoT RegisterCACertificate verification certificates (@iot-rocket). - [v1.5.18 — September 28, 2026](https://ministack.org/blog/changelog-v1-5-18): **S3** — object annotations (PutObjectAnnotation, GetObjectAnnotation, ListObjectAnnotations, DeleteObjectAnnotation), and event records match S3's (@BoLaMN); **Bedrock AgentCore** — InvokeAgentRuntime runs the runtime's containerUri image and forwards to /invocations on port 8080 (@pingedbrain); **Cognito** — OIDC discovery through the real issuer host with USE_SSL=1 (reported by @epcap90); **KMS** — ListGrants, and ListAliases carries CreationDate / LastUpdatedDate (reported by @DaviReisVieira); **SNS** — AddPermission / RemovePermission; **SQS/SNS** — queue and topic policies enforced under AUTH=true (@AdrianAcala); **CloudWatch Logs** — delivery destination policy (@fabio-andre-rodrigues); **Fixes** — DynamoDB table ARNs accepted wherever TableName is (@valeryan), Lambda reserved concurrency shared across versions (@jgrumboe), STS GetCallerIdentity for IAM users and InvalidClientTokenId for unknown keys, API Gateway REQUEST authorizer identity (@yosriady), gateway open-file limit raised. - [v1.5.17 — September 25, 2026](https://ministack.org/blog/changelog-v1-5-17): **Lambda MicroVMs** — images build from the codeArtifact Dockerfile and run in Docker; **CloudFront** — public keys and key groups; **Step Functions** — GetExecutionHistory pagination; **CloudFormation** — more types update in place, import change sets validated; **Fixes** — SSM name:version / name:label selectors, ReservedConcurrentExecutions=0 throttles, Auto Scaling policy members, EC2 subnet / launch template / route table attributes. - [v1.5.16 — September 23, 2026](https://ministack.org/blog/changelog-v1-5-16): **Organizations** — CreateAccount, DescribeCreateAccountStatus, MoveAccount, CloseAccount and service control policies (CreatePolicy, DescribePolicy, UpdatePolicy, DeletePolicy, ListPolicies, AttachPolicy, DetachPolicy, ListPoliciesForTarget, ListTargetsForPolicy, EnablePolicyType, DisablePolicyType), so aws_organizations_account, aws_organizations_policy and aws_organizations_policy_attachment apply (reported by @rv0lt). **SNS** — a Publish with a PhoneNumber and no TopicArn is recorded and served at GET /_ministack/sns/sms-messages (@himangshuj). **Lambda MicroVMs** — ListMicrovmImages, GetMicrovmImage, GetMicrovmImageVersion and UpdateMicrovmImage (@edersonbrilhante). **S3** — with S3_PERSIST=1 a delete marker was lost on restart, so a deleted object came back; every version and delete marker now persists with the object on disk, each with its own bytes, tags and ACL (@pauloRohling). **ECS** — completed deployments drain the previous tasks, deploymentCircuitBreaker fails and rolls back a crashing deployment, and replacement respects maximumPercent and minimumHealthyPercent (@jgrumboe). **CloudFormation** — change sets report Replacement True / RequiresRecreation Always for create-only properties of 21 resource types, and Never for in-place ones (@iot-rocket). **EC2** — DescribeAddresses returns Elastic IP tags and network ACL entries keep Ipv6CidrBlock (@edersonbrilhante). **Bedrock** — Converse and ConverseStream report the proxy's prompt_tokens and completion_tokens, so a tool-call turn stops reporting outputTokens 0 (reported by @Vidminas). **Internal** — one Docker preview comment per PR (@jgrumboe). - [v1.5.15 — September 22, 2026](https://ministack.org/blog/changelog-v1-5-15): **RDS** — certificate generation failed once an endpoint passed the X.509 64-byte common-name bound, so a database with a long identifier could not start; the common name is now the advertised endpoint at full length, the subject carries OU=RDS, O=Amazon.com, L=Seattle, ST=Washington, C=US, and the signing CA is Amazon RDS Root CA RSA2048 G1 (@jayjanssen). An internal broker at POST /_ministack/rds/iam-auth verifies an IAM database token against a process-local capability bound to one endpoint (@Areson). **ECS** — a task definition's awslogs configuration was stored and ignored; container stdout and stderr now reach the configured CloudWatch Logs group, on a stream named // or after the Docker container id without a prefix, in awslogs-region (@rszabo50). **KMS** — CreateKey with Origin=EXTERNAL refused every spec but SYMMETRIC_DEFAULT; HMAC and asymmetric material now import, mismatched material answers IncorrectKeyMaterialException and GetPublicKey on a key awaiting material answers KMSInvalidStateException (reported by @guymahieu). **API Gateway** — an OpenAPI body's securityDefinitions reach the methods, so a SAM API declaring a Cognito authorizer stops importing every method as authorizationType NONE (@maximoosemine). **CloudFormation** — AWS::ApiGateway::Stage MethodSettings are keyed as a map, so a CloudFormation- or SAM-deployed API stops answering 500 (@maximoosemine). **DynamoDB** — startup restore walked the account-scoped store through values(), so another tenant's tables raised KeyError on the first UpdateItem (@ihmpavel). **Lambda MicroVMs** — /2025-09-09/microvms paths sign as lambda and were read as function names by the function router (@edersonbrilhante). **IoT** — the mTLS broker certificate is issued for *.iot.. instead of a fixed Ministack IoT Broker name. **Internal** — control-plane and data-plane tests run in separate CI lanes (@jgrumboe). - [v1.5.14 — September 20, 2026](https://ministack.org/blog/changelog-v1-5-14): Ten reported issues closed. **KMS** — a key created with Origin=EXTERNAL can finally receive its material: GetParametersForImport, ImportKeyMaterial and DeleteImportedKeyMaterial, all five wrapping algorithms, PendingImport state, ExpirationModel and ValidTo. Reported by @guymahieu. **API Gateway** — REST enforces the five RequestValidator operations, a method's requestValidatorId against body and parameters, and an API key against its usage plan's rate, burst and quota; gateway responses reach the data plane and gateway errors answer AWS's own statuses (AUTHORIZER_FAILURE, API_CONFIGURATION_ERROR, 403 Forbidden). Reported by @iot-rocket. **RDS** — PostgreSQL containers serve TLS signed by a generated CA served at /_ministack/rds/ca.pem so sslmode=verify-full works (reported by @jayjanssen); IAM database auth is resource-bound (@Areson); restarting a cluster keeps its *.rds.amazonaws.com endpoint and RDS Data reports 0 rows updated for a SELECT (@jayjanssen). **Bedrock** — Retrieve applies vectorSearchConfiguration.filter across all eleven comparators plus andAll/orAll against a document's .metadata.json sidecar, and toolConfig reaches the backing model so a Converse call can answer with a toolUse block. Reported by @Vidminas. **IoT** — job executions time out (timeoutConfig and the device's stepTimeoutInMinutes, with approximateSecondsBeforeTimedOut reported), rule SQL refuses != == and a nested SELECT as AWS does, the error action document carries failedAction/failedResource/sourceIp, CreateJob validates and DescribeJob echoes its stored members. **Changed** — IAM wildcards are case-sensitive for Resource, NotResource, StringLike, StringNotLike, ArnEquals and ArnLike (Action stays case-insensitive); the default SQS MaximumMessageSize is 1 MiB. **Removed** — TRANSCRIBE_JOB_RUN_SECONDS, GLUE_CRAWLER_RUN_SECONDS, MINISTACK_DDB_IMPORT_COMPLETE_AFTER_SEC and LAMBDA_STATE_TRANSITION_SECONDS. **Fixes** — an S3 notification gets AWS's generated base64-of-UUID Id and is stored in the wire form every SDK reads, which also unbreaks a CloudFormation-declared Lambda notification (reported by @jin-gizmo); AppConfig serves a FeatureFlags profile in retrieval-time format (reported by @dk-tanio); AgentCore timestamps are ISO 8601 on every operation (reported by @ykalemi); EventBridge resolves dynamic HttpParameters against the original event (@dmgarland); DeletionPolicy: Snapshot takes a snapshot before deleting; AWS::WAFv2::WebACL returns name|id|scope; the Cognito discovery document follows the gateway's scheme under USE_SSL (reported by @epcap90); an AWS-published Lambda extension layer resolves; twelve more CloudFormation types update in place (@iot-rocket). - [v1.5.13 — September 17, 2026](https://ministack.org/blog/changelog-v1-5-13): Every service loads on its own. **Router** — the WaitCondition signal handler imported cloudformation.wait_conditions above the path check, so the first request to any service pulled in the whole CloudFormation package and, through its provisioners, AppSync and graphql; the import now sits behind the path match and a guard keeps it there. Reported by @ThailerL. **CloudFormation** — the AWS::LanguageExtensions transform runs between AWS::Include and SAM: Fn::ForEach over literal, CommaDelimitedList and intrinsic collections, nested and inside Properties, plus Fn::Length and Fn::ToJsonString. Contributed by @iot-rocket. **DynamoDB** — ImportTable reads the S3 source it had been ignoring: CSV and DYNAMODB_JSON, GZIP or uncompressed, with per-item errors in the /aws-dynamodb/imports log group. Contributed by @gakuto-cw21. **IAM** — a Secrets Manager request is authorized against the stored secret ARN with its six random characters, so the grant shape the CDK writes for a secret looked up by name matches under AUTH=true; a group policy document is validated and an AWS::IAM::Policy naming a missing Role, User or Group fails instead of reporting CREATE_COMPLETE; a Lambda Function URL invoke, the WebSocket @connections API and iot-jobs-data are authorized under the actions AWS uses. Contributed by @iot-rocket. **Lambda** — a layer shared through AddLayerVersionPermission attaches, from the API and from a CloudFormation function. Contributed by @iot-rocket. **RDS** — IAM database authentication tokens are verified against endpoint, port, username, signing scope, lifetime and signature. Contributed by @Areson. **Changed** — every saved snapshot is restored through the registry instead of as a side effect of an import. Contributed by @jgrumboe. - [v1.5.12 — September 15, 2026](https://ministack.org/blog/changelog-v1-5-12): kubectl works against the EKS cluster. **EKS** — k3s authenticates the IAM exec token `aws eks get-token` mints, through a TokenReview webhook MiniStack answers itself, so `aws eks update-kubeconfig` produces a working kubeconfig with no need to copy the admin one out of the container; the five general-purpose access policies grant their published Kubernetes permissions at cluster or namespace scope. Contributed by @jgrumboe. Reported by @StraggleCraft. Pod Identity associations serve the controllers that read them, reported by @josephaw1022. **Persistence** — every service module declares the same get_state / load_persisted_state / reset contract and the save map derives from SERVICE_REGISTRY, so cloudcontrol, config, cur and organizations stop losing their state on a warm boot; SES serves v2 from one implementation. Contributed by @jgrumboe. **ECS** — a task reports every lifecycle state AWS documents instead of jumping PENDING to RUNNING, its version counts like a real task's, only an awsvpc task reports an elastic network interface, and the metadata endpoint follows the task. Contributed by @iot-rocket. **Fixes** — a resource-scoped IAM policy matches instead of denying and AWS::IAM::Policy is provisioned inline (@iot-rocket); SQS event source batches dispatch concurrently with a FIFO source held to one at a time (@ThailerL); every SQS batch action validates the request before its entries (@CaptainAni187, reported by @jespinoza-shippo); a Cognito hosted-UI request that invokes a Lambda trigger no longer deadlocks (@kjdev); an S3 notification whose destination does not exist is refused (reported by @ortizgui). - [v1.5.11 — September 13, 2026](https://ministack.org/blog/changelog-v1-5-11): CloudFormation stack updates stop destroying resources. **CloudFormation** — eighteen more resource types update in place instead of falling through to the create handler (the CloudFront distribution and the five policy/OAC/function types, the four API Gateway v2 types, the SQS and SNS policy types, an SNS subscription, a Lambda alias, a log subscription filter, an IAM instance profile and two Cognito types), `UpdateReplacePolicy: Retain` holds for every handler-side replacement, a nested stack's resource reads its own policy, `ValidateTemplate` reports capabilities and transforms, and a stack and a change set report what a deploy acknowledged. **S3** — a presigned URL is verified against the credentials that signed it, and is no longer rejected for the checksum SDKs sign into its query string. **Lambda** — an SDK call runs under the function's execution role, durable invocations run on the warm pool, and two durable executions no longer share a callback. **ECS** — `RunTask` returns before the image is pulled. Reads fixed: CloudWatch `logGroupClass`, SSM `KeyId`, EC2 security-group IPv6 rules, launch-template metadata options, and `Fn::GetAtt` on a user pool client's `ClientSecret`. - [v1.5.10 — September 10, 2026](https://ministack.org/blog/changelog-v1-5-10): Five new services — Amazon Location, AWS Signer, IoT Wireless, Amazon Translate and Lambda Core. **Amazon Location** — CreateTracker/DescribeTracker/UpdateTracker/ListTrackers/DeleteTracker, the four device-position operations and AWS::Location::Tracker; PositionFiltering applies (TimeBased one sample per 30s per device, DistanceBased ignores a move under 30 m); newest 100 positions per device, in memory. Contributed by @iot-rocket. **AWS Signer** — StartSigningJob, DescribeSigningJob, ListSigningJobs, PutSigningProfile, GetSigningProfile; signing is synchronous and synthetic, the marker object lands at prefix + jobId before the call returns. Contributed by @iot-rocket. **IoT Wireless** — GetPositionEstimate on POST /position-estimate; the output shape declares a payload blob, so the body is the raw GeoJSON Point, not a JSON envelope. Contributed by @iot-rocket. **Amazon Translate** — StartTextTranslationJob, DescribeTextTranslationJob, ListTextTranslationJobs, StopTextTranslationJob against the local S3 store. Contributed by @ppettitau. **Lambda Core** — the five network-connector operations on /2026-04-04/network-connectors; the service signs with Lambda's own credential scope, so the surface is routed by path. Reported by @edersonbrilhante. **CloudFormation** — the Rules section is evaluated (the CDK's CheckBootstrapVersion rule now refuses an outdated bootstrap), the AWS::Include transform resolves, template and stack quotas are enforced, and Capabilities are enforced under AUTH=true. Contributed by @iot-rocket. **Fixes** — a REST method's COGNITO_USER_POOLS authorizer is enforced and its claims reach the backend (@ppettitau); EC2 subnets report AvailabilityZoneId and DescribeAvailabilityZones reports ZoneType (@Alexis-DevOps); CreateFleet applies a launch template's instance tags (reported by @edersonbrilhante); Step Functions numeric *Path Choice comparisons resolve (@jayjanssen); SES SendBulkEmail is routed (@jgrumboe); Glue Data Catalog operations. - [v1.5.9 — September 8, 2026](https://ministack.org/blog/changelog-v1-5-9): WaitCondition and SignalResource, stack tags propagate, CloudFormation pages its listings. **CloudFormation — WaitCondition waits, SignalResource delivers** — the handle's Ref is a served URL (PUT the AWS signal JSON, empty Content-Type), Count distinct SUCCESS signals complete it, FAILURE or Timeout rolls back, signals land in stack events, GetAtt Wait.Data is the {UniqueId: Data} map; CreationPolicy form signalled via the new SignalResource action; nested stacks deploy on a worker thread. Contributed by @iot-rocket. **CloudFormation — stack tags propagate** — 44 tagged types receive stack tags + aws:cloudformation:stack-name/stack-id/logical-id on create and update (template key wins); queue/topic/table/function/log-group/stream store their own Tags where their service reads them; empty Tags removes, >50 or aws: keys refused, service-API tags survive. Contributed by @iot-rocket. **CloudFormation — paging** — DescribeStacks, ListStacks, DescribeStackEvents, ListStackResources, ListExports, ListImports, ListChangeSets return 100/page with NextToken; foreign tokens are ValidationError. Contributed by @iot-rocket. **CloudFormation — dynamic references resolve** ({{resolve:ssm}}, {{resolve:ssm-secure}}, {{resolve:secretsmanager}}, AWS-measured update semantics), **DeletionPolicy/UpdateReplacePolicy honoured** (Retain keeps with DELETE_SKIPPED; RetainExceptOnCreate, RetainResources), **ListImports/UpdateTerminationProtection/SetStackPolicy/GetStackPolicy/CancelUpdateStack/ContinueUpdateRollback added**. Contributed by @iot-rocket. **Fixes** — Lambda Docker extraction content-addressed (repeat cold start writes nothing, reference-swept, reset clears); S3 Tables/Glue Iceberg upgrade-format-version to v3 applies atomically, downgrades 400; Fn::Cidr splits its block, Fn::GetAZs answers the stack's zones, Fn::FindInMap gains DefaultValue, condition functions resolve in value position (measured); parameter constraints enforced with CloudFormation's wording; unregistered AWS::CloudFormation::* types refused; stack id addresses GetTemplateSummary and UPDATE change sets; DELETE_FAILED leftovers stay visible and retried, DescribeStackResource(s) carry ResourceStatusReason/LastUpdatedTimestamp/Metadata; change sets see DeletionPolicy/UpdateReplacePolicy/Metadata edits; MRAP alias matches ^[a-z][a-z0-9]*[.]mrap$ (all @iot-rocket). - [v1.5.8 — September 5, 2026](https://ministack.org/blog/changelog-v1-5-8): CloudFormation in-place updates complete, planned Aurora MySQL switchover, S3 Multi-Region Access Points. **CloudFormation — AWS::IoT::ThingGroup provisions** — CreateThingGroup with ThingGroupProperties/ParentGroupName, Ref = thing group id, GetAtt Arn/Id, in-place property updates, rename/re-parent replaces per the resource reference. Contributed by @iot-rocket. **CloudFront — CachePolicy, OriginRequestPolicy, ResponseHeadersPolicy, OriginAccessControl and Function provision** through the service's own config parser with documented Ref/GetAtt values. Contributed by @mm-salesqueze. **S3 — Multi-Region Access Points deploy and serve** — AWS::S3::MultiRegionAccessPoint mints the .mrap alias and .accesspoint.s3-global.amazonaws.com serves the member buckets (region-matched member, else the first); SigV4A not verified per the no-SigV4 stance. Contributed by @mm-salesqueze. **RDS — planned Aurora MySQL switchover** — SwitchoverGlobalCluster (and lossless FailoverGlobalCluster) on two-member Aurora MySQL 8 global clusters fences and drains the writer, awaits GTID convergence, reverses and verifies replication, verifies the promoted writer; AllowDataLoss=true and non-native configs keep the metadata-only path. Contributed by @Areson. **RDS — FailoverDBCluster promotes replicated PostgreSQL readers** via pg_promote() under MINISTACK_RDS_PG_CLUSTER_REPLICATION=1. Contributed by @kiran01bm. **Fixes** — CloudFormation: nineteen types update in place (the four Cognito types incl. EnabledMfas, SecretsManager Secret with same-ARN new AWSCURRENT, Kinesis, ECR, DynamoDB GlobalTable, EventBus, Events Rule, CodeBuild, Route53 RecordSet, Scheduler Schedule, StepFunctions StateMachine, CloudWatch Alarm, IAM Policy, ApiGateway Authorizer, ApiGateway Deployment, KMS Alias) with engine predecessor cleanup, Lambda::Permission swaps its statement under a fresh generated Sid with all nine documented properties, a failed update deletes only what it created and reports the previous template/parameters/tags after UPDATE_ROLLBACK_COMPLETE, a no-change UpdateStack answers ValidationError: No updates are to be performed., unrecognized types and dynamic references refuse synchronously, Fn::GetAtt to a missing attribute fails the stack, DeleteChangeSet of a missing set succeeds (cdk deploy works), DeleteStack blocks only on real Fn::ImportValue imports, Events::Rule reports the service's rule ARN, UserPoolName is honoured (all @iot-rocket); CloudWatch PutMetricAlarm keeps StateUpdatedTimestamp and only moves AlarmConfigurationUpdatedTimestamp; IAM maps the remaining S3 operations to their documented actions under AUTH=true (@iot-rocket); DynamoDB PartiQL SELECT from "table"."index", document paths in SET/REMOVE, OR predicates, RETURNING MODIFIED, AWS-worded Select/ProjectionExpression refusals, index-arm ConsumedCapacity, secondary-index key validation (reported by the paritysuite.org project); Lambda durable executions emit InvocationCompleted, ExecutionTimedOut (ExecutionTimeout enforced), ChainedInvokeTimedOut and ChainedInvokeStopped; Cognito PreSignUp fires on plain SignUp, fail-closed; STS sessions expire (403 ExpiredToken) and evict. - [v1.5.7 — September 4, 2026](https://ministack.org/blog/changelog-v1-5-7): Cross-account AMI sharing, CloudFormation updates stop destroying resources, IAM caller identity on API Gateway. **EC2 — cross-account AMI sharing** — ModifyImageAttribute applies launchPermission add/remove (both wire forms), DescribeImages shows shared images with the owner's OwnerId, Public flips on Group=all, ExecutableUsers honored, shared AMIs launch; a non-owner modifying an image answers AuthFailure as real EC2 does. Reported by @edersonbrilhante. **API Gateway — IAM caller identity** — AWS_IAM REST methods fill the payload-1.0 identity fields (accessKey, accountId, userArn, principalOrgId, and the four cognito* fields with the CognitoSignIn: provider format); HTTP API routes fill requestContext.authorizer.iam and reject unsigned requests 403; GetCredentialsForIdentity registers its credentials as an STS session (GetCallerIdentity reports assumed-role//CognitoIdentityCredentials) so identity-pool credentials work under AUTH=true. Reported by @iot-rocket. **Cognito — principal tag attribute maps** (Set/GetPrincipalTagAttributeMap + AWS::Cognito::IdentityPoolPrincipalTag). Contributed by @ppettitau. **RDS — Aurora MySQL switchover foundations**, dormant. Contributed by @Areson. **Fixes** — CloudFormation: twelve types update in place (Cognito UserPool/Client/IdentityPool/Group, SecretsManager Secret with same-ARN new AWSCURRENT, Kinesis, ECR, DynamoDB GlobalTable, EventBus, CodeBuild, Route53 RecordSet, Scheduler Schedule) and the engine deletes a replaced resource's predecessor; Cognito TOTP verifies with RFC 6238 (EnableSoftwareTokenMFAException / CodeMismatchException) and PreSignUp fires on plain SignUp, fail-closed (@iot-rocket); Lambda Docker functions see the control-plane ARN in context.invoked_function_arn instead of the RIE's hardcoded 012345678912 (@TomaszKupka); the Aurora cluster-ro- reader endpoint registers as a network alias and reports in Describe under alias mode (@jbschooley); CloudWatch JSON timestamps are epoch numbers, CloudFront GetDistribution drops the invented ns0: prefixes, cross-account AssumeRole resolves in the ARN's account and sessions run in the right tenant, stacks addressed by ID delete and update (cdk destroy works), CodeBuild lands FAULT on a build the agent never ran plus CODEBUILD_DOCKER_FLAGS (all @mm-salesqueze); SNS→Lambda and Logs subscription-filter deliveries run under the right account; STS sessions expire (403 ExpiredToken) and evict; empty NextToken/NextMarker omitted across MSK, Organizations, WAF Classic, Bedrock and newer Lambda surfaces; seeded public AMIs carry their real publishing accounts. - [v1.5.6 — September 2, 2026](https://ministack.org/blog/changelog-v1-5-6): Amazon Transcribe lands, Lambda SnapStart emulated mechanism-and-shape, ALB authenticate-oidc authenticates, IAM resolves the managed-policy ARNs CDK attaches, host-header routing stops guessing on unregistered domains. **Amazon Transcribe** — batch transcription jobs end to end: StartTranscriptionJob walks QUEUED→IN_PROGRESS→COMPLETED, reads media from MiniStack S3, writes the transcript back in the real result format (redaction, subtitles, speaker labels honored), publishes Transcribe Job State Change events; deterministic canned transcript, no speech recognition. Contributed by @ppettitau. **Lambda — SnapStart** — the parameter round-trips with AWS's constraints (Java 11+/Python 3.12+/.NET 8+ zip, container images, no ephemeral storage above 512 MB); publishing a version initializes its execution environment right then so the first invoke lands warm, invoking while Pending answers ResourceConflictException, a broken init fails the publish (State: Failed), snapshot-restore-py before-snapshot/after-restore hooks run during a published version's init. **RDS — MySQL writer quiescence primitives** for Aurora global-cluster switchover, deadline-bounded and fail-closed. Contributed by @Areson. **Glue / S3 Tables — Iceberg-Spark catalog for Glue 5.0** plus a pyiceberg-usable Iceberg REST catalog (createNamespace routes; format-version and schema-id fixed). Reported by @kevinprince. **Fixes** — ALB authenticate-oidc runs the documented OIDC flow end to end and signs x-amzn-oidc-data as AWS does, with rule actions chained in Order (@dhanesh); host patterns apply only to hosts the stack serves, each service token anchored at a label boundary (@iot-rocket); IAM managed policies live under their real service-role/ ARNs and the path-less spellings answer NoSuchEntity, aws:ResourceAccount resolves, S3 multipart uploads authorize as s3:PutObject (@iot-rocket); a failed Lambda Docker cold start no longer leaks its extraction directory (reported @iot-rocket); an RDS container worker no longer clobbers an intervened StopDBInstance. - [v1.5.5 — September 1, 2026](https://ministack.org/blog/changelog-v1-5-5): Bedrock knowledge bases get real, KMS multi-Region keys, stable RDS cluster endpoints, gzip request bodies inflated. **Bedrock — knowledge bases** — StartIngestionJob reads the S3 data source (inclusionPrefixes honored) and reports real statistics, an unreadable source lands FAILED with failureReasons, Retrieve returns content with s3Location and scores. Reported by @bradleyhet. **KMS — multi-Region keys and ReplicateKey** — mrk- keys with shared key material across regions, PendingReplicaDeletion on deleting a primary with live replicas. Reported by @cringdahl. **Fixes** — Bedrock guardrails enforce their deterministic policies (word policy, sensitive-information regexes, pattern-matchable PII with BLOCK/ANONYMIZE) across ApplyGuardrail and Converse/ConverseStream, and InvokeAgent no longer fabricates an orchestration trace (reported @bradleyhet); an RDS cluster endpoint is a stable Docker network alias that survives container replacement (@jbschooley); gzip-compressed SDK request bodies are inflated so a large PutMetricData stops vanishing, S3 excluded where Content-Encoding is object metadata (@Lukasdoe); Cognito PreventUserExistenceErrors=ENABLED hides unknown users with the documented masked destinations (@fhfournier); Lambda SQS event records carry AWSTraceHeader and the FIFO attributes (reported @future-h-takeda-g3); request bodies assemble in linear time — a 95 MB PutObject drops from ~23 s to ~0.3 s (reported @vernonhaughton). - [v1.5.4 — August 31, 2026](https://ministack.org/blog/changelog-v1-5-4): AppSync executes: APPSYNC_JS resolvers run, queries parse through graphql-core, the schema/function/cache control plane lands, auth modes are enforced; Aurora DSQL foreign keys and CDC streams; AWS::IoT::CACertificate; KMS GenerateRandom; stale-state fixes across ECS, Lambda, RDS, Kinesis and Cognito. **AppSync — APPSYNC_JS resolvers execute** — request()/response() run against NONE/HTTP/DynamoDB/Lambda data sources with the util/runtime/extensions globals, runtime.earlyReturn in both documented positions, pipeline stash threading, and the @aws-appsync/utils/dynamodb helpers, on a pool of warm Node workers (30s bound, kill-and-respawn, heap cap; reuses the image's Node). Contributed by @jbschooley. **AppSync — graphql-core execution** — an API with a schema parses, validates and executes with the reference engine (AWS* scalars and @aws_* directives supplied; schemaless APIs keep the lenient path); adds graphql-core as a dependency. Contributed by @jbschooley. **AppSync — control plane** — StartSchemaCreation/GetSchemaCreationStatus, GetIntrospectionSchema (SDL or a real format=JSON introspection document), pipeline functions, environment variables, the Update* family, the five ApiCache operations (required members validated, healthMetricsConfig reported, cache honored by the data plane), and EvaluateCode. Contributed by @jbschooley. **AppSync — auth modes enforced** — a request satisfying none of the API's providers answers 401 UnauthorizedException, as on AWS. Contributed by @jbschooley. **Aurora DSQL — foreign keys, CDC streams, FOR KEY SHARE, GetVpcEndpointServiceName** — REFERENCES reaches the backend with DSQL's live-measured rules enforced; streams create/describe/list/page/tag/delete (metadata only); ALTER TABLE refusals now answer the service's own wordings. Contributed by @vivedo. **IoT — ListThingGroupsForThing** — the reverse membership lookup. Contributed by @iot-rocket. **CloudFormation — AWS::IoT::CACertificate** — create/update/delete through the real registry API with RegistrationConfig and CertificateMode; an existing PEM fails the create as CloudFormation does. Contributed by @iot-rocket. **KMS — GenerateRandom** — 1-1024 bytes, service wordings, Recipient refused loudly. Contributed by @iot-rocket. **Fixes** — a service module that fails to import no longer overwrites its persisted state (@jbschooley); restored ECS services relaunch their tasks (@jbschooley); six write-only fields round-trip across Lambda/s3control/Kinesis/RDS/Cognito (@jbschooley); ECS tasks and Lambda functions run their declared architecture (@jbschooley); Cognito AdminListUserAuthEvents requires user-pool add-ons (@iot-rocket). - [v1.5.3 — August 28, 2026](https://ministack.org/blog/changelog-v1-5-3): The JSONata query language for Step Functions, IoT Jobs over MQTT and provisioning templates, API Gateway custom-domain routing, CloudFormation in-place updates with honest failure states, S3 replication that delivers, and ECS/ELBv2 fixes. **Step Functions — JSONata** — QueryLanguage: JSONata evaluates through a full engine ($states, workflow variables, the six Step Functions functions), causes lead with the JSONata error code, malformed expressions are refused at CreateStateMachine with INVALID_JSONATA_EXPRESSION, D3110/D1004 as on AWS, 1-second timeout, $eval absent. Reported by @facuparedes. **IoT — jobs over MQTT** — the reserved $aws/things//jobs/# topics answer accepted/rejected with string ErrorCode rejections, notify/notify-next on state changes; device timestamps are epoch seconds on both planes. Contributed by @iot-rocket. **IoT — provisioning templates** — the five operations plus AWS::IoT::ProvisioningTemplate, storage + CRUD with real wire shapes. Contributed by @iot-rocket. **API Gateway — custom domains** — a registered domain routes through its base-path mappings (longest wins, (none) is root) before any host guessing. Contributed by @iot-rocket. **CloudFormation — in-place updates and honest failures** — eleven types update through their service's own APIs keeping the physical id; DeleteStack lands DELETE_FAILED with failed resources retained, rollbacks land ROLLBACK_FAILED/UPDATE_ROLLBACK_FAILED; AWS::Lambda::Version Ref returns the qualified ARN. Contributed by @iot-rocket. **S3 — replication delivers** — a write matching an Enabled rule lands in the destination with x-amz-replication-status COMPLETED/FAILED on the source and REPLICA on the copy. Reported by @cringdahl. **Fixes** — IoT HTTP shadow writes publish the reserved-topic notifications (@iot-rocket); Step Functions standard executions publish Execution Status Change events to the default EventBridge bus (reported @moonyseven); ECS services register their running tasks in their target groups, withdrawing only their own registrations (@jbschooley); awsvpc tasks no longer publish host ports (@jbschooley); ELBv2 rule conditions sent as typed configs parse and DescribeRules echoes both shapes (@jbschooley). - [v1.5.2 — August 26, 2026](https://ministack.org/blog/changelog-v1-5-2): Cognito federated identity linking and pool schema, S3 ListBuckets pagination and CRC32C checksums, EventBridge Pipes delivery to Step Functions, and S3, EventBridge, Step Functions, EC2, CodeBuild, Lambda and s3tables fixes. **Cognito — AdminLinkProviderForUser / AdminDisableProviderForUser** — a federated identity links to a local user (identities attribute, up to 5 per user, AliasExistsException when already linked), hosted-UI federated sign-in resolves to the linked user; ProviderName=Cognito deactivates the local user's password sign-in. Reported by @rsimples. **Cognito — AddCustomAttributes and pool SchemaAttributes** — DescribeUserPool reports the full standard attribute set with AWS's types, mutability and constraints, request Schema entries override field-for-field, AddCustomAttributes adds 1-25 attributes; a Required custom attribute is refused. Contributed by @jgrumboe. **S3 — ListBuckets pagination** — MaxBuckets, ContinuationToken and Prefix honored, ContinuationToken alone signals a further page. Reported by @gaul. **S3 — CRC32C checksums** — computed in-process, BadDigest on mismatch, surfaced with checksum mode enabled, completing all five algorithms. Reported by @gaul. **Fixes** — Step Functions CreateStateMachine is idempotent, an identical re-create answers the existing ARN and DescribeStateMachine leaks no bookkeeping fields (@bandle); EventBridge input templates quote a string variable in a JSON value position, interpolate raw inside a string literal, and strip an object's internal quotes in-string (@ppettitau); Pipes delivers a DynamoDB stream batch to a Step Functions target as one StartExecution with a JSON array, holding the batch on failure (@facuparedes); EC2 DescribeSnapshots evaluates Filters (@bandle) and the invented DescribeInstanceMaintenanceOptions / DescribeInstanceAutoRecoveryAttribute are removed; S3 CopyObject applies x-amz-acl and UploadPartCopy honors x-amz-copy-source-if-* (@gaul); S3 versioning edges — DeleteBucket refuses BucketNotEmpty while versions remain, a delete marker read by version id answers 405, a nonexistent version on ACL/tag ops answers NoSuchVersion, ListObjectVersions honors delimiter (@gaul); S3 directory-bucket delete conditions answer NotImplemented (reported @gaul); CodeBuild BatchDeleteBuilds reports buildsNotDeleted as {id, statusCode} structures; Lambda InvokeWithResponseStream returns HTTP-level errors unframed; s3tables deletes answer 204 No Content. - [v1.5.1 — August 25, 2026](https://ministack.org/blog/changelog-v1-5-1): The RDS Proxy control plane, SNS platform application attributes, Step Functions States.StringSplit/States.Hash and the aws-sdk:cloudwatchlogs integration, MySQL IAM auth plugins in the slim image, verified S3 checksums, and least-privilege IAM fixes. **SNS — Get/SetPlatformApplicationAttributes** — both answered 400 InvalidAction so terraform plan on an aws_sns_platform_application failed at refresh; Get returns the attribute map, Set merges the supplied entries, CreatePlatformApplication seeds Enabled=true. Contributed by @jgrumboe. **Step Functions — States.StringSplit and States.Hash** — StringSplit treats every character of its second argument as a delimiter and keeps no empty member; Hash computes MD5/SHA-1/SHA-256/SHA-384/SHA-512 as lowercase hex with the 10,000-character cap. Contributed by @bandle. **RDS — RDS Proxy (control plane)** — CreateDBProxy and the twelve other proxy operations with documented shapes, defaults, constraints and faults; metadata only, nothing listens on the proxy hostname. Reported by @jmreicha. **EC2 — EC2_DOCKER_FLAGS** — opt-in docker-CLI-style launch options for instance containers. Contributed by @iot-rocket. **Changed** — the slim image ships the MySQL IAM auth plugins, copied from the published full image pinned by digest. Contributed by @Areson. **Fixes** — IAM resource-scoped policies work for JSON-protocol services (SQS/ACM/SSM/CloudWatch read the request body; SQS resolves a path-addressed queue) and kms:Decrypt resolves the key from the ciphertext (reported @rsimples); Lambda CreateFunction with an unresolvable role answers 400 InvalidParameterValueException (reported @rsimples); Cognito group membership and AdminDeleteUser key on the resolved Username in UsernameAttributes pools (@Lukasdoe); S3 presigned uploads keep hoisted x-amz-* headers (@dennmart) and every supplied x-amz-checksum-* value is verified, BadDigest on mismatch, trailer checksums read (@gaul); Step Functions aws-sdk:cloudwatchlogs routes with PascalCase Parameters and CloudWatchLogs.* errors (@bandle); Glue job scripts' boto3 clients reach MiniStack via AWS_ENDPOINT_URL plus a bootstrap for the older botocore in the Glue 4.0 image; CloudFormation Fn::Sub honors the ${!Literal} escape (@maximoosemine); EventBridge dotted pattern keys resolve as nested paths (@prandogabriel); IoT Core an unresolvable action role fails CreateTopicRule with 400 InvalidRequestException (@iot-rocket); RDS Aurora PostgreSQL major-version selectors return the matching catalog with DefaultOnly honored (@jayjanssen). - [v1.5.0 — August 23, 2026](https://ministack.org/blog/changelog-v1-5-0): Opt-in IAM request authorization (AUTH=true), CloudFront SaaS Manager multi-tenant distributions, EC2 RegisterImage that boots a real container behind an instance, SSM Run Command, S3 Glacier/Deep Archive restore, and blocking-handler concurrency; plus IAM, S3, RDS, Cognito, DynamoDB and Lambda fixes. **IAM — opt-in request authorization (AUTH=true)** — evaluates the caller's IAM policies and returns 403 AccessDenied when they don't allow the action, across control-plane and data-plane paths (S3 object access, execute-api:Invoke, lambda:InvokeFunctionUrl, per-service actions from the botocore model); SigV4 is still not validated, so this is authorization not authentication, off by default. **CloudFront — SaaS Manager (multi-tenant distributions)** — connection groups and distribution tenants with ETag/If-Match concurrency, per-tenant WAF association, tenant invalidations, and domain tooling; a tenant requires a tenant-only distribution (InvalidAssociation) and CNAMEs are unique across tenants and aliases (CNAMEAlreadyExists). Contributed by @mjdavidson. **EC2 — RegisterImage boots a real container behind an instance** — a registered image runs as a container whose IP becomes the instance address so ssm:SendCommand reports a real exit code; instance-store backed, opt-in, and RebootInstances rejects unknown ids (InvalidInstanceID.NotFound). Reported by @iot-rocket. **SSM — Run Command** — SendCommand, GetCommandInvocation, ListCommands and DescribeInstanceInformation; AWS-RunShellScript runs in the instance's container, SendCommand answers Pending and the caller polls. Contributed by @bandle. **S3 — Glacier and Deep Archive restore (RestoreObject)** — an object in GLACIER/DEEP_ARCHIVE is unreadable until restored (403 InvalidObjectState), with async RestoreObject and x-amz-restore; GLACIER_IR stays readable. **Concurrency — a blocking handler no longer stalls concurrent requests** — the request loop is captured at startup and blocking work runs on worker threads that can re-enter the server. Contributed by @Areson and @iot-rocket. **Changed — the full Docker image is smaller.** **Fixes** — IAM CloudFormation-provisioned policies no longer break the read APIs (reported @iot-rocket) and AccessDenied is serialized per the caller's wire protocol; Lambda Node.js ESM top-level await handlers load (@ryan-bennett); Cognito ListUsers matches filter values case-insensitively (@ppettitau); DynamoDB UpdateExpression aliases resolve before the key-attribute check (reported @ppettitau); RDS DescribeDBInstances honors SDK Filters (@jayjanssen); S3 conditional delete of a key with no current object answers 404 (@gaul) and one canonical owner ID across every S3 API (reported @jin-gizmo); EC2 DescribeAvailabilityZones reports groupName/networkBorderGroup/optInStatus. - [v1.4.21 — August 20, 2026](https://ministack.org/blog/changelog-v1-4-21): CloudFormation change sets report a valid status and fail correctly (unblocking the CDK), a replacement of a custom-named resource is refused instead of destroying data, and SES configuration sets provision; RDS Aurora global databases and replicated readers survive Stop/Start and validate engine versions on every write path; plus S3 conditional deletes and multipart composite checksums, a native IoT mTLS MQTT listener on port 8883, and resource+method API Gateway routing. **IoT Core — native mTLS MQTT on port 8883** — the embedded broker also accepts MQTT over TLS on 8883, on by default when cryptography is installed (IOT_MTLS_ENABLED=0 to disable, IOT_MTLS_PORT to move it), broker cert at GET /_ministack/iot/ca.pem; a client cert is optional. Contributed by @iot-rocket. **RDS — replicated Aurora PostgreSQL readers survive Stop/Start and warm boot** — StopDBCluster stops the reader containers alongside the writer and StartDBCluster revives each reader by re-cloning from the writer; the same revival runs on warm boot. Contributed by @kiran01bm. **CloudFormation — AWS::SES::ConfigurationSet and AWS::SES::ConfigurationSetEventDestination** — both provision (registered in the classic and v2 SES stores, Ref returns the set name, the event destination round-trips). Contributed by @ryan-bennett. **API Gateway (REST) — routing on the resource+method pair** — a request a matched resource does not serve falls through to a {proxy+} elsewhere in the tree, and only an exact match keeps it; routing precedes authorization. Supersedes the 1.4.16 methodless-403 change. Contributed by @iot-rocket. **CloudFormation — change sets report a valid status, fail when execution fails, and do not outlive their stack** — Status stays CREATE_COMPLETE (ExecuteChangeSet no longer writes the invalid EXECUTE_COMPLETE that broke the CDK) while ExecutionStatus tracks the outcome; a no-change set ends FAILED, a missing set returns ChangeSetNotFound (404), duplicate names are AlreadyExistsException, deleting a stack removes its change sets, and a direct UpdateStack marks pending sets OBSOLETE. Reported by @iot-rocket. **CloudFormation — a replacement of a custom-named resource is refused instead of destroying data** — an update requiring replacement of a resource with an explicit physical name now fails and rolls back to UPDATE_ROLLBACK_COMPLETE, leaving the resource and its data intact. Reported by @iot-rocket. **RDS — Aurora engine versions validated on non-create writes** — ModifyDBInstance/ModifyDBCluster/CreateGlobalCluster/ModifyGlobalCluster reject uncatalogued versions (InvalidParameterCombination on the modify paths), ModifyGlobalCluster propagates to every member, and a cross-major member change is refused. Contributed by @kiran01bm. **RDS — global Aurora stop/start preserves topology and MySQL replication** — stop/start limited to sole-member global databases, last-instance deletion preserves shared compute, and a recreate resets stale MySQL replica state before re-linking. Contributed by @kiran01bm. **Step Functions — an unimplemented optimized integration fails instead of passing through** — a Task using an unimplemented arn:aws:states:::: integration now fails with States.Runtime instead of echoing its input as SUCCEEDED. Reported by @iwasakar. **S3 — a conditional delete of an absent key is answered correctly** — DeleteObject with If-Match on a missing key returns 204, and If-Match: * is an existence check (412 when the key is absent). Contributed by @gaul. **S3 — multipart uploads carry their parts' checksums through to a composite** — parts are validated and echoed, and completion builds the AWS composite - read back as COMPOSITE (BadDigest on mismatch). Contributed by @gaul. - [v1.4.20 — August 19, 2026](https://ministack.org/blog/changelog-v1-4-20): opt-in Aurora PostgreSQL reader replication and RDS FailoverDBCluster, AWS IoT Jobs with its iot-jobs-data device plane, and CloudFormation API Gateway keys and usage plans, plus a broad S3 correctness pass and parity fixes across DynamoDB, CloudWatch, EC2, IAM, Step Functions and Aurora DSQL. **RDS — opt-in Aurora PostgreSQL reader replication** — with MINISTACK_RDS_PG_CLUSTER_REPLICATION=1, the second and later members of an Aurora PostgreSQL cluster launch their own PostgreSQL containers, cloned with pg_basebackup and streaming WAL as hot standbys; a reader is genuinely read-only, sees the writer's data, and the cluster ReaderEndpoint resolves to a reader. Off by default. Contributed by @kiran01bm. **RDS — FailoverDBCluster** — promotes a reader to writer (explicit TargetDBInstanceIdentifier or the lowest PromotionTier), reporting the transitional failing-over status and flipped IsClusterWriter flags. Contributed by @kiran01bm. **AWS IoT Jobs — control plane and device data plane** — the iot service serves the nine job operations and a new iot-jobs-data service the device ones, sharing one store and the AWS execution state machine. Contributed by @iot-rocket. **CloudFormation — API Gateway (v1) API keys and usage plans** — AWS::ApiGateway::ApiKey/UsagePlan/UsagePlanKey provision through the runtime stores, with Ref and Fn::GetAtt wired. Contributed by @ryan-bennett. **S3 — server-side encryption stated, validated and enforced** — SSE-S3/KMS/SSE-C are contract state: validated on write, echoed on HEAD/GET, and enforced for SSE-C (keyless/plain read 400, wrong key 403). Contributed by @gaul. **S3 — CRC64NVME checksums computed** — the default SDK checksum algorithm is computed from a stdlib table instead of refused, no new dependency. Contributed by @gaul. **S3 — versioning edges, canned ACLs, conditional multipart** — the null version, delete-marker signals and versioned copies match AWS; canned ACLs are stored and object ACLs bind to versions; CompleteMultipartUpload honors If-Match/If-None-Match. Contributed by @gaul. **S3 — presigned SigV4 for virtual-hosted addressing and temporary credentials** — verification runs against the original signed URI and the secret STS issued. Reported by @mayankgupta57. **DynamoDB — key attribute types enforced on PutItem, Query and UpdateTable** — a key's declared type can no longer be violated or changed in place. Reported by @iot-rocket. **CloudWatch — extended-statistic percentiles computed** — GetMetricData and alarm evaluation interpolate pNN from the period's samples instead of aliasing to Average, and a percentile alarm's StateReason names the actual statistic. Contributed by @MGSousa. **EC2 — instance public IP and DNS reach the SDKs** — the address rides the wire tags ipAddress/dnsName and generated addresses complete to four octets. Contributed by @iot-rocket. **Step Functions — events:putEvents publishes** — the optimized EventBridge integration calls PutEvents instead of passing through. Reported by @iwasakar. **IAM — role Description charset validated** — CreateRole/UpdateRole/UpdateRoleDescription reject an out-of-charset or over-1000-character description. Reported by @iot-rocket. **Aurora DSQL** — SELECT ... FOR UPDATE is gated on lock strength, not predicate, and quoted identifiers fold the way the server stores them. **CloudFormation** — AWS::IoT::Policy updates apply, AWS::SSM::Parameter goes through the SSM API, and auto-generated physical names keep their uniqueness suffix when truncated. - [v1.4.19 — August 17, 2026](https://ministack.org/blog/changelog-v1-4-19): device shadows over MQTT, MQTT 5.0 negotiated per connection, a CA-certificate registry with just-in-time registration events, connectivity terms in the fleet index, and the sqs topic-rule action, plus an AWS-faithful EventBridge event-pattern matcher and Cognito federation from the user pool domain. **IoT Core — device shadows over MQTT** — the classic and named shadow operations are served over the broker at $aws/things//shadow[/name/]/{get,update,delete}, replying on the accepted/rejected topics (with delta and documents on update) and echoing the request's clientToken. Contributed by @iot-rocket. **IoT Core — MQTT 5.0 per connection** — the broker negotiates its wire format from the CONNECT protocol level; a 5.0 client gets property blocks, subscription options and reason codes, a 3.1.1 client keeps its exact bytes, messages cross versions, and the CONNACK advertises AWS's capabilities (Maximum QoS 1, Maximum Packet Size 128 KB, retain, wildcards). Contributed by @iot-rocket. **IoT Core — CA-certificate registry and JITR events** — RegisterCACertificate and friends, with CertificateStateException (406) on an ACTIVE-CA delete, ResourceAlreadyExistsException (409) on a duplicate, CertificateValidationException (400) when caCertificatePem does not match the signing CA, and the registered event on $aws/events/certificates/registered/{caCertificateId}. Contributed by @iot-rocket. **IoT Core — connectivity.* fleet index** — with thingConnectivityIndexingMode STATUS, SearchIndex answers connectivity.connected/timestamp/disconnectReason and DescribeIndex reports ..._AND_CONNECTIVITY_STATUS; connected is derived from the live session registry (client id equals thing name) so it cannot drift or survive a restart. Contributed by @iot-rocket. **IoT Core — sqs topic-rule action** — the payload goes through SQS's SendMessage (queue DelaySeconds and size limit apply), useBase64 Base64-encodes the body, an unresolvable queue reaches the rule's errorAction, and FIFO destinations are refused as on AWS. Contributed by @iot-rocket. **EventBridge — event-pattern matching** — rewritten to AWS's real semantics: a $or-only or unknown-key-only pattern no longer matches everything, $or expands with last-write-wins and the 1000-combination cap, wildcard treats only * as special, exists works on leaf nodes, resources is an OR, and cidr/equals-ignore-case/case-insensitive prefix-suffix are evaluated; an unparseable pattern is InvalidEventPatternException. Contributed by @t-rech. **Cognito — federation from the pool domain** — /saml2/idpresponse and /oauth2/idpresponse are derived from the user pool's domain (custom or the regional Cognito host) instead of the local host, and CustomDomainConfig is honored on CreateUserPoolDomain. Contributed by @tema-mazy. **DynamoDB — UpdateTable stream ARN** — enabling a stream through UpdateTable now mints LatestStreamLabel and LatestStreamArn on the disabled→enabled transition, as CreateTable does, so aws_dynamodb_table.stream_arn is no longer empty. Contributed by @nightcityblade, reported by @wparad. **Lambda — 250 MB unzipped limit counts layers** — CreateFunction/UpdateFunctionCode sum the function code and every attached layer, unzipped, and reject a total over 262144000 bytes with InvalidParameterValueException, matching AWS's "including layers and custom runtimes" quota. Reported by @iot-rocket. - [v1.4.18 — August 16, 2026](https://ministack.org/blog/changelog-v1-4-18): API Gateway Lambda authorizer cache scoped to the method and route ARN, an IoT topic-rule engine with WHERE evaluation and non-Lambda actions plus fleet indexing, Lambda reliability fixes, S3 conditional reads, and Aurora DSQL expression indexes. **API Gateway — authorizer cache scoping** — the REST (v1) and HTTP API (v2) caches stored the allow/deny decision keyed on the identity source alone, so a cached Allow leaked across methods, routes, and stages; they now cache the authorizer's output (the policy document, or isAuthorized for a simple response) and re-evaluate it against each request's own method/route ARN, with the stage in the key. Non-proxy (AWS) Lambda integrations also return the handler's raw output (200 by default; a standard Lambda error passed through at 200; 504 for an uninvokable or throttled backend). Contributed by @iot-rocket. **IoT — topic-rule engine and fleet indexing** — rules evaluate the WHERE clause (three-valued logic: comparisons, IN/LIKE/BETWEEN/IS NULL/regexp_matches, AND/OR/NOT, arithmetic), implement the clientid/encode/replace/timestamp/topic SQL functions, and dispatch republish/dynamoDBv2/sns actions with the rule's errorAction; SearchIndex answers over the AWS_Things index (OFF by default); RegisterCertificateWithoutCA and the deprecated principal-policy operations are added; MQTT UNSUBSCRIBE removes only the named filters. Contributed by @iot-rocket. **Lambda — reliability** — a failed INIT or a timed-out handler is reported once instead of retried to the timeout, RecursiveLoop is enforced (a self-invoking chain is dropped past ~16 hops with RecursiveInvocationException unless set to Allow), and Docker-executor nested SDK calls resolve on native Linux by mapping host.docker.internal to host-gateway. Contributed by @iot-rocket. **S3 — conditional reads** — GetObject/HeadObject answer If-Match/If-None-Match/If-Modified-Since/If-Unmodified-Since with 412 PreconditionFailed or 304 Not Modified at AWS's precedence (entity tag over date), evaluated before Range; repeated request-header lines combine per RFC 9110. Reported by @gaul. **Aurora DSQL — index and DDL error parity** — expression index keys on CREATE INDEX ASYNC (a volatile function is rejected 42P17), plain CREATE INDEX refused, and USING/CONCURRENTLY/WHERE/8-column-limit/primary-key-drop aligned with a live cluster. Contributed by @ry-allan. **SES v2 — email templates** — CRUD and SendEmail with Content.Template over the shared v1 store, and error responses carry x-amzn-errortype. Contributed by @mikolajk0wal. **ALB — response streaming** — target responses stream as produced instead of buffering (@uttom-akash). **RDS — Aurora MySQL compatibility objects** (@Areson) and **TLS — leaf certificates carry an Authority Key Identifier** (@iot-rocket). - [v1.4.17 — August 14, 2026](https://ministack.org/blog/changelog-v1-4-17): EventBridge API destination outbound requests validated and contained, API Gateway (HTTP API) REQUEST Lambda authorizers enforced, a large S3 conformance batch, and broader CloudFormation resource coverage plus two Step Functions intrinsics. **EventBridge — API destination hardening** — an api-destination target's outbound request carries the connection's credentials to a caller-chosen URL, so the path is now validated and contained: no redirect following (a 3xx could leak the Authorization header cross-host), InvocationEndpoint and the OAuth AuthorizationEndpoint must be dialable http(s):// URLs, HttpMethod/AuthorizationType are enum-validated, reserved headers cannot be overridden, DeauthorizeConnection clears the stored credentials, and the OAuth token response is read with a 1 MiB bound. Contributed by @t-rech. **API Gateway (HTTP API / v2) — REQUEST authorizers** — a route referencing a REQUEST authorizer (authorization type CUSTOM) is now invoked and enforced, honoring payload format 1.0/2.0, enableSimpleResponses vs an IAM policy, and authorizerResultTtlInSeconds caching, injecting requestContext.authorizer.lambda. Contributed by @ryan-bennett. **S3 — conformance batch** — encoding-type=url leaves the forward slash intact, a delimited listing's NextMarker is the common prefix, CopyObject honors the copy-source date preconditions, a canned ACL expands to its group grants, a malformed Content-MD5 is InvalidDigest, CompleteMultipartUpload's Location reflects the request host, and PutObject echoes the bucket's default-encryption header. Reported by @gaul. **CloudFormation — resource coverage, notifications, stack persistence** — AWS::Lambda::LayerVersionPermission, AWS::IoT::ThingType/Policy, and AWS::Cognito::IdentityPoolRoleAttachment now provision; AWS::S3::Bucket NotificationConfiguration is applied instead of silently dropped (reported by @VictorAlejMadrid); and with PERSIST_STATE=1 stack records/events/exports/change sets survive a restart (reported by @iot-rocket). Contributed by @iot-rocket. **Step Functions — route53 tasks and Base64 intrinsics** — aws-sdk:route53 tasks (e.g. ChangeResourceRecordSets) and the States.Base64Encode/States.Base64Decode intrinsics (UTF-8, 10,000-character cap, lenient decode). Contributed by @bandle. **CloudWatch Logs — GetLogGroupFields** — field names from recent stored events with a rough presence percent. Contributed by @ovsteenb. **Lambda/IoT/EC2/Cognito** — uncaught handler exceptions report X-Amz-Function-Error: Unhandled, CreateThingType is idempotent, RevokeSecurityGroup*/SecurityGroupRuleIds honored (all @iot-rocket), and /oauth2/userInfo returns custom attributes and the plain username (@rjmackay). - [v1.4.16 — August 12, 2026](https://ministack.org/blog/changelog-v1-4-16): an Aurora DSQL emulator, API Gateway (REST) custom Lambda authorizers enforced on the request path, and tighter CloudFormation stack-update semantics; plus S3 versioned-metadata and GetBucketLocation fixes and a Route 53 PENDING change. **Aurora DSQL — new service** — a control plane over the DSQL REST-JSON API (cluster lifecycle, tags, policies; clientToken idempotency, deletionProtectionEnabled, expectedPolicyVersion concurrency); with DSQL_STRICT=1 and Docker each cluster gets a real Postgres container fronted by an in-process wire-protocol proxy enforcing DSQL's SQL subset, otherwise ACTIVE metadata-only; tunable via DSQL_BASE_PORT/DSQL_STRICT/DSQL_PERSIST/DSQL_PG_IMAGE. Contributed by @ry-allan. **CloudFormation — update fidelity** — unchanged resources are left alone (auto-named resources no longer duplicate on update, including AWS::Events::EventBus), AWS::ApiGatewayV2::Authorizer survives a property update, and AWS::SSM::Parameter::Value<...> parameters resolve against Parameter Store. Contributed by @ryan-bennett. **CloudFormation — DELETE_COMPLETE re-create** — a deleted stack is addressable only by its stack ID, so describe/update/change-set by name report does-not-exist and the name re-deploys as a fresh stack. Reported by @iot-rocket. **S3 — versioned metadata** — each version stores and returns its own x-amz-meta-*, preserved headers, and content-encoding. Reported by @Kaphaalor. **S3 — GetBucketLocation** — returns the bucket's stored signing region, empty only for us-east-1. Contributed by @iot-rocket. **API Gateway (REST) — Lambda authorizers** — TOKEN/REQUEST custom authorizers run on the data path (401 on a missing identity source, 403 on Deny/no-match, authorizerResultTtlInSeconds caching, context+principalId injected into requestContext.authorizer); AWS_IAM requires an Authorization header; an unsupported resource or method returns 403 Missing Authentication Token. Reported by @iot-rocket. **Route 53 — PENDING then INSYNC** — changes are submitted PENDING and flip to INSYNC on the first GetChange read. Reported by @jayjanssen. - [v1.4.15 — August 10, 2026](https://ministack.org/blog/changelog-v1-4-15): KMS HMAC keys with GenerateMac/VerifyMac, RDS ManageMasterUserPassword wired to Secrets Manager, and EventBridge API destinations invoked over HTTP; plus a large S3 conformance batch, RDS Data API endpoint fidelity, and SQS, Route 53, and Step Functions parity fixes. **KMS — HMAC keys, GenerateMac, VerifyMac** — the four HMAC key specs (HMAC_224/256/384/512) with KeyUsage=GENERATE_VERIFY_MAC, RFC 2104 generation and constant-time verification (KMSInvalidMacException on mismatch), and DryRun; HMAC keys are rejected by Encrypt/Decrypt/Sign/Verify/GenerateDataKey*, and EnableKeyRotation/DisableKeyRotation reject them with UnsupportedOperationException while GetKeyRotationStatus reports KeyRotationEnabled false. Contributed by @nafdev. **RDS — ManageMasterUserPassword** — CreateDBCluster(ManageMasterUserPassword=true) generates a random master password, stores it in Secrets Manager under rds!cluster-, and returns MasterUserSecret from create/describe/modify; RotateMasterUserPassword rotates the login and promotes to AWSCURRENT, with AWS-exact rejections validated before mutation. Contributed by @kiran01bm. **EventBridge — API destinations over HTTP** — a matching rule with an api-destination target now POSTs (or the configured method) to the InvocationEndpoint with the input-selected payload; BASIC/API_KEY/OAUTH_CLIENT_CREDENTIALS authorization is honored (token caching, proactive refresh, one 401/407 retry), header merging follows AWS precedence, delivery runs on a background thread. Contributed by @t-rech. **Lambda — LAMBDA_KEEPALIVE_MS=0** — a LocalStack-compat lever (not AWS): for Docker RIE runtimes (Ruby/Java/.NET), 0 tears the warm container down after each invocation so the next invoke re-runs INIT; unset or any non-zero value keeps the warm pool. Reported by @mayankgupta57. **S3 — conformance batch** — POST Object reads only the field named file as the body, GetObject partNumber returns 206, ListObjectVersions emits NextKeyMarker/NextVersionIdMarker and honors version-id-marker, CompleteMultipartUpload returns 400 MalformedXML on bad XML and is idempotent, owner id is consistent between listings and ACLs, expired presigned URLs return 403 AccessDenied, and conditional deletes honor If-Match (412 PreconditionFailed). Reported by @gaul. **S3 — CopyObject/HeadObject versionId** — a ?versionId= on the copy source and on HeadObject is honored (echoes x-amz-copy-source-version-id, NoSuchVersion on a bad version). Reported by @Kaphaalor. **S3 — NewerNoncurrentVersions** — survives the lifecycle configuration PUT/GET round-trip on both NoncurrentVersionExpiration and NoncurrentVersionTransition. Contributed by @sac-outsystems. **RDS Data API — endpoint fidelity** — a cluster with the HTTP endpoint disabled returns HttpEndpointNotEnabledException, a missing/deletion-scheduled/password-less secret returns SecretsErrorException/InvalidSecretException, CommitTransaction/RollbackTransaction require resourceArn and secretArn, and a transaction is bound to its originating cluster (TransactionNotFoundException from execute/batch, NotFoundException from commit/rollback). Contributed by @Areson. **SQS — FIFO dedup window** — a MessageDeduplicationId is retained for its full 5-minute window from send time regardless of receive/delete, including the Lambda event-source-mapping consume path. Reported by @giannimassi. **Route 53 — value-exact DELETE** — ChangeResourceRecordSets DELETE now requires the provided values to match the current record and fails the batch atomically with InvalidChangeBatch otherwise. Contributed by @jayjanssen. **CloudWatch Logs — vended-delivery tags** — TagResource/UntagResource/ListTagsForResource resolve log-delivery-source/destination/delivery ARNs, unbreaking EventBridge bus-logging Terraform stacks. Contributed by @t-rech. **Step Functions — singleton list wrappers** — the query-XML to JSON converter keeps known list wrappers (e.g. VpcSecurityGroups) as lists for zero, one, or multiple items. Contributed by @Areson. **CodeBuild — TIMED_OUT** — a build stopped by timeoutInMinutes now reports TIMED_OUT instead of FAILED. - [v1.4.14 — August 7, 2026](https://ministack.org/blog/changelog-v1-4-14): AWS Config, Cloud Control API, and an SDK control plane for EventBridge Pipes; executable CodeBuild builds; Cognito choice-based sign-in; plus RDS, CloudWatch, SNS, and CloudFormation parity fixes. **EventBridge Pipes — SDK data plane** — Pipes was fully built but had no REST route, so aws pipes list-pipes fell through to S3 and returned NoSuchBucket; ListPipes/CreatePipe/DescribePipe/UpdatePipe/DeletePipe/StartPipe/StopPipe and tagging are now served over boto3/Terraform/CDK at pipes. and /v1/pipes. **AWS Config — new service** — config rules, configuration recorders, and delivery channels (PutConfigRule/DescribeConfigRules/DeleteConfigRule, recorder and delivery-channel CRUD plus status reads, StartConfigurationRecorder/StopConfigurationRecorder, compliance and evaluation-status reads). **Cloud Control API — new service** — the generic resource control plane behind Terraform's awscc provider and CDK L1 constructs (CreateResource/GetResource/UpdateResource/DeleteResource/ListResources plus resource-request status and cancel), with the AWS ProgressEvent and ResourceDescription shapes. **CodeBuild — executable builds** — with MINISTACK_CODEBUILD_EXECUTE=1, StartBuild returns IN_PROGRESS and hands the inline buildspec to the official AWS CodeBuild local agent, which runs the phases in the project image; BatchGetBuilds reflects live phases and the container exit maps to SUCCEEDED/FAILED; default behavior unchanged. Contributed by @igorgawrys1. **Cognito — choice-based sign-in** — a client with ALLOW_USER_AUTH in ExplicitAuthFlows drives a multi-step Hosted UI (username, challenge selection, PASSWORD or EMAIL_OTP) from Policies.SignInPolicy.AllowedFirstAuthFactors. Contributed by @kjdev. **KMS — UpdateKeyDescription** — the unregistered action returned InvalidAction; it now updates the description (an empty string clears it) and 404s an unknown key. Contributed by @sac-outsystems. **RDS — StopDBCluster/StartDBCluster stop and start Aurora compute** — both only flipped metadata; they now stop and start the shared container (volume/data preserved), returning transitional status while a readiness worker flips members to available, with AWS-exact InvalidDBClusterStateFault messages. Contributed by @kiran01bm. **RDS — aurora-postgresql version validation** — an unknown EngineVersion now fails with InvalidParameterCombination / Cannot find version {version} for aurora-postgresql (bare majors still resolve); the catalog is refreshed to the real creatable set. Contributed by @kiran01bm. **RDS — duplicate instance wire code** — DBInstanceAlreadyExistsFault corrected to the on-wire DBInstanceAlreadyExists so SDKs produce the typed error. Contributed by @kiran01bm. **SNS — $or filter policies** — a top-level $or is now matched (any member matches, siblings AND-ed, nesting supported) instead of dropping every message. Reported by @StiliyanDr. **CloudWatch — GetMetricData dimensions** — resolves by the query's exact MetricStat dimensions instead of aggregating across every dimension set. Reported by @boesing. **CloudFormation — AWS::KMS::Key** — honours KeySpec/KeyUsage, applies KeyPolicy/Tags/Enabled/rotation, fails immutable-property updates, and schedules deletion instead of dropping the key. Contributed by @hiddengearz. **CloudWatch Logs — toMillis filters and GetQueryResults pagination** — Insights toMillis(@timestamp) comparisons are honoured and GetQueryResults pages with maxItems/nextToken. Contributed by @ovsteenb. **EC2 — AuthorizeSecurityGroup* dedupe** — an already-present rule is echoed in securityGroupRuleSet (with the id DescribeSecurityGroupRules reports) instead of an empty set that panics terraform-provider-aws. Contributed by @sac-outsystems. **Query-protocol services** — unimplemented Query services return a parseable envelope (InvalidAction, HTTP 400). **Backup/CloudFront/Inspector2/MediaConnect** — ~96 previously-unrouted read operations now return AWS-shaped responses. - [v1.4.13 — August 6, 2026](https://ministack.org/blog/changelog-v1-4-13): maintenance release restoring the Docker image to its prior size. **Docker image — restored to its prior size** — the image bundles the AWS CLI for the in-container awslocal wrapper and the build dependency was unpinned; awscli 1.46.0 began vendoring its own botocore and s3transfer (~120 MB uncompressed) on top of the botocore already installed for boto3, inflating the 1.4.12 image. awscli is pinned to 1.45.63 (the last release before the vendored botocore), returning the image to its 1.4.11 size. No runtime behavior changes. - [v1.4.12 — August 6, 2026](https://ministack.org/blog/changelog-v1-4-12): CloudWatch Logs GetLogRecord, Insights @ptr rows, and StartLiveTail; the Lambda recursion-config API; account+region isolation for API Gateway v2; and DynamoDB, S3, RDS, EC2, and Step Functions parity fixes. **CloudWatch Logs — GetLogRecord, Insights @ptr, StartLiveTail** — StartQuery/GetQueryResults previously stubbed empty results; PutLogEvents now assigns an opaque pointer per event, Insights queries return AWS-shaped rows (@ptr, @timestamp, @message, @logStream, @log) over a CWLI subset (fields, | filter with = and like /regex/, | sort @timestamp, post-filter | limit), GetLogRecord resolves those pointers, and StartLiveTail holds a wire-valid application/vnd.amazon.eventstream open until disconnect (initial-response, sessionStart, sessionUpdate frames fed by matching concurrent PutLogEvents; 1s idle heartbeats; buffer of 10 updates, oldest dropped with sampled set); FilterLogEvents now returns the eventId real AWS assigns. Contributed by @ovsteenb. **Lambda — recursion config** — Get/PutFunctionRecursionConfig (GET/PUT /2024-08-31/functions/{name}/recursion-config) now served; RecursiveLoop defaults to Terminate, accepts Allow/Terminate, and 404s an unknown function. Reported by @mayankgupta57. **Multi-region — API Gateway v2** — HTTP and WebSocket APIs, routes, integrations, stages, deployments, authorizers, responses, and tags now isolate state by account and region, with execute-api pinned to the owning API's region. Contributed by @Areson. **S3 — lifecycle And filters** — an And filter (prefix + tags) never converged, timing out Terraform's 3-minute waiter; the And operator now echoes ObjectSizeGreaterThan (0 when unset) and an empty Prefix, which the provider's equality check requires. Reported by @rogercost. **DynamoDB — Scan/Query ProjectionExpression without Select** — a projection with no Select is now treated as SPECIFIC_ATTRIBUTES rather than rejected as incompatible with ALL_ATTRIBUTES. Reported by @jin-gizmo. **DynamoDB Streams — backlog** — shard records expire after 24h and event-source-mapping poll state is released, so long-lived containers stop degrading. Contributed by @maximoosemine. **RDS — subnet group fidelity** — subnet groups resolve VpcId/AZs from EC2 subnets and return InvalidSubnet for unknown ones; VpcSecurityGroupIds on CreateDBCluster/ModifyDBCluster are preserved. Contributed by @Areson. **EC2 — filter evaluation** — DescribeVolumes, DescribeSubnets (cidr-block), and DescribeInternetGateways now evaluate their Filters instead of returning every resource. Contributed by @bandle. **Step Functions** — Map Parameters applied per item only (it is the legacy spelling of ItemSelector), and EC2 aws-sdk parameter names are no longer over-expanded (VpcId/EnableDnsHostnames). Contributed by @bandle. **Lambda — SDK stub lookup and durable restore** — SDK client stubs keyed by exact module specifier (@roshie548); durable execution restore rebuilds timers/callbacks across every persisted account scope and re-arms each under its ARN's account and region (@Areson). - [v1.4.11 — August 4, 2026](https://ministack.org/blog/changelog-v1-4-11): the Lambda Function URL data plane, account+region isolation for API Gateway v1 and CloudWatch Logs Insights queries, Step Functions aws-sdk:ec2 SDK output shapes, and a CloudWatch CBOR fix for the Terraform AWS provider. **Lambda — Function URL data plane** — CreateFunctionUrlConfig returned a {urlId}.lambda-url.{region}.on.aws URL that nothing served; Function URLs are now invocable (host-based or path-based /_aws/lambda-url/{urlId}/...), delivering a payload-format-2.0 event ($default route/stage, percent-encoded rawQueryString, body/queryStringParameters omitted rather than null), enforcing AuthType (AWS_IAM returns 403 to an unsigned request, NONE is open), driving preflight/response headers from the Cors config, and unwrapping InvokeMode: RESPONSE_STREAM from the HttpResponseStream framing. Contributed by @liammizrahi. **Multi-region — API Gateway v1 and CloudWatch Logs Insights queries** — both now isolate state by account and region (API Gateway v1 resolves execute-api's owning region by id; Logs Insights query ids are no longer readable or stoppable cross-region); v3 persistence with legacy region self-placement. Contributed by @Areson. **Step Functions — aws-sdk:ec2 output shape** — tasks return the SDK output shape (Volumes[0].State, not VolumeSet.Item.Status; typed list/int/bool leaves; no requestId) instead of near-wire Query XML, so an ASL Choice written against AWS takes the right branch. Contributed by @bandle. **CloudWatch — DescribeAlarms and metric reads over CBOR** — absent optional fields (ExtendedStatistic, Unit) are omitted instead of serialized as CBOR Nil, and GetMetricStatistics/GetMetricData timestamps are tag-1 encoded, so the Terraform AWS provider >= 6.50 no longer fails with unexpected value type *cbor.Nil. Reported by @sdreger. - [v1.4.10 — August 3, 2026](https://ministack.org/blog/changelog-v1-4-10): CloudFront cache/origin-request/response-headers policies, account+region isolation for Cognito and CloudFormation, DynamoDB PartiQL RETURNING/REMOVE, EKS ListIdentityProviderConfigs, plus API Gateway, EC2, IoT, ACM, and CloudWatch CBOR fixes. **CloudFront — policies** — full CRUD plus GetConfig and ListDistributionsBy...Id for CachePolicy, OriginRequestPolicy, and ResponseHeadersPolicy, so aws_cloudfront_cache_policy / _origin_request_policy / _response_headers_policy work end-to-end; full config round-trip, ETag on every read, If-Match on update/delete, and AWS ...AlreadyExists / NoSuch... / ...InUse error codes. Reported by @wparad. **Multi-region — Cognito and CloudFormation** — both now isolate state by account and region (Cognito infers the region for unsigned data-plane requests from pool/identity IDs, tokens, sessions, or client ownership; CloudFormation stops same-name stacks colliding and exports leaking cross-region); v3 persistence with legacy self-placement. Contributed by @Areson. **EKS — ListIdentityProviderConfigs** — GET /clusters/{name}/identity-provider-configs returns the AWS-shaped {name, type} list. Contributed by @b-rajesh. **DynamoDB PartiQL — RETURNING, REMOVE, richer WHERE** — ExecuteStatement supports RETURNING ALL/MODIFIED OLD/NEW on UPDATE and ALL OLD on DELETE, the REMOVE clause, and begins_with / IN / IS MISSING predicates; an UPDATE matching no item returns ConditionalCheckFailedException. **CloudWatch — DescribeAlarms CBOR** — alarm Timestamp members are now CBOR tag 1 (epoch date-time) instead of bare uint, so the Terraform AWS provider >= 6.50 no longer fails DescribeAlarms with unexpected value type cbor.Uint. Reported by @sdreger. **API Gateway — HTTP route specificity** — the most specific matching route wins instead of the first created. Contributed by @Lukasdoe. **EC2 — real AZ IDs** — ZoneId is the region-coded form (use1-az1, euc1-az1) instead of a copy of ZoneName. Contributed by @bandle. **ACM — wildcard SAN validation** — the wildcard validation CNAME collapses onto the base domain, so aws_acm_certificate_validation resolves. Reported by @wparad. **IoT — binary payloads and SELECT projection**. Contributed by @maximoosemine. **DynamoDB — projection list-index compaction**. - [v1.4.9 — August 1, 2026](https://ministack.org/blog/changelog-v1-4-9): A new Lambda MicroVMs service, region isolation for 11 more services, presigned S3 URL signature verification, plus Step Functions, IoT, and SNS fixes. **Lambda MicroVMs — new service** — the AWS Lambda MicroVM control plane (2025-09-09): run/get/list/suspend/resume/terminate MicroVMs, create images and auth tokens; MicroVMs go straight to RUNNING and images to CREATED; account+region scoped. Reported by @wparad. **Multi-region — 11 more services** — EC2, CloudTrail, ECR, Glue, OpenSearch, WAFv2, and Backup (contributed by @Areson) plus ACM, ELB, MediaConnect, and RDS Data now isolate state by account and region; WAFv2 homes CLOUDFRONT-scope resources in us-east-1 with global-segment ARNs; v3 persistence with ARN-region migration. **S3 — presigned URL verification** — presigned SigV4 URLs are now verified against the server secret (AWS_SECRET_ACCESS_KEY, default test); a bad signature or a tampered signed header (content-type, content-length) returns 403 SignatureDoesNotMatch, matching real S3; header-signed and anonymous requests unaffected. Reported by @BartekAndree. **SNS — String.Array filter policies** — each element of a String.Array attribute is evaluated separately so array attributes match. Reported by @cabrerafd. **S3 — GetBucketEncryption default** — returns the AES256 SSE-S3 default instead of ServerSideEncryptionConfigurationNotFoundError. Reported by @rsariyev-nav. **Step Functions — aws-sdk Query-protocol integrations** — EC2 list params use botocore wire names, body sent as bytes, GetQueueAttributes returns the Attributes map, IsTruncated is boolean. Contributed by @bandle. **Step Functions — wildcard path projections** resolve. Contributed by @felixp-square. **IoT — topic-rule Lambda region lookup** fixed. Contributed by @Areson. **EC2 — ModifySecurityGroupRules** implemented. Contributed by @staranto. **IAM — role update parity** (PermissionsBoundary round-trip, UpdateRoleDescription). Contributed by @jayjanssen. - [v1.4.8 — July 28, 2026](https://ministack.org/blog/changelog-v1-4-8): Region isolation for AWS IoT and AppSync Events, plus S3 Tables Iceberg and CloudFormation fixes, Step Functions JSONPath array indexes, and an aws-cdk-local cross-stack deploy fix. **AWS IoT — account+region-scoped state** — the control plane (Things, thing types, thing groups, certificates, policies, topic rules, device shadows) and the MQTT broker (clients, persistent sessions, subscriptions, retained messages) now scope by account and region; the request region threads through the HTTP and WebSocket MQTT paths and exact scope is required before topic-wildcard matching so signer-controlled values can't cross regions; v3 persistence with ARN-region migration. Contributed by @Areson. **AppSync Events — account+region-scoped state** — Event APIs, channel namespaces, and API keys scope by account and region, with the WebSocket and HTTP data planes resolving an API's creation region while preserving SigV4 credential-region enforcement and per-API fan-out isolation; v3 persistence. Contributed by @Areson. **Step Functions — JSONPath array indexes in context paths** — references like `$$.Map.Item.Value.values[0].name` resolve instead of returning `null`. Contributed by @felixp-square. **S3 Tables — Iceberg REST idempotent commits** — `add-schema`/`add-spec`/`add-sort-order` are now idempotent by id, fixing a Spark "Multiple entries with same key" crash on re-declared schemas. Contributed by @squirmy. **S3 Tables — CloudFormation schema wiring** — `AWS::S3Tables::Table` now reads `IcebergMetadata.IcebergSchema.SchemaFieldList` into the table's Iceberg schema instead of creating an empty one. Contributed by @ryan-bennett. **CloudFormation — cross-stack deploys** — `aws-cdk-local`'s `Fn::GetStackOutput` intrinsic now resolves to the referenced stack's output, fixing a `'dict' object has no attribute 'startswith'` crash on `cdklocal deploy --all`. Reported by @jacsonrsasse. - [v1.4.7 — July 26, 2026](https://ministack.org/blog/changelog-v1-4-7): New Amazon Bedrock AgentCore service, Kinesis Data Firehose Apache Iceberg (S3 Tables) delivery plus CloudFormation, S3 `GetObjectAttributes`, SNS `ListPlatformApplications`, three more region-isolated services, and DynamoDB/S3 Tables/Lambda/SQS/Cognito fixes. **Amazon Bedrock AgentCore — new service** — agent-runtime control plane (`CreateAgentRuntime`/`GetAgentRuntime`/`ListAgentRuntimes`/`UpdateAgentRuntime`/`DeleteAgentRuntime`, `ListAgentRuntimeVersions`, and the runtime-endpoint CRUD) plus a deterministic `InvokeAgentRuntime` data plane that echoes the request payload; ARNs, status transitions (`CREATING`/`UPDATING`→`READY`), and shapes are verified against botocore, and all state is account+region scoped. Reported by @wolfgangmeyers. **Kinesis Data Firehose — Apache Iceberg (S3 Tables) delivery** — a DirectPut stream with an `IcebergDestinationConfiguration` writes records into the target Iceberg table with Merge-on-Read semantics (`insert`/`update`/`delete` on `UniqueKeys`) through the DuckDB-backed S3 Tables Iceberg REST catalog, and `AWS::KinesisFirehose::DeliveryStream` provisions through CloudFormation. Contributed by @squirmy. Reported by @ryan-bennett. **S3 — `GetObjectAttributes`** — returns the attributes document (`ETag` without quotes, `Checksum`, `ObjectParts`, `StorageClass` omitted for S3 Standard, `ObjectSize`) selected by the `x-amz-object-attributes` header. Reported by @JayJuch. **SNS — `ListPlatformApplications`** — lists the caller's platform applications with pagination, account+region scoped. Reported by @ctalibard-sk. **Region isolation** — MWAA, EKS, and Transfer Family move to account+region scope (on-disk format v3). Contributed by @Areson. **Fixes** — DynamoDB validation and read metering aligned with real AWS; S3 Tables Iceberg REST catalog returns the spec error envelope (`NoSuchTableException`/`NoSuchNamespaceException`); Docker-in-Docker Lambda ZIP functions populate `/var/task` via `docker cp` (`LAMBDA_REMOTE_DOCKER_VOLUME_MOUNT` deprecated, reported by @smoores-dev); SQS `QueueUrl` reflects the caller `Host` header (contributed by @thejusdutt, reported by @Millroy094); Cognito `UsernameAttributes` pools assign a UUID `Username` (contributed by @kjdev). - [v1.4.6 — July 24, 2026](https://ministack.org/blog/changelog-v1-4-6): Seven new CloudFormation resource types, REST API exports, Aurora MySQL global replication, nine more region-isolated services, and Cognito and Docker Lambda fixes. **CloudFormation** — seven resource types that rolled a stack back with `Unsupported resource type` now provision: `AWS::EC2::VPCEndpoint`, `AWS::ApiGateway::RequestValidator`, `AWS::ApiGateway::DocumentationVersion`, `AWS::AppSync::FunctionConfiguration`, `AWS::Lambda::Url`, `AWS::Logs::ResourcePolicy`, and `AWS::CloudFront::CloudFrontOriginAccessIdentity`. Contributed by @robert-pitt-foodhub. **API Gateway — `GetExport`** — export a REST API stage as OpenAPI 3 (`oas30`) or Swagger 2 (`swagger`), JSON or YAML, with the optional `integrations` extension. Contributed by @robert-pitt-foodhub. **RDS — Aurora MySQL global replication** — Aurora MySQL 8 global clusters replicate from the global writer to secondary-region readers over GTID-based binary log replication. Contributed by @Areson. **Region isolation** — Athena, Auto Scaling, Cloud Map, EFS, EMR, Inspector2, Amazon MQ, AppSync, and S3 Files move to account+region scope (on-disk format v3). Contributed by @Areson. **Fixes** — API Gateway v2 omits `queryStringParameters`/`body` instead of sending `null` (contributed by @ryan-bennett); Cognito Hosted UI binds the auth code to the resolved Username instead of the raw email alias (contributed by @kjdev); Docker-executed custom resources rewrite the `ResponseURL` `localhost` to `host.docker.internal` so callbacks no longer hang (reported by @robert-pitt-foodhub). - [v1.4.5 — July 22, 2026](https://ministack.org/blog/changelog-v1-4-5): Eight new CloudFormation resource types, OpenSearch package management, Cognito `GetTokensFromRefreshToken` for aws-amplify v6.15+, Batch and SES region isolation, and CloudFront/SQS/API Gateway/EC2/Lambda fixes. **CloudFormation** — eight resource types that rolled a stack back with `Unsupported resource type` now provision: `AWS::ApiGateway::Model`, `AWS::ApiGateway::DomainName`, `AWS::ApiGateway::BasePathMapping`, `AWS::ApiGateway::DocumentationPart` (with the native documentation-part control plane), `AWS::Lambda::EventInvokeConfig` (per-qualifier), `AWS::CloudWatch::Dashboard`, `AWS::OpenSearchService::Domain`, and `AWS::Cognito::UserPoolGroup`. Contributed by @robert-pitt-foodhub and @ryan-bennett. **OpenSearch — packages** — `CreatePackage`/`UpdatePackage`/`DescribePackages`/`DeletePackage`/`AssociatePackage`/`DissociatePackage`/`ListPackagesForDomain`, with `AVAILABLE`/`ACTIVE` reported immediately. Reported by @Simon-Hayden-Dev. **Cognito** — resource servers (`CreateResourceServer` … `ListResourceServers`) plus `AWS::Cognito::UserPoolResourceServer` (contributed by @ryan-bennett), and `GetTokensFromRefreshToken`, the only session-refresh path aws-amplify v6.15+ uses, returning the `REFRESH_TOKEN_AUTH` `AuthenticationResult` shape (reported by @scriptgenerator64). **Region isolation** — Batch and SES move to account+region scope with a versioned regional persistence schema. Contributed by @Areson. **Fixes** — CloudFront `CreateInvalidation` on CFN-created distributions (contributed by @robert-pitt-foodhub); CDK S3 notification custom-resource hangs (contributed by @robert-pitt-foodhub); API Gateway `AWS::ApiGateway::Stage` `Ref` returns the stage name (contributed by @robert-pitt-foodhub); SQS `ListQueues` returns/accepts `NextToken` (contributed by @bfreitastgtg); EC2 `DescribeSecurityGroupRules` returns rule `Tags` and `SecurityGroupRuleArn` (reported by @staranto); Cognito CFN `AWS::Cognito::UserPool` honors `LambdaConfig` (contributed by @ryan-bennett). - [v1.4.4 — July 22, 2026](https://ministack.org/blog/changelog-v1-4-4): Aurora cluster shared storage, ElastiCache Valkey, s3tables CloudFormation and Iceberg REST, KMS data key pairs, ALB instance/ip forwarding, GatewayResponse CloudFormation, Cognito Hosted UI password change, and three more region-isolated services. **RDS — Aurora shared storage** — cluster members share one cluster-owned container so tables/users/grants are visible through the writer and reader endpoints and the RDS Data API; `DisableHttpEndpoint` mirrors `EnableHttpEndpoint`. Contributed by @Areson and @jayjanssen. **ElastiCache — Valkey** — `Engine=valkey` spawns real `valkey/valkey:-alpine` containers on port 6379 (AWS versions 7.2/8.0/8.1), previously misrouted to memcached's 11211. Contributed by @jasondcamp. **KMS** — `GenerateDataKeyPair`/`GenerateDataKeyPairWithoutPlaintext` generate an asymmetric data key pair wrapped under a symmetric CMK. Contributed by @yl. **ALB** — data-plane forwarding to `instance`/`ip` targets over HTTP with `X-Forwarded-*` and `X-Amzn-Trace-Id`; connection failures return `502`. Contributed by @jasondcamp. **CloudFormation** — `AWS::ApiGateway::GatewayResponse` provisions with the v1 `PutGatewayResponse`/`GetGatewayResponse(s)`/`DeleteGatewayResponse` control plane (contributed by @robert-pitt-foodhub); `AWS::S3Tables::TableBucket`/`Namespace`/`Table` provision and the DuckDB-backed Iceberg REST catalog is served (contributed by @squirmy). **Cognito** — `NEW_PASSWORD_REQUIRED` first-login users get a change-password form in the Hosted UI. Contributed by @kjdev. **EventBridge Scheduler, CodeBuild, Resource Groups — region-isolated state** — three more services move to account+region scope with a versioned regional persistence schema. Contributed by @Areson. **Fixes** — Batch `UpdateComputeEnvironment` resolves by name or ARN (reported by @smoores-dev); S3 keeps empty object tag values (contributed by @murlock); EC2 `DescribeSecurityGroupRules` honors `SecurityGroupRuleIds` with stable rule ids (reported by @staranto); Lambda docker workers respawn on `UpdateFunctionConfiguration` (reported by @ykharko). - [v1.4.3 — July 18, 2026](https://ministack.org/blog/changelog-v1-4-3): IoT device shadows and topic-rule routing to Lambda, region-isolated EventBridge/ECS/Firehose, AWS::ApiGatewayV2::Authorizer CloudFormation support, and Cognito/Lambda/S3 fixes. **IoT — device shadows** — `GetThingShadow`/`UpdateThingShadow`/`DeleteThingShadow` on the `iot-data` endpoint (classic and named shadows) store `desired`/`reported` state with deep-merge, per-attribute `metadata` timestamps, computed `state.delta` and `metadata.delta`, `409` on stale `version`, and version kept on delete. Contributed by @maximoosemine. **IoT — topic-rule routing to Lambda** — MQTT/`iot-data` publishes match each account's topic rules by their `FROM ''` clause (`+`/`#` wildcards) and invoke matching enabled rules' `lambda` actions; Basic Ingest to `$aws/rules/` bypasses pub/sub. Contributed by @maximoosemine. **EventBridge, ECS, Firehose — region-isolated state** — three more services move to account+region scope; legacy state migrates from stored ARNs (ECS on-disk format v3). Contributed by @Areson. **CloudFormation — `AWS::ApiGatewayV2::Authorizer`** — deploys and `AWS::ApiGatewayV2::Route` carries `AuthorizerId`/`AuthorizationScopes` so the route is enforced. Contributed by @ryan-bennett. **Cognito** — `PreSignUp_ExternalProvider` fires on SAML/OIDC federated sign-up fail-closed (`UserLambdaValidationException`), federated users keep `UserStatus: EXTERNAL_PROVIDER`; `PreTokenGeneration` `triggerSource` reflects the call path (`TokenGeneration_RefreshTokens`/`TokenGeneration_HostedAuth`); `ListUsers` `status` filter matches the `Enabled` boolean. Contributed by @kjdev and @jey-mfv. **Lambda** — Node warm-worker no longer fails on `fs.writeSync`/`fs.write` to fd 1 (reported by @kofuk, contributed by @vvaide); `X-Amz-Log-Result` returned only for `LogType=Tail` (reported by @w-zx, contributed by @Sanjays2402); event source mappings pace failed-invoke retries per ESM (contributed by @squirmy). **S3** — a versioned delete with an explicit `VersionId` removes that exact version/marker (contributed by @asleeponduty); versioned reads preserve `Content-Type` (reported by @aaronsteed, contributed by @vvaide); `CreateBucket` applies and validates request-body `Tags` (contributed by @nirajsapkota). **EventBridge Pipes** — a cross-region source or target is rejected before any state is written. Contributed by @Areson. - [v1.4.2 — July 13, 2026](https://ministack.org/blog/changelog-v1-4-2): DynamoDB validation parity verified against real AWS, region-isolated SNS/Kinesis/KMS/ElastiCache, IoT TopicRule CloudFormation, Step Functions Lambda write SDK tasks, and WebSocket/S3/SQS fixes. **DynamoDB — validation parity with real AWS** — eight gaps where MiniStack silently accepted requests real AWS rejects, all verified against real AWS DynamoDB: `GetItem`/`DeleteItem`/`BatchGetItem` reject empty string/binary key values; `BatchWriteItem` validates every member before applying any; `TransactWriteItems` validates members up front and matches AWS's two failure shapes (empty key values are a top-level `ValidationException`; wrong-typed keys and update-expression type errors cancel with a positional `ValidationError` reason); `Query` rejects inverted `BETWEEN` bounds at parse time, empty key-condition operands, and an `ExclusiveStartKey` outside the range predicate; `UpdateItem` `SET` rejects unresolvable document paths and `ADD`/`DELETE` enforce operand types with exact AWS error strings. Contributed by @ifutivic. **DynamoDB — `LastEvaluatedKey` at exact `Limit`** — real DynamoDB doesn't look ahead: stopping because of the limit always returns a key, and the follow-up page is empty with no key; pagination helpers now behave identically against MiniStack and AWS. Contributed by @ifutivic. **SNS, Kinesis, KMS, ElastiCache — region-isolated state** — four more services move to account+region scope (SNS topics/subscriptions/platform endpoints; Kinesis streams, warm-boot-surviving shard iterators, consumers; per-region KMS keys and aliases; all ElastiCache stores with account+region container naming); legacy state migrates from stored ARNs. Contributed by @Areson. **IoT — `AWS::IoT::TopicRule` CloudFormation** — the provisioner plus `CreateTopicRule`/`GetTopicRule`/`ListTopicRules`/`ReplaceTopicRule`/`DeleteTopicRule`. Contributed by @maximoosemine. **Step Functions — `aws-sdk:lambda` write actions** — `createFunction`, `updateFunctionConfiguration`, `updateFunctionCode`, `createAlias`, `updateAlias` dispatch through the Lambda REST emulator; SFN-convention `KmsKeyArn` maps to wire-form `KMSKeyArn`. Contributed by @Areson. **Fixes** — API Gateway v2 WebSocket `$connect` now invokes JWT authorizers (close 1008 on missing/invalid token, claims in `requestContext.authorizer.jwt`), reported by @Lukasdoe; S3 versioned `GetObject` returns the body after a restart with `S3_PERSIST=1`, reported by @adzcodemi; SQS XML error responses carry the legacy `awsQueryCompatible` codes (`AWS.SimpleQueueService.NonExistentQueue`), reported by @play4uman. - [v1.4.1 — July 9, 2026](https://ministack.org/blog/changelog-v1-4-1): EKS pulls from local ECR, Aurora MySQL 8.4, region-isolated EventBridge Pipes, Python 3.13 images, and Lambda/S3/Cognito fixes. **EKS — clusters pull images from local ECR** — every k3s cluster boots with an auto-injected `/etc/rancher/k3s/registries.yaml` mapping the cluster's ECR registry hostname (`.dkr.ecr..amazonaws.com`) to the MiniStack gateway (MiniStack's address on the shared Docker network when detected, else `host.docker.internal` via `host-gateway`), so `kubectl run` with an ECR image URI pulls what you pushed to local ECR with no manual wiring. Reported by @L3337. **RDS — Aurora MySQL 8.4 and version-mapped images** — engine versions select the matching MySQL image track (5.7/8.0/8.4) instead of the floating `mysql:8` tag; `DescribeDBEngineVersions` returns the full creatable catalog with per-family parameter groups including `8.4.mysql_aurora.8.4.7`/`aurora-mysql8.4`; unknown explicit versions are rejected with the AWS error shape. Contributed by @Areson. **EventBridge Pipes — region-isolated state** — pipe records and stream positions move to account+region scope; same-name pipes in different regions no longer collide and the poller runs each pipe under its own scope; legacy state migrates from pipe ARNs. Contributed by @Areson. **Docker images — Python 3.13** — both images move from `python:3.12` to `python:3.13`, clearing the CPython 3.12 interpreter CVEs; the full image also runs `apt-get upgrade` for Debian base patches. Contributed by @scottschreckengaust. **Fixes** — Lambda `provided.*`: concurrent invocations no longer fail with `ETXTBSY` (extraction is content-addressed per code sha256 with spawns serialized against extraction), and `AWS_LAMBDA_FUNCTION_MEMORY_SIZE`/`AWS_LAMBDA_FUNCTION_VERSION`/`AWS_LAMBDA_LOG_STREAM_NAME` are re-injected from the function config (1.4.0 regression that crashed the Rust `lambda_runtime`), both reported by @crestonbunch; SQS event source mappings deliver `messageAttributes` with camelCase inner keys as real Lambda does (fixes Java `SQSEvent.MessageAttribute` handlers), reported by @w-zx; S3 `versionId` survives payload persistence to a volume (`S3_PERSIST=1`), reported by @adzcodemi; Cognito `ListUsers` parses quoted attribute names in `Filter` (`"email" = "value"`) and logs unparseable filters instead of silently returning all users, contributed by @kjdev. - [v1.4.0 “Areson” — July 8, 2026](https://ministack.org/blog/changelog-v1-4-0): Multi-region support, four new Amazon Bedrock services, and Amazon MSK. **Multi-region support** — resource state is isolated per account *and* region; the request region comes from the SigV4 credential scope (header or presigned query), so two clients pointed at different regions see fully independent state, matching real AWS. Region-isolated in this release: AppConfig, Bedrock (all four services), CloudWatch, CloudWatch Logs, DynamoDB (tables, metadata, Streams), Lambda (functions, event source mappings, durable executions), MSK, RDS, S3 Tables, Secrets Manager, SQS, SSM Parameter Store, and Step Functions. Cross-resource references resolve in the referenced ARN's own account and region, background workers re-scope per tenant, and cross-region references real AWS rejects return the same errors AWS returns. Persisted state moves to on-disk format v2 with a version stamp (newer-format files are refused on downgrade); legacy account-scoped state loads and migrates automatically, recovering regions from stored ARNs. Not yet region-isolated (S3, SNS, IAM/STS, EC2, Kinesis, EventBridge, ECS, ECR, EKS, EFS, KMS, Glue, Athena, API Gateway v1/v2, Cognito, CloudFormation, CloudFront, Route 53, ElastiCache, EMR, Firehose, SES, CodeBuild, AutoScaling, WAF, ACM, Backup, Organizations, EventBridge Scheduler, Transfer Family, AppSync, CloudTrail, and the remaining control-plane services) — these share state across regions within an account as in 1.3.x. Contributed by @Areson. **Amazon Bedrock — four new services** — bedrock control plane (66 operations verified against botocore: foundation-model catalog with real model IDs, inference profiles, guardrails with versioning, custom/imported models, provisioned throughput, customization/import/copy/batch-invocation jobs), bedrock-runtime (`Converse`, `ConverseStream`, `InvokeModel`, `InvokeModelWithResponseStream` with real eventstream wire format, `ApplyGuardrail`, async invokes — deterministic family-aware mocks by model ID prefix; `MINISTACK_BEDROCK_PROXY_URL` forwards Converse/InvokeModel to any OpenAI-compatible endpoint — Ollama, llama.cpp, vLLM — for real completions), bedrock-agent (72 operations — agents, knowledge bases, flows, prompts), bedrock-agent-runtime (31 operations — InvokeAgent, Retrieve/RetrieveAndGenerate, reranking, sessions, flow executions). Led by @dcabib. **Amazon MSK** — Kafka control plane: cluster lifecycle, configurations with revisions, SCRAM secrets, tagging; `GetBootstrapBrokers` honors `MINISTACK_MSK_BOOTSTRAP` (plus `_TLS`/`_SASL_SCRAM`/`_SASL_IAM` variants) to route clients to a real broker (Redpanda, Kafka, KRaft); the Kafka wire protocol is not emulated. - [v1.3.72 — July 6, 2026](https://ministack.org/blog/changelog-v1-3-72): EC2 placement group actions and Auto Scaling groups that report in-service instances so Terraform capacity waiters converge, plus presigned-URL account scoping, the EKS OIDC issuer scheme, and DynamoDB UpdateItem validation. **EC2 — placement group actions** — `CreatePlacementGroup`, `DeletePlacementGroup`, and `DescribePlacementGroups` are implemented (previously `InvalidAction: Unknown EC2 action`), so `aws_placement_group` creates, reads, and deletes; account-scoped, tagged like other EC2 resources (`pg-` ids, tag filters), with `InvalidPlacementGroup.Duplicate`/`InvalidPlacementGroup.Unknown` and `partitionCount` only for the `partition` strategy. Contributed by @c-julin. **Auto Scaling — capacity waiters converge** — `CreateAutoScalingGroup`/`UpdateAutoScalingGroup`/`SetDesiredCapacity` materialize `DesiredCapacity` in-service instances (round-robined across the group's AZs) and `DescribeAutoScalingGroups`/`DescribeAutoScalingInstances` report them; previously a group reported zero forever, so Terraform's `aws_autoscaling_group` capacity waiter blocked the full `wait_for_capacity_timeout` and failed on every apply. Contributed by @c-julin. **Router — presigned-URL account scoping** — the per-request account and CloudTrail attribution were read only from the Authorization header, so a presigned S3 URL under a non-default account resolved to the default account and 404'd; the access key is now also extracted from the SigV4 `X-Amz-Credential` and SigV2 `AWSAccessKeyId` query parameters. Contributed by @neriyaco. **EKS — OIDC issuer scheme follows `USE_SSL`** — the cluster issuer advertised by `DescribeCluster` and the discovery document was hardcoded http, failing Terraform's `aws_iam_openid_connect_provider` (which rejects non-https urls) at plan time; the scheme now derives from `USE_SSL` (https when the gateway serves TLS, http otherwise). **DynamoDB — `UpdateItem` validation and `UPDATED_NEW`/`UPDATED_OLD`** — UpdateItem now runs the same value/size validation as PutItem, and the return values report every attribute the update expression touched, including a same-value SET, matching AWS. Contributed by @chincharjuin. - [v1.3.71 — July 6, 2026](https://ministack.org/blog/changelog-v1-3-71): EventBridge Scheduler now fires standalone schedules, plus S3 GetObject TagCount, API Gateway v2 rawQueryString, and CloudFormation Lambda event source mapping fixes. **EventBridge Scheduler — standalone schedules fire their targets** — a background sweep invokes each `ENABLED` schedule's target (Lambda, SQS, SNS, Step Functions) when due, supporting `at()`/`rate()`/`cron()` expressions and honoring `State`, `StartDate`/`EndDate`, and `ActionAfterCompletion: DELETE`; previously the `scheduler` API stored schedules but never fired them. Reported by @BarkinBalci. **Lambda — event source mappings accept and persist `ScalingConfig` (`MaximumConcurrency`)** — round-trips the SQS-trigger `scaling_config`, validated to 2–1000 and restricted to Amazon SQS sources (rejected with `InvalidParameterValueException` elsewhere). Contributed by @liammizrahi. **Organizations — `ListParents` + tag ops for the OU Terraform round-trip** — `ListParents` populates `parent_id` (which `DescribeOrganizationalUnit` omits) and `TagResource`/`UntagResource`/`ListTagsForResource` are added, so `aws_organizations_organizational_unit` applies cleanly. Contributed by @b-rajesh. **CloudTrail — `CreateTrail` persists `KmsKeyId`** — so `DescribeTrails`/`GetTrail` echo it and `aws_cloudtrail` converges in a single apply. Contributed by @b-rajesh. **S3 — `GetObject` returns `x-amz-tagging-count` (`TagCount`)** — present only when the object has at least one tag, matching AWS; the header was never sent before. Reported by @vschreiner. **API Gateway v2 — `rawQueryString` stays percent-encoded** — it was rebuilt from URL-decoded params, turning `%20` into a literal space and 502-ing Rust `lambda_http` functions; each key/value is now re-encoded. Reported by @crestonbunch. **CloudFormation — `AWS::Lambda::EventSourceMapping` round-trips all optional properties and updates in place** — it kept only `FilterCriteria` and dropped `DestinationConfig`/`ParallelizationFactor`/the retry-age knobs/`ScalingConfig`, and a stack update duplicated the mapping instead of mutating it in place. Contributed by @maximoosemine. - [v1.3.70 — June 30, 2026](https://ministack.org/blog/changelog-v1-3-70): SNS mobile-push endpoint lifecycle, CloudFormation AWS SAM transform expansion (full image), and IAM group policies, plus S3→EventBridge, OIDC, Lambda worker, and Cognito fixes. **CloudFormation — AWS SAM transform (`AWS::Serverless-2016-10-31`) templates expanded into native CloudFormation** — via the canonical `aws-sam-translator` (the library the SAM CLI uses), on create/update/change-set; ships in the full image only. Contributed by @maximoosemine. **IAM — group policy attach/detach and inline group policies** — `AttachGroupPolicy`, `DetachGroupPolicy`, `ListAttachedGroupPolicies`, `PutGroupPolicy`, `GetGroupPolicy`, `DeleteGroupPolicy`, `ListGroupPolicies`. Contributed by @maxflorentin. **SNS — mobile-push endpoint lifecycle** — `GetEndpointAttributes`, `SetEndpointAttributes`, `DeleteEndpoint`, `DeletePlatformApplication` complete the platform-endpoint flow; `CreatePlatformEndpoint` dedups by device token and `Publish` to a platform-endpoint `TargetArn` now succeeds. Contributed by @sjincho. **S3 — S3→EventBridge events use AWS-conformant `detail-type`, `reason`, and `deletion-type`** — delivery string-mangled the `detail-type` (`Object ObjectCreated Put` instead of `Object Created`), so rules matching the documented type silently never fired. Contributed by @lucasmfraser. **API Gateway — failed OIDC discovery is negative-cached** — a transient failure cached `jwks_uri = None` for the full 7200s TTL, breaking JWT validation for up to two hours; discovery now caches success for 7200s and failure for only 60s. Contributed by @Pratham2703005. **Lambda — worker respawn cleans up the previous tmpdir and terminates the dead process**. Contributed by @hiddengearz. **Cognito — OAuth2 Basic-auth client secret containing `+` no longer corrupted** — the decode used `unquote_plus`, turning a literal `+` into a space; it now uses `unquote`. Contributed by @jgrumboe. - [v1.3.69 — June 27, 2026](https://ministack.org/blog/changelog-v1-3-69): EKS DescribeCluster endpoint and SQS XML message validation fixes. **EKS — `DescribeCluster` returns a host-reachable endpoint on every path** — it now advertises the host-published port `https://{MINISTACK_HOST}:{port}` (default `localhost`) on cluster create, OIDC-config restart, and persistence restore; previously the failure-fallback and restore paths could leave a stale value, so `aws eks update-kubeconfig` + kubectl from the host got an unreachable endpoint. The k3s container publishes 6443 to that host port, so the endpoint works from the host and from containers that can route to `MINISTACK_HOST`. Contributed by @b-rajesh. **SQS — `SendMessage` rejects message bodies with XML 1.0 forbidden characters** — AWS SQS only accepts characters valid in XML 1.0 and returns `InvalidMessageContents` for anything else; MiniStack silently accepted them, so a payload that fails against real AWS passed locally. `SendMessage` and every `SendMessageBatch` entry now reject C0 control characters other than tab/LF/CR, the surrogate block `#xD800`–`#xDFFF`, and `#xFFFE`/`#xFFFF` with `InvalidMessageContents`. Contributed by @yamachu. - [v1.3.68 — June 25, 2026](https://ministack.org/blog/changelog-v1-3-68): Cognito HTTP Basic Auth, Step Functions Lambda, and SNS async delivery fixes. **Cognito — OAuth2 token endpoint URL-decodes HTTP Basic client credentials** — a `client_secret` with `/` or `+` arrives in the `Authorization: Basic` header as `%2F`/`%2B` (RFC 6749 §2.3.1 form-urlencodes the credentials before base64); MiniStack didn't decode them, so `client_secret_basic` failed with `invalid_client` for any secret with special characters; they're now decoded, matching the `client_secret_post` path. Reported by @pny-nc. **Step Functions — `lambda:invoke.waitForTaskToken` delivers the unwrapped `Payload`** — the callback path forwarded the whole `{"FunctionName": ..., "Payload": {...}}` envelope instead of just the `Payload`, so a handler reading its task token / input from the top level never resumed the task and the execution hung. Contributed by @ryan-bennett. **Step Functions — a failed `lambda:invoke` task sets `Cause` to a JSON-encoded error payload** — `Cause` was the bare `errorMessage` string instead of AWS's `{"errorType": ..., "errorMessage": ..., "trace": [...]}`, so `Catch` handlers that `json.loads(Cause)` failed to parse it; `Cause` now matches the AWS wire form. Contributed by @ryan-bennett. **SNS — `lambda` subscribers delivered asynchronously** — fanout invoked the subscriber synchronously inside `Publish`, so a slow subscriber blocked `Publish` and its upstream caller; delivery now runs on a background thread, matching AWS's asynchronous SNS→Lambda delivery, so `Publish` returns immediately. Contributed by @ryan-bennett. - [v1.3.67 — June 24, 2026](https://ministack.org/blog/changelog-v1-3-67): API Gateway OpenAPI imports + EC2 instance-profile APIs, plus Cognito/API Gateway/RDS Data fixes. **CloudFormation / API Gateway — `AWS::ApiGateway::RestApi` imports an OpenAPI `Body` (added)** — a REST API defined inline through the `Body` property materializes its paths, methods, and `x-amazon-apigateway-integration` blocks as real resources, methods, and integrations, covering the basic SAM-transform Swagger 2.0 + Lambda-proxy shape; partial support, with authorization/validation/most extensions not yet handled. Contributed by @maximoosemine. **EC2 — IAM instance-profile association APIs (added)** — `AssociateIamInstanceProfile`, `DescribeIamInstanceProfileAssociations`, `ReplaceIamInstanceProfileAssociation`, `DisassociateIamInstanceProfile`, with launch-time backfill and termination cleanup, so Terraform's `aws_instance` `iam_instance_profile` round-trips without drift. Contributed by @D-artisan. **Cognito — OAuth2 token endpoint no longer consumes the authorization code on a failed client-secret check** — bad client auth consumed the one-time code before failing, so a Basic-then-`client_secret_post` retry (Go/Vault) got `invalid_grant`; credentials are now validated before the code is consumed. Reported by @pny-nc. **API Gateway v1 — literal path segments resolve ahead of a `{param}` sibling regardless of creation order** — a literal path (e.g. `/users/verifyUserEmail`) returned 405 when a `{id}` sibling was registered first; resolution now orders literal > `{param}` > `{proxy+}`. Reported by @ethan-dyas438. **RDS Data API — `:name` placeholders substituted by whole token** — the earlier substring replace corrupted unrelated longer tokens (`:id` ate into `:identity`) and was fragile around `::type` casts; a single token-aware pass keeps `:1`/`:10` distinct, leaves `::jsonb` casts intact, and passes through any `:word` that is not a supplied parameter. Reported by @awilson9. **Docs — AWS SAM transform macro clarified as unsupported** — `Transform: AWS::Serverless-2016-10-31` is not expanded; the docs point to the IaC guidance and MiniStack MCP. Contributed by @dashitongzhi. - [v1.3.66 — June 22, 2026](https://ministack.org/blog/changelog-v1-3-66): ElastiCache parity + IAM X-Ray policies, plus CloudFormation/Step Functions/Cognito/RDS fixes. **ElastiCache — broad parity (added)** — built-in `default.*` parameter groups for Redis, Memcached, and Valkey (including `.cluster.on`) with engine-version→family mapping; seeded defaults are immutable; replication-group creation materializes member clusters (metadata, tags, IDs) and deletes them on removal; create/modify validate user groups; tag updates fan out to member ARNs; ElastiCache is now in the Resource Groups Tagging API; user/user-group error codes use AWS wire forms (`UserNotFound`, `UserGroupNotFound`). Contributed by @ZiningYin. **IAM — managed policies seeded (added)** — `AWSXRayDaemonWriteAccess`, `AWSXrayReadOnlyAccess`, `AWSLambdaRole` pre-seeded with canonical documents, so Terraform's `attach_tracing_policy` lookup resolves. Contributed by @mattwang44. **CloudFormation — `deploy` without `--parameter-overrides` now updates resources** — a `UsePreviousValue=true` change set resolved parameters to empty, so a parameter-driven resource name resolved wrong and the update missed the real resource; `UsePreviousValue` is now resolved against the stack's stored parameters. Reported by @ankitaabad. **Step Functions — `.waitForTaskToken` invokes non-Lambda integrations** — `sqs:sendMessage.waitForTaskToken` (and `sns:publish`, `dynamodb:*`, `aws-sdk:*`) scheduled the task but never performed the integration, so the token payload was never sent and the execution hung; the callback path now dispatches the integration before blocking, and object `MessageBody` is JSON-serialized for SQS. Reported by @taylor1791. **RDS Data API — PostgreSQL fixes** — psycopg2 connections autocommit (so non-transactional `ExecuteStatement` isn't rolled back); named params substituted longest-first so `:1` doesn't corrupt `:10`/`:18`; `jsonb` returned as JSON text. Reported by @awilson9. **Cognito — token invalidation takes effect** — `RevokeToken`/`GlobalSignOut`/`AdminUserGlobalSignOut` were no-ops; they now invalidate refresh tokens and `REFRESH_TOKEN_AUTH` honours it. **RDS — `CreateDBInstance`/`CreateDBCluster` validate parameter-group existence** — a missing custom group returns `DBParameterGroupNotFound`/`DBClusterParameterGroupNotFound`. **Athena — `GetTableMetadata`/`ListTableMetadata` return real columns and partition keys** instead of empty stubs. **SNS — `Publish` accepts non-string `Message`** — Step Functions object payloads are JSON-serialized before delivery. Contributed by @noynoy83. **CI — test suite sharded across parallel runners** for faster CI. Contributed by @jgrumboe. - [v1.3.65 — June 19, 2026](https://ministack.org/blog/changelog-v1-3-65): Fixes release across Auto Scaling, S3, API Gateway, EC2, Glue, Lambda, and ECS. **Auto Scaling — instance-refresh actions implemented** — `StartInstanceRefresh`, `DescribeInstanceRefreshes`, and `CancelInstanceRefresh` failed with `InvalidAction: Unknown AutoScaling action`; they are now handled and recorded on the group so a refresh can be started, polled, and cancelled. Contributed by @c-julin. **S3 — `GetBucketOwnershipControls` 404s after delete** — it always returned a default ownership block (200), so `DeleteBucketOwnershipControls` wasn't observable and Terraform's delete waiter looped (`found resource`); it now returns `OwnershipControlsNotFoundError` (404) once deleted, while still reporting the default for a never-configured bucket. Contributed by @c-julin. **API Gateway v2 — CloudFormation provisioner honours the `ms-custom-id` tag** — `AWS::ApiGatewayV2::Api` always got a random id, ignoring the tag even though `CreateApi` and the v1 REST provisioner honoured it; the v2 provisioner now resolves the custom id first. Contributed by @hiddengearz. **EC2 — source security groups (`UserIdGroupPairs`) returned by `DescribeSecurityGroupRules` / `DescribeSecurityGroups`** — rules referencing another security group were dropped at ingestion and never surfaced (`ReferencedGroupInfo` omitted, empty ``); now parsed and emitted by both. Reported by @kamegoro. Contributed by @kurok. **Glue — `GetUserDefinedFunctions` accepts `java.util.regex` `\Q…\E` patterns** — real AWS compiles `Pattern` with `java.util.regex`, so clients like Trino send literal-quoted patterns (e.g. `trino__\Qname\E__.*`) that Python's `re` rejected with `InvalidInputException`; the literal-quote sequences are now translated before matching. Contributed by @yonatoasis. **Lambda — function code stored as content-addressed blob files** — `get_state` base64-encoded every `code_zip` inline into `lambda.json`, so many large zips (e.g. 26 × ~30 MB) produced a ~1 GB state file that OOM'd on warm boot; code bytes are now written as content-addressed blobs and loaded lazily. Contributed by @mattwang44. **Lambda — CloudFormation/CDK-provisioned layers carry their content** — layers created via CloudFormation stored no zip data, so functions couldn't import their layer packages even though `ListLayers` showed them; the provisioner now stores the layer bytes. **Lambda — CloudFormation-created DynamoDB-stream ESMs anchor `LATEST` at create time** — matching the API path, so a `LATEST` mapping skips records that existed when the stack was deployed instead of replaying them (no-op for SQS/Kinesis). **ECS — `RunTask` secrets resolve SSM Parameter Store references** — `containerDefinitions[].secrets` `valueFrom` entries pointing at SSM were left unresolved; they are now fetched in-process and injected alongside Secrets Manager references. - [v1.3.64 — June 15, 2026](https://ministack.org/blog/changelog-v1-3-64): Fixes release across EC2, ECS, S3, CloudFormation, Lambda, CloudWatch Logs, EventBridge, Step Functions, Glue, and IAM. **EC2 — source security groups (`UserIdGroupPairs`) returned by `DescribeSecurityGroupRules` / `DescribeSecurityGroups`** — rules referencing another security group were dropped at ingestion and never surfaced (`ReferencedGroupInfo` omitted, empty ``); now parsed and emitted by both. Reported by @kamegoro. **ECS — `RunTask` injects `containerDefinitions[].secrets` from Secrets Manager** — `valueFrom` references (including the `:json-key:` form) were dropped; now resolved and merged into the container environment before overrides (SSM not yet resolved). Reported by @kamegoro. Contributed by @kurok. **ECS — `RunTask` applies `containerOverrides.command`** — an overridden command (including an explicit empty command) was ignored because Docker still used the task-definition command. Contributed by @noynoy83. **S3 — `DeletePublicAccessBlock` now actually clears the configuration** — `GetPublicAccessBlock` returned a default all-blocked 200 instead of `NoSuchPublicAccessBlockConfiguration` (404), so Terraform's delete waiter timed out; it now returns 404 when unset. Reported by @kamegoro. Contributed by @kurok. **S3 — `WebsiteRedirectLocation` preserved** — `x-amz-website-redirect-location` on `PutObject` is stored and returned by `GetObject` / `HeadObject`. Contributed by @murlock. **CloudFormation — `GetTemplateSummary` returns `Capabilities` / `CapabilitiesReason`** — computed from the template (`CAPABILITY_NAMED_IAM` / `CAPABILITY_IAM` / `CAPABILITY_AUTO_EXPAND`). Contributed by @maximoosemine. **Lambda — `CreateEventSourceMapping` persists `FilterCriteria`** — the parameter was silently dropped at creation time. Contributed by @maximoosemine. **Lambda — CloudFormation-created DynamoDB stream ESMs now poll** — an ARN-with-qualifier `FunctionName` was mis-parsed so the poller couldn't resolve the function, and a `LATEST` mapping skipped its first record on an empty table. Contributed by @maximoosemine. **CloudWatch Logs — subscription filters deliver matching log events to the destination Lambda** — a `SubscriptionFilter` (via CloudFormation or `PutSubscriptionFilter`) was provisioned but never forwarded log events; matching events from `PutLogEvents` and Lambda's own log emission are now delivered to Lambda destinations in the `awslogs` gzip+base64 `DATA_MESSAGE` envelope, with a self-loop guard. Reported by @ankitaabad. **EventBridge — reserved input-transformer variables** — ``, ``, ``, ``, `` were left literal, producing invalid JSON; they now resolve. Contributed by @AbdoNile. **Step Functions — mocked `Throw` routes to `Catch`** — a `SFN_MOCK_CONFIG` `Throw` was raised above Retry/Catch, so the execution always failed instead of routing to a matching `Catch`; it now flows through the same machinery as a real failure. Reported by @amissemer. **Glue — `GetUserDefinedFunctions` treats `Pattern` as a regex** — matched as a glob before, so patterns like Trino's `trino____.*` never matched; an invalid pattern now returns `InvalidInputException`. Contributed by @yonatoasis. **IAM — instance-profile tagging actions** — `TagInstanceProfile` / `UntagInstanceProfile` / `ListInstanceProfileTags` implemented and read back from `GetInstanceProfile` / `ListInstanceProfiles`. Contributed by @c-julin. - [v1.3.63 — June 13, 2026](https://ministack.org/blog/changelog-v1-3-63): Fixes release across Lambda, CloudFormation, and Step Functions. **Lambda — local executor exposes dependency layers' `site-packages`** — the in-process worker added `/python` to `sys.path` but not `/python/lib/python/site-packages` where `pip install -t` layers land; AWS exposes it as a site directory, so it's now added via `site.addsitedir` (so `.pth` files and namespace packages resolve too). Reported by @omargr299. **Lambda — `LoggingConfig.LogGroup` honored** — handler logs went to the default `/aws/lambda/` group instead of the configured/shared group. Reported by @ankitaabad. **CloudFormation — `AWS::Logs::SubscriptionFilter`** resource type supported (provisions against the named log group, removed on stack delete). Reported by @ankitaabad. **CloudFormation — change sets detect parameter-driven property changes** — `aws cloudformation deploy` silently no-oped when a property like a Lambda `Code` S3 key was driven by a stack parameter because the diff compared unresolved templates; it now resolves parameters/intrinsics before diffing, matching `update-stack`. Reported by @ankitaabad. **CloudFormation — `DescribeStackResources` honors the `LogicalResourceId` filter** (returns the matching resource or `ValidationError`). Contributed by @maximoosemine. **Step Functions — `Assign` applied in the JSONata mock path** — with `SFN_MOCK_CONFIG`, `Assign` blocks were silently skipped on the mock return branch, failing downstream states with `States.QueryEvaluationError: Undefined variable`. Contributed by @amissemer. **Step Functions — Pass state `Parameters` resolve context object paths** — `$$.*` resolved to `null` because the executor didn't forward the execution context. Contributed by @noynoy83. - [v1.3.62 — June 11, 2026](https://ministack.org/blog/changelog-v1-3-62): **Glue — Iceberg REST Catalog (Glue-backed)** — read-path subset of the Apache Iceberg REST OpenAPI at `/iceberg`, mirroring AWS Glue's `glue..amazonaws.com/iceberg` endpoint on the `glue` credential scope; `GET /v1/config`, `ListNamespaces`, `GetNamespace`, `ListTables`, `LoadTable`, `HEAD TableExists` (writes return 501); a Glue table participates when its `Parameters["metadata_location"]` points at an Iceberg `metadata.json` on MiniStack S3, letting DuckDB's `iceberg` extension `ATTACH` (requires `USE_SSL=1`). Contributed by @yonatoasis. **Glue — `ColumnStatistics` API family (table + partition)** — `UpdateColumnStatisticsForTable`/`Get`/`Delete` and the `*ForPartition` equivalents, account-scoped, persisted, cleared on table/partition delete. Contributed by @yonatoasis. **CloudFormation — `DescribeStackEvents` returns the initial `REVIEW_IN_PROGRESS` event for change-set-created stacks** — `CreateChangeSet --change-set-type CREATE` left an empty event list so `sam deploy` crashed reading `StackEvents[0]`. Contributed by @maximoosemine. **Step Functions — `ecs:runTask` no longer drops `ContainerOverrides`** — the Pascal→camelCase conversion only covered top-level keys, so nested `Overrides.ContainerOverrides` stayed PascalCase and was ignored; the conversion is now recursive. Contributed by @lucasmfraser. **Lambda — layers reachable in the docker executor + zip permissions preserved** — layers merge into `/opt` (not `/opt/layer_N`), unix mode bits restored so `/opt/bin` stays executable. Reported by @omargr299. **`awslocal` works in TLS mode without `--no-verify-ssl`** — resolves MiniStack's TLS cert and exports `AWS_CA_BUNDLE` only when it's a real file. Reported by @ChronosMasterOfAllTime. **Lambda — restored SQS event source mappings resume polling after a warm restart** — `lambda_svc` is eager-imported at boot when persisted ESMs exist, so the poller starts. Reported by @ChronosMasterOfAllTime. - [v1.3.61 — June 10, 2026](https://ministack.org/blog/changelog-v1-3-61): **AmazonMQ — new service (`mq`)** covering both RabbitMQ and ActiveMQ: broker lifecycle (`CreateBroker`, `ListBrokers`, `DescribeBroker`, `UpdateBroker`, `DeleteBroker`, `RebootBroker`), engine/instance metadata (`DescribeBrokerEngineTypes`, `DescribeBrokerInstanceOptions`), ActiveMQ user management, and broker tagging; brokers come up `RUNNING` immediately (metadata only, no container), state is account-scoped and persisted, and REST routing matches AWS's `mq` request URIs so boto3 and Terraform's `aws_mq_broker` work unchanged. Contributed by @lucas-giaco. **IAM — account posture**: `GetAccountSummary` (computed counts + quotas), account password policy (`GetAccountPasswordPolicy` returns `NoSuchEntity` before set, plus `Update`/`Delete`), and account aliases (`List`/`Create`/`DeleteAccountAlias`). **IAM — credential report** (`GenerateCredentialReport` + `GetCredentialReport`) builds the exact 22-column AWS CSV with live `password_enabled` / `mfa_active` / `access_key_*_active` columns and returns `ReportNotPresent` (410) before generation. Both contributed by @lahmish. **S3 — event notifications now fire for non-default accounts** — the delivery thread didn't inherit the request's account context, so it ran under `000000000000`, the account-scoped bucket-notification config resolved empty, and the event was silently dropped (SQS / SNS / Lambda / EventBridge targets also resolved under the wrong account); the thread now copies the request context. Reported by @rsking. - [v1.3.60 — June 10, 2026](https://ministack.org/blog/changelog-v1-3-60): **IAM — the identity-discovery surface posture-probing agents reach for** lands in five PRs from @lahmish: **`CreateLoginProfile` / `Get` / `Update` / `Delete`** models whether an IAM user has a console password (the signal that distinguishes a human IAM user from a service account); **virtual MFA device lifecycle** (`CreateVirtualMFADevice`, `EnableMFADevice`, `DeactivateMFADevice`, `ResyncMFADevice`, `ListMFADevices`, `ListVirtualMFADevices`, `DeleteVirtualMFADevice`) with `SerialNumber` in ARN form, `Base32StringSeed` + `QRCodePNG` blobs, `AssignmentStatus` filter defaulting to `Any`, `DeleteConflict` on assigned devices; **`GetAccountAuthorizationDetails`** — the one-shot identity graph returning `UserDetailList` / `GroupDetailList` / `RoleDetailList` / `Policies` with inline + attached policies, group memberships, instance profiles, tags, and url-encoded policy documents; **SAML provider CRUD plus `ListOpenIDConnectProviders`** for federation discovery; **Access Advisor** generate / get job handshake returning `JobStatus=COMPLETED` with an empty `ServicesLastAccessed` list. **Cognito — CUSTOM_AUTH `RespondToAuthChallenge` merges verify result into the pending round** — multi-round flows (magic-link → SMS-OTP) were stuck because the verify result was appended as a separate metadata-less `session` entry; AWS records one `ChallengeResult` per round carrying both `challengeMetadata` and `challengeResult`, the pending round is now updated in place. Contributed by @AdigaAkhil. **SQS — out-of-range numeric attributes rejected with `InvalidAttributeValue`** — `VisibilityTimeout` (0–43200), `MaximumMessageSize` (1024–262144), `MessageRetentionPeriod` (60–1209600), `DelaySeconds` (0–900), `ReceiveMessageWaitTimeSeconds` (0–20), `KmsDataKeyReusePeriodSeconds` (60–86400) are validated against the documented AWS ranges and rejected with 400 when outside or non-numeric. Reported by @dcabib. **EventBridge — `anything-but` honors nested `prefix` / `suffix` / `wildcard` matchers** — `{"anything-but": {"prefix": "TEST-"}}` was silently ignored and every event matched; the dispatcher now negates the nested filter correctly. Reported by @aldirrix. **ElastiCache — Redis container respawned after restart** — with `PERSIST_STATE=1`, restored cluster metadata reported `available` but the persisted Docker container id was dead; restored clusters and replication groups are now marked pending and lazily spawned on the first dispatcher call (under a lock to prevent double-spawn), endpoint metadata is rewritten to the fresh container before any caller can read it. Reported by @ItsSmiffy. - [v1.3.59 — June 5, 2026](https://ministack.org/blog/changelog-v1-3-59): v1.3.58 fixed Lambda layer attachment for the in-process warm worker; v1.3.59 closes the same gap for the **docker executor (DinD)** — `container.put_archive("/opt/layer_N", ...)` returned 404 because the destination subdir doesn't pre-exist in the RIE image; layers now extract into the existing `/opt` with `arcname=layer_N`. The docker warm-container pool is also reaped on `UpdateFunctionConfiguration` / `DeleteFunction` so a layer attached after the first invoke is actually mounted on the next one. Reported by @omargr299. **AppSync — AWS-standard `AppSyncResolverEvent` for `AWS_LAMBDA` data sources** — `arguments`, `source`, `request.headers`, `prev`, `stash`, `info.fieldName/parentTypeName/variables`; `AWS_LAMBDA` auth runs the authorizer first and threads its `resolverContext` into `identity`; authorizer event carries the verbatim AWS `requestContext` (`apiId` / `accountId` / `requestId` / `queryString` / `operationName` / `variables`); rejected authorizers surface as `UnauthorizedException` (HTTP 401). Contributed by @AdigaAkhil. **API Gateway v2 — JWT authorizer resolves JWKS via OIDC discovery** — the JWKS path was hardcoded to `{issuer}/.well-known/jwks.json` (404 for Salesforce `/id/keys`, Okta `/oauth2/v1/keys`, etc.); the resolver now fetches `{issuer}/.well-known/openid-configuration` and reads `jwks_uri` per the documented AWS behavior, 2h cache, Cognito short-circuit preserved, conventional path as fallback. Contributed by @Pratham2703005. **S3 — `PutObject` checksums end-to-end** — SHA256 / SHA1 / CRC32 client-supplied values are accepted; `x-amz-sdk-checksum-algorithm` triggers server-side compute and validates mismatches with `BadDigest`; `Get` / `HeadObject` surface them under `x-amz-checksum-mode: ENABLED`; `CopyObject` propagates the source's checksum; versioned reads honor per-version checksums; checksums never accompany a `206 Partial Content` reply; CRC32C / CRC64NVME are rejected with `InvalidRequest` instead of silently round-tripping unverifiable client-supplied values. Reported by @Guigoz. **S3 — on-disk bucket directory is account-scoped** — `CreateBucket`'s `makedirs` was at `DATA_DIR/` while every object write goes to `DATA_DIR///`; now scoped end-to-end, and `DeleteBucket` cleans it up. Reported by @rsking. **Glue — `BatchUpdatePartition`** — closes the last partition action; matches AWS per-entry shape (`Entries[*].{PartitionValueList, PartitionInput}` in, `Errors[*].{PartitionValueList, ErrorDetail}` out); preserves `CreationTime`, refreshes `LastAccessTime`. Contributed by @yonatoasis. **Glue — `StartJobRun` script resolution + crawler completion under non-default accounts** — `_resolve_script` built an unscoped on-disk path so file-backed scripts never matched; `_finish_crawl` ran on a `threading.Timer` without contextvars so crawlers under non-default accounts hung in `RUNNING` forever. Both background paths now carry the request's account via `contextvars.copy_context().run(...)`, mirroring the established `stepfunctions.py` / `rds.py` idiom. Contributed by @AdigaAkhil. **CloudFormation — AppConfig `Environment` / `ConfigurationProfile` / `HostedConfigurationVersion` / `DeploymentStrategy` / `Deployment`** — the rest of the AppConfig CFN surface (Application landed in v1.3.55); property names, defaults, Ref returns and `Fn::GetAtt` attribute names match the AWS reference verbatim; `HostedConfigurationVersion` enforces the optional `LatestVersionNumber` locking token; `Deployment` tags stored against the AWS-shape ARN. Reported by @zdenekmartinec. - [v1.3.58 — June 4, 2026](https://ministack.org/blog/changelog-v1-3-58): The headline fix: **Lambda — `UpdateFunctionConfiguration(Layers=[...])` finally works after the first invoke** — `GetFunctionConfiguration.Layers[*].CodeSize` now reports the layer's real zip size (was hardcoded `0` in both `CreateFunction` and `UpdateFunctionConfiguration`); the warm worker is recycled when `Layers` / `Runtime` / `Handler` / `Environment` / `MemorySize` / `Architectures` / `VpcConfig` / `FileSystemConfigs` change, so the next `Invoke` mounts the layer at `/opt/layer_N` and the handler can `import` from it. Reported by @omargr299. **KMS — Ed25519 (`ECC_NIST_EDWARDS25519`) sign / verify** — real Ed25519 keypair generation; `SigningAlgorithms=["ED25519_SHA_512","ED25519_PH_SHA_512"]` per the AWS Developer Guide "Supported signing algorithms for ECC key specs" table; `Sign` / `Verify` enforce `MessageType=RAW` for `ED25519_SHA_512`; `ED25519_PH_SHA_512` (Ed25519ph / HashEdDSA, RFC 8032 §5.1) returns `UnsupportedOperationException` instead of producing wire-incompatible signatures via pure Ed25519. Contributed by @KABBOUCHI. **EKS — default `topology.kubernetes.io/zone` and `topology.kubernetes.io/region` labels on k3s nodes** — matches the labels real EKS nodes carry via the AWS cloud-controller-manager; unblocks Karpenter / Cluster Autoscaler / scheduler `topologySpreadConstraints` without manual `kubectl label node`. Region resolves through `get_region()`; per-node-group label overrides belong on `CreateNodegroup.labels` — the AWS-shape-correct surface. Contributed by @b-rajesh. **ELBv2 — `SetSubnets`, `SetIpAddressType`, `SetSecurityGroups`** — three load-balancer mutation actions, output shapes verified against botocore (`SetSecurityGroups` returns `SecurityGroupIds`, not `SecurityGroups`). **Glue — `UserDefinedFunction` APIs** — full lifecycle (`CreateUserDefinedFunction` / `UpdateUserDefinedFunction` / `DeleteUserDefinedFunction` / `GetUserDefinedFunction` / `GetUserDefinedFunctions`) with the AWS-required `Pattern` glob on `GetUserDefinedFunctions`. **IAM — real EKS managed-policy seeds** — `AmazonEKSClusterPolicy`, `AmazonEKSWorkerNodePolicy`, `AmazonEKS_CNI_Policy`, `AmazonEKSServicePolicy` now carry the verbatim AWS documents instead of the wildcard `Allow *` fallback, so Terraform diffs and policy simulators behave the same as real AWS. **EC2 — `Attachment.AttachTime` on ENI describe** matches the AWS `NetworkInterfaceAttachment` shape; required by tools that audit attachment age (Cloud Custodian, Config rules). **Glue — `CreateDatabase` honors top-level `Tags`** (previously dropped) and `DeleteDatabase` cleans them up. **Glue — `UpdateTable` optimistic concurrency via `VersionId`** — stale `VersionId` returns `ConcurrentModificationException`; calls without `VersionId` keep the old back-compat behavior. **ECS — `DeleteService` marks the record `INACTIVE`** instead of removing it, matching the AWS contract that "Services in the `DRAINING` or `INACTIVE` status can still be viewed with the `DescribeServices` API operation". **Cognito — `CUSTOM_AUTH` trigger Lambdas no longer deadlock the event loop** — the IDP / Identity dispatchers are now `async` and run sync handlers via `asyncio.to_thread`, so the loop stays free to serve the Lambda's HTTP callback. Reported by @aahoughton. - [v1.3.57 — June 3, 2026](https://ministack.org/blog/changelog-v1-3-57): Karpenter and Cluster Autoscaler can finally run against MiniStack locally, EKS gains OIDC Identity Provider Config, and DynamoDB stops lying about export/import status at submit time. **EC2 Fleet — `CreateFleet` + `DescribeFleets`** with `instant`-type synchronous launch + multi-config × multi-override capacity distribution (Karpenter's 2 configs × 2 overrides × `TotalTargetCapacity=4` launches one of each combination); `DefaultTargetCapacityType`-driven spot/on-demand selection (the top-level `FleetType` enum is `{request, maintain, instant}` and doesn't include `"spot"`); shape parity restored — `Instances` + `Errors` emitted only when `Type=instant`, `maintain` / `request` return `FleetId` alone with `FulfilledCapacity=0` + `ActivityStatus=pending_fulfillment`; `DescribeFleets` on unknown id → `InvalidFleetId.NotFound`. Reported and contributed by @b-rajesh. **EKS — OIDC Identity Provider Config** — `AssociateIdentityProviderConfig` / `DescribeIdentityProviderConfig` / `DisassociateIdentityProviderConfig` at `/clusters/{name}/identity-provider-configs/{verb}`. AWS allows one OIDC IdP per cluster regardless of name (any second associate → `ResourceInUseException`); issuer + client ID + claims forwarded to k3s via `--kube-apiserver-arg=oidc-*`; IdP ARN stable across describes so Terraform / CDK / Pulumi don't see drift; tags reachable via `ListTagsForResource(resourceArn=idp_arn)`; cluster stays `ACTIVE` (the work is in the returned `update` record). Contributed by @b-rajesh. **DynamoDB — `ExportTableToPointInTime` + `ImportTable` return `IN_PROGRESS` at submit time** — both used to emit `COMPLETED` synchronously; `DescribeExport` / `DescribeImport` now stay `IN_PROGRESS` within the grace window (`MINISTACK_DDB_EXPORT_COMPLETE_AFTER_SEC` / `MINISTACK_DDB_IMPORT_COMPLETE_AFTER_SEC`, default 1s) and flip to `COMPLETED` + stamp `EndTime` after. Reported by @hicksy. Export contributed by @HarrisonTCodes. **DynamoDB PartiQL — `UPDATE` / `DELETE` with a false non-key predicate returns `ConditionalCheckFailedException`** — previously silently no-op'd because the handler iterated every row against the full WHERE clause; AWS treats non-key clauses as a conditional check on the PK-targeted item. Now splits WHERE into PK equalities + "the rest", requires `=` on every PK attribute (else `ValidationException`), and returns CCF when the targeted item is missing or any non-key predicate fails. Reported by @hicksy. **SQS — `/_ministack/sqs/messages` admin endpoint** — returns every queue's messages grouped by account with optional `?account` / `?QueueUrl` filters; pure introspection, no `visible_at` / `receive_count` mutation. Reported by @mbamber. **RDS — `MINISTACK_RDS_PUBLIC_ENDPOINT` env var** — set `1` when MiniStack runs in Docker but RDS clients connect from outside that network; `DescribeDBInstances` then returns `{MINISTACK_HOST, host_port}` (the externally-reachable host-published port). Off by default. **AppConfigData — `StartConfigurationSession` accepts identifier by ID or name** — `service-2.json` documents both shapes; ministack treated them as IDs only. Contributed by @LiamMacP. **`MINISTACK_HOST` honored consistently across services** — ECS / ElastiCache / OpenSearch / Lambda subprocess paths previously hardcoded `"localhost"`. Contributed by @neriyaco. - [v1.3.56 — June 2, 2026](https://ministack.org/blog/changelog-v1-3-56): Two new flows that unblock entire integration categories, a Lambda runtime gap closed for X-Ray, the missing half of the Firehose Kinesis-source fix from v1.3.53, and a deep DynamoDB error-message conformance pass. **Cognito User Pools — `CUSTOM_AUTH` flow with DefineAuthChallenge / CreateAuthChallenge / VerifyAuthChallengeResponse Lambda triggers** — `InitiateAuth` / `AdminInitiateAuth` / `RespondToAuthChallenge` / `AdminRespondToAuthChallenge` now run the full custom-auth state machine through the configured Lambdas; session TTL honors the client's `AuthSessionValidity`, capped at 3 answered rounds per AWS. Unblocks passwordless / magic-link / SMS-OTP flows. Reported by @aahoughton. Contributed by @AdigaAkhil. **EKS Access Entries — modern post-1.29 IAM bindings replacing the aws-auth ConfigMap** — 8 ops at `/clusters/{name}/access-entries[/{principalArn}[/access-policies[/{policyArn}]]]`: `CreateAccessEntry`, `DescribeAccessEntry`, `ListAccessEntries`, `UpdateAccessEntry`, `DeleteAccessEntry`, `AssociateAccessPolicy`, `DisassociateAccessPolicy`, `ListAssociatedAccessPolicies`. `accessScope` validated against `{cluster, namespace}` with `namespaces` required when namespace-bound; deleting an access entry cascades its associated policies. Unblocks Crossplane `accessentry.eks.aws.upbound.io` and Terraform `aws_eks_access_entry` + `aws_eks_access_policy_association`. Reported by @b-rajesh. **Lambda — `_X_AMZN_TRACE_ID` injected for `TracingConfig.Mode=Active`** — synthesized per invocation in the AWS-canonical format (`Root=1-<8hex>-<24hex>;Parent=<16hex>;Sampled=1`) and threaded into the warm Python / Node pool (bootstrap pops the per-event value into `os.environ` / `process.env`), provided runtimes, and the local subprocess executor. Docker RIE path is documented as upstream-unsupported (AWS RIE drops X-Ray) and logs a warning. Reported by @arivazhaganjeganathan-abc. **Firehose — Lambda processor invoked in the delivery pipeline** — `ProcessingConfiguration.Processors[].Type=Lambda` is now consulted at invocation time. Per-batch event `{invocationId, deliveryStreamArn, region, records:[{recordId, approximateArrivalTimestamp, data}]}`; response `{records:[{recordId, result, data}]}` with `result ∈ {Ok, Dropped, ProcessingFailed}`. Lambda failures pass records through unchanged (best-effort per AWS). Applies to both `PutRecord` / `PutRecordBatch` and `KinesisStreamAsSource` fan-out. Reported by @arivazhaganjeganathan-abc. **Cognito CUSTOM_AUTH — `issueTokens` on the cap-boundary attempt now wins over MaxAttempts**. **DynamoDB — AWS-canonical error-message parity across 24 operations** driven by `dynamodb-conformance.org`: set-duplicates include collection contents (`Input collection [a, a] contains duplicates.`), `UpdateExpression` syntax errors carry token-context, hash / range key mutation pre-rejected, redundant-parens + `begins_with` non-string operand pre-validated at parse time so empty tables still reject, `BatchExecuteStatement` per-statement `Error.Code` drops `Exception` suffix to match `BatchStatementErrorCodeEnum`, `TransactGetItems` missing-key surfaces via cancellation reasons, size-exceeded envelopes include the Java-toString dump. - [v1.3.55 — June 1, 2026](https://ministack.org/blog/changelog-v1-3-55): A new control-plane service, two EKS additions that unblock terraform IRSA modules, and four API Gateway Lambda-proxy correctness fixes — three contributed and all verified against real AWS. **AWS Elemental MediaConnect — control-plane stub** — 5 ops at `/v1/flows[/{FlowArn}]` and `/tags/{ResourceArn}`: `CreateFlow`, `DescribeFlow`, `ListFlows`, `UpdateFlow`, `ListTagsForResource`. `ListFlows` returns the slimmer `ListedFlow` projection; `UpdateFlow` is narrow to the AWS-allowed fields (`SourceFailoverConfig`, `Maintenance`, `SourceMonitoringConfig`, `NdiConfig`). No real streaming — flows are control-plane metadata, enough to integration-test services that wrap the MediaConnect API. Reported by @tashif-hoda. **EKS `AssociateEncryptionConfig` + OIDC discovery / JWKS for IRSA** — new `POST /clusters/{name}/encryption-config/associate` records KMS encryption config and rejects re-association (matches AWS, which only allows adding encryption to a cluster that has none). Each cluster's `identity.oidc.issuer` now points at a ministack-hosted URL (`/oidc/id/{32-char-id}`) instead of the unreachable real `oidc.eks.{region}.amazonaws.com`; `GET /.well-known/openid-configuration` and `GET /keys` are served with `authorization_endpoint: "urn:kubernetes:programmatic_authorization"` and `claims_supported: ["sub","iss"]` matching real EKS — enough for terraform's `aws_iam_openid_connect_provider` to fetch the document. Reported by @b-rajesh. **API Gateway v2 Lambda-proxy — `Set-Cookie` from `headers` and the `cookies` array now both ship** — observed real-AWS behavior is to emit the array entries first followed by any header `Set-Cookie`; the earlier supersede approach silently dropped the header cookie. **API Gateway v2 Lambda-proxy — `isBase64Encoded` honored in both directions** — only `text/*` and `application/json` / `application/xml` / `application/javascript` arrive as UTF-8 strings; everything else (incl. missing `Content-Type` and `application/x-www-form-urlencoded`) is base64-encoded with `isBase64Encoded: true`. Outbound base64 bodies are decoded to raw bytes — HTTP API has no `binaryMediaTypes` negotiation. Contributed by @rmlasseter. **API Gateway v1 Lambda-proxy — `binaryMediaTypes` is now wired** — request bodies matching a configured pattern arrive base64 with `isBase64Encoded: true`; response base64 bodies are decoded only when the request `Accept` also matches. Wildcards (`*/*`, `type/*`) honored on the configured side; a request `Accept` of `*/*` does NOT auto-match specific configured types — verified against real AWS. Contributed by @rmlasseter. **API Gateway v1 & v2 Lambda-proxy — case-insensitive header override** — a lowercase `content-type` from a Lambda response now replaces the seeded default rather than shipping two `Content-Type` headers (RFC 9110 §5.1). Contributed by @rmlasseter. - [v1.3.54 — May 30, 2026](https://ministack.org/blog/changelog-v1-3-54): One unblocking EKS feature, one cross-cutting API Gateway bug fix from a first-time contributor, and two AWS-shape corrections. **EKS addons** — 5 new ops at `/clusters/{name}/addons[/{addonName}[/update]]` (`CreateAddon`, `DescribeAddon`, `ListAddons`, `UpdateAddon`, `DeleteAddon`), unblocking `aws_eks_addon` for the standard cluster bootstrap (`vpc-cni`, `coredns`, `kube-proxy`, `aws-ebs-csi-driver`). Status flips to `ACTIVE` immediately on create / update, matching the nodegroup shortcut. Reported by @b-rajesh. **API Gateway Lambda-proxy `Set-Cookie` and `multiValueHeaders` now reach the client** — v2 maps the payload-format-2.0 `cookies` array to a list-valued `Set-Cookie` (RFC 6265 §3 forbids comma-folding); v1 folds format-1.0 `multiValueHeaders` into the response with `multiValueHeaders` winning over `headers` on key collision per the AWS contract; `_send_response` expands list-valued headers into one wire line per entry. The v1 collision check is case-insensitive (HTTP headers are case-insensitive per RFC 7230 §3.2), so `Set-Cookie` in `headers` plus `set-cookie` in `multiValueHeaders` correctly resolves to MVH wins instead of shipping both. Contributed by @rmlasseter. **DynamoDB data-plane table-name length range** — data-plane ops (`PutItem` / `GetItem` / `UpdateItem` / `DeleteItem` / `Query` / `Scan`) now accept the AWS-documented 1..255 range (the 3-char minimum is a `CreateTable`-only rule). NULL-attribute error message text aligned. **EC2 launch template version XML shape** — `CreateLaunchTemplateVersion` returns a single `` struct; `DescribeLaunchTemplateVersions` wraps in `…`. The `` wrapper now belongs at the list-context boundary, not on the inner struct. - [v1.3.53 — May 30, 2026](https://ministack.org/blog/changelog-v1-3-53): One real bug fix, a deep DynamoDB conformance pass, and AWS error-type clean-up across eight services. **Firehose `KinesisStreamAsSource` → S3 fan-out** — delivery streams of type `KinesisStreamAsSource` with an `ExtendedS3` / `S3` destination now actually consume records from the source Kinesis stream and forward them to S3 (previously the source config round-tripped on `DescribeDeliveryStream` but no consumer ever read the records). Fan-out fires inline from Kinesis `PutRecord` / `PutRecords` (same pattern as SNS→SQS), honors `Prefix` and `DeliveryStartTimestamp`, best-effort so a Firehose problem can never break the producer. Reported by @arivazhaganjeganathan-abc. **DynamoDB Tier 3 conformance pass** — 30+ message-text fixes so the strings returned by ministack match the strings captured from real AWS by the dynamodb-conformance.org Tier 3 suite: non-existent-table responses uniformly returning `"Requested resource not found"` across `Batch*` / `Transact*` / single-item ops; `BatchWriteItem` / `BatchGetItem` empty `RequestItems` using `"The requestItems parameter is required."`; per-expression-scoped undefined-reference errors (`"Invalid FilterExpression: An expression attribute value used in expression is not defined; attribute value: :v"`); empty `KeyConditionExpression` / `UpdateExpression` using the `"Invalid {Expression}: The expression cannot be empty;"` template; `Scan` `Segment` validation aligned to AWS phrasing; set / NULL / empty-BS / `KeySchema` / index-validation / billingMode / tableClass / deletion-protection / `Limit` / GSI-not-found messages all aligned; `ListTagsOfResource` on a non-existent ARN returns `AccessDeniedException` (AWS security-through-obscurity contract). Plus two functional bugs: GSI / LSI `INCLUDE` and `KEYS_ONLY` projections are now enforced on `Query` and `Scan`; parallel `Scan` partitions items deterministically across segments by hashing the partition key; LSI sparse semantics drop items lacking the range-key attribute. **AWS error-type fixes** across EFS (per-resource-type `FileSystemNotFound` / `AccessPointNotFound`), S3 Tables (`NotFoundException`), CloudFront KeyValueStore / Account (`ValidationException`), API Gateway v1 (`BadRequestException` instead of an invented 405), ECS / Batch (`ClientException`), MWAA (`ValidationException`), OpenSearch (`ValidationException`). KMS / MWAA / Inspector2 no longer leak Python exception text in `InternalServerException` / `InvalidCiphertextException` responses. **IMDS instance-profile-ID literal assembled at runtime** so credential-pattern secret scanners stop false-flagging `AIPA…` in `imds.py`. Reported by @diplomatic-ms. - [v1.3.52 — May 29, 2026](https://ministack.org/blog/changelog-v1-3-52): One major Lambda feature, an S3 tagging refinement, and a CloudFormation resource type — all three close open GitHub issues. **Lambda Durable Functions (Durable Execution)** — full support for the AWS preview API (`2025-12-01`): `CreateFunction` with `DurableConfig`, the seven management ops (`CheckpointDurableExecution`, `GetDurableExecutionState`, `GetDurableExecution`, `GetDurableExecutionHistory`, `ListDurableExecutionsByFunction`, `StopDurableExecution`), and the three external callback ops (`SendDurableExecutionCallbackSuccess`, `SendDurableExecutionCallbackFailure`, `SendDurableExecutionCallbackHeartbeat`). A resume scheduler fires `WAIT` expiries, callback timeouts (`Callback.Timeout` / `Callback.Heartbeat`), and step-retry backoffs (`NextAttemptDelaySeconds`); state persists across restarts — the in-memory callback index is rebuilt from restored executions on boot and pending timers are re-armed. End-to-end verified against the official `aws-durable-execution-sdk-python` 1.5.0 and `aws-durable-execution-sdk-java` 2.44.13. Reported by @youngkwangk. **S3 object tagging by `versionId`** — `GET` / `PUT` / `DELETE` `?tagging` honor the `versionId` query parameter, and `PutObject` / `POST` form upload store the `x-amz-tagging` header against the resulting version rather than the object key. Reported by @barrywilks7. **CloudFormation `AWS::AppConfig::Application`** — create and delete provisioners; physical id is the application id and `ApplicationId` is exposed via `Fn::GetAtt`. Reported by @zmartinec. Also: `MaxItems` on durable Lambda list / state / history is now bounded to AWS's `[0, 1000]` range (out-of-range → 400 `InvalidParameterValueException`); `CheckpointDurableExecution` rejects malformed `Updates`; `StopDurableExecution` on a terminal execution returns 400. - [v1.3.51 — May 27, 2026](https://ministack.org/blog/changelog-v1-3-51): A DynamoDB-heavy release driven by the [dynamodb-conformance.org](https://dynamodb-conformance.org) gap report. **DynamoDB backups & restore** — `CreateBackup`, `DescribeBackup`, `DeleteBackup`, `ListBackups`, `RestoreTableFromBackup`, `RestoreTableToPointInTime`; restore rebuilds with snapshot items, key schema, and indexes; `BillingModeOverride`, `GlobalSecondaryIndexOverride`, `LocalSecondaryIndexOverride` honored; state persists. **Export / Import** — `ExportTableToPointInTime`, `DescribeExport`, `ListExports`, `ImportTable`, `DescribeImport`, `ListImports`; both idempotent on `ClientToken`. **Contributor Insights** — `UpdateContributorInsights`, `DescribeContributorInsights`, `ListContributorInsights`; ENABLING→ENABLED / DISABLING→DISABLED settling matches real AWS; optional `IndexName` validated against the GSI list. **Resource-Based Policies** — `PutResourcePolicy`, `GetResourcePolicy`, `DeleteResourcePolicy` with full revision-id semantics, the `NO_POLICY` conditional path, 20 KB policy size cap. **PartiQL transactions and batches** — `BatchExecuteStatement`, `ExecuteTransaction`, `ClientRequestToken` idempotency, all-or-nothing rollback, `DuplicateItemException` on duplicate `INSERT`. **`DescribeLimits`** returns canonical account and table read/write capacity limits. **EC2 security-group lifecycle** — `CreateSecurityGroup` returns `SecurityGroupArn`, `DeleteSecurityGroup` returns `GroupId`, `RevokeSecurityGroupEgress` returns `RevokedSecurityGroupRules`; `DescribeSecurityGroups` distinguishes malformed IDs (`InvalidGroupId.Malformed`) from missing ones (`InvalidGroup.NotFound`). Contributed by @Areson. Plus ~20 DynamoDB validator and shape fixes covering item validation, batch and transaction caps, full `CreateTable` / `UpdateTable` validation, `Query` and `Scan` validation, `UpdateItem` pre-update snapshot semantics, nested `ProjectionExpression`, binary key ordering, reserved keyword rejection, and `ExpressionAttribute` bookkeeping. Glue `StartJobRun` no longer auto-pulls missing Docker images; MWAA worker containers auto-remove on exit. - [v1.3.50 — May 26, 2026](https://ministack.org/blog/changelog-v1-3-50): One new service, an analytics upgrade for Glue, two new IAM ops, plus AWS-shape fixes on Lambda and EC2. **S3 Tables (`s3tables`)** — new service emulator for the AWS S3 Tables API: table buckets, namespaces, and Iceberg-format tables. Control plane covers `CreateTableBucket`, `ListTableBuckets`, `GetTableBucket`, `DeleteTableBucket`, `CreateNamespace`, `ListNamespaces`, `GetNamespace`, `DeleteNamespace`, `CreateTable`, `ListTables`, `GetTable`, `DeleteTable`, `GetTableMetadataLocation`, `UpdateTableMetadataLocation`. Ships with an embedded **Iceberg REST catalog** at `/iceberg` so Spark jobs configured with `spark.sql.catalog.*.type=rest` and `spark.sql.catalog.*.uri=http:///iceberg` can create, load, and commit Iceberg tables without an external catalog server; data files in S3, metadata in memory. **Glue Spark jobs run on the official `amazon/aws-glue-libs` PySpark image** — `GlueVersion: 4.0` and `3.0` map to their canonical AWS Glue images (`glue_libs_4.0.0_image_01` / `glue_libs_3.0.0_image_01`); override via `GLUE_DOCKER_IMAGE`. Job containers run on MiniStack's Docker network so they reach S3, RDS, and other ministack services by container hostname. **IAM `UpdateAccessKey`** — toggles an access key between `Active` and `Inactive`, matching the two statuses real AWS accepts; optional `UserName` validated when provided. **IAM `GetAccessKeyLastUsed`** — returns the AWS "never used" shape (`Region` / `ServiceName` = `N/A`, no `LastUsedDate`) since MiniStack does not track per-key usage history. Both contributed by @lahmish. **Lambda invocation log includes user output alongside the traceback on error** — when a handler raised after printing, the response log dropped the user output and only returned the traceback; both are now returned, newline-separated, matching real Lambda CloudWatch Logs output. Contributed by @Baptiste-Garcin. **EC2 `CreateVpcEndpoint` and `CreateFlowLogs` now persist `TagSpecifications`** — tags passed at creation time were silently dropped. Tags are now stored, returned by `DescribeFlowLogs`, and cleaned up on `DeleteFlowLogs`. The `fl-` prefix is also registered in the resource-type guesser so flow-log IDs are correctly resolved by the Resource Groups Tagging API. Contributed by @lahmish. - [v1.3.49 — May 25, 2026](https://ministack.org/blog/changelog-v1-3-49): One new service, three contributor improvements, persistence and AWS-shape fixes. **Amazon Inspector2** — new service emulator covering 14 ops (`Enable`, `Disable`, `ListFindings` with filtering/sorting/pagination, `BatchGetFindingDetails`, `ListCoverage`, `ListCoverageStatistics`, `ListFindingAggregations`, `SearchVulnerabilities`, tag and filter CRUD); generates deterministic stub vulnerability findings for ECR container images, Lambda functions, and EC2 instances when enabled. Contributed by @ry-allan. **RDS auto-respawn at boot** with `PERSIST_STATE=1` — MiniStack now eager-imports the RDS module at startup and respawns the Docker container for every persisted instance immediately, no client API call required; zero idle cost when no `rds.json` exists. Reported by @doodaz. **Glue persists view fields** on `CreateTable` / `UpdateTable` — `ViewOriginalText` / `ViewExpandedText` (contributed by @yonatoasis) so Trino's iceberg connector stops failing with `viewOriginalText must be present`, plus `ViewDefinition` and `IsMultiDialectView` round-tripped for newer Spark 3.4+ / Glue 4.0 / Lake Formation multi-dialect view clients. **AppSync Events resources persist** across restarts (`PERSIST_STATE=1`) — Event APIs, channel namespaces, and API keys were silently dropped on restart because the events module was reached only via a cross-service call from the parent AppSync handler; the same fix covers related restart drops for `apigateway_v1` on first boot, Lambda-auto-created CloudWatch log groups, and EventBridge targets fired by S3 notifications. Reported by @yaegassy. **RDS respawn no longer fails with `port is already allocated`** — restored DB instances were trying to bind the engine's standard port (5432 for postgres, 3306 for mysql) on the host instead of the original docker host port; the host port is now tracked separately, probed for freeness before reuse, and falls back to a fresh free port if something else has taken it. Stale `Created`-status containers from prior failed boots are force-removed before respawn so they don't hold the binding. Reported by @doodaz. **CloudFront `DistributionSummary` parity** — `ListDistributions` round-trips the stored origin configuration (`Origins`, `DefaultCacheBehavior`; contributed by @CoffeeRaptor), plus the remaining required fields of the real AWS shape (`Aliases`, `CacheBehaviors`, `CustomErrorResponses`, `PriceClass`, `ViewerCertificate`, `Restrictions`, `WebACLId`, `HttpVersion`, `IsIPV6Enabled`, `Staging`) with minimal-but-valid defaults so strict-parsing SDKs (Go v2, Java v2) don't reject the response. - [v1.3.48 — May 24, 2026](https://ministack.org/blog/changelog-v1-3-48): Two ships. **S3 `GetObjectAcl` and `PutObjectAcl`** — both `?acl` subresource operations are now implemented. `GetObjectAcl` returns the stored policy or, if none has been set, the AWS default of a single `FULL_CONTROL` Grant to the request account-id owner. `PutObjectAcl` accepts either a canned ACL via the `x-amz-acl` header (`private`, `public-read`, `public-read-write`, `authenticated-read`, `aws-exec-read`, `bucket-owner-read`, `bucket-owner-full-control`) or a full `` XML body; invalid canned values return `InvalidArgument` and malformed bodies return `MalformedACLError`. As with retention, legal-hold, and bucket policies, the ACL is stored and round-tripped but not enforced on the data plane. `NoSuchKey` for missing keys. Reported by @smpial. **RDS persistence-restore module-import race** — the v1.3.47 restore-respawn daemon threads called `_get_docker()` which was defined further down in the same module, so a thread reaching the lookup before the parser finished raised `NameError: name '_get_docker' is not defined` and stranded the restored instance in `creating`. The `load_state("rds")` block now runs at the bottom of the module, after every helper the restore threads can touch. Reported by @doodaz. - [v1.3.47 — May 23, 2026](https://ministack.org/blog/changelog-v1-3-47): One new CloudFormation feature, three contributor bug fixes, two Cognito quality-of-life improvements for federated sign-in debugging. **CloudFormation nested stacks (`AWS::CloudFormation::Stack`)** — child template is fetched from `TemplateURL` (resolved against the local S3 emulator), `Parameters` pass through, child resources provision inline, and `Outputs` flow back to the parent via `Fn::GetAtt: [Nested, Outputs.]` — the same sub-attribute form CDK emits from the `NestedStack` construct. `Ref` resolves to the child `StackId` ARN matching real AWS; delete and update propagate to the child; the child stack gets its own `_stacks` entry with `RootId`/`ParentId` pointers so it shows up in events under its own ID. Reported by @jayalfredprufrock. **CloudFront `CreateInvalidation` caller-reference idempotency** — repeated calls with the same `CallerReference` on the same distribution now return the existing invalidation rather than creating duplicates; path comparison is set-based so re-submitting the same paths in a different order counts as the same batch (real AWS treats paths as a set). Different paths under the same `CallerReference` surface `InvalidationBatchAlreadyExists`. Contributed by @CoffeeRaptor. **S3 `DeleteObjects` removes keys from disk** — singular `DeleteObject` already purged the persisted file plus its `.meta.json` sidecar, but the batch path only cleared in-memory metadata, leaving orphaned files on disk after a `S3_PERSIST=1` cleanup. `DeleteObjects` now calls `_delete_persisted_object` per deleted key, mirroring `DeleteObject`. Contributed by @parafoxia. **RDS persisted-instance container restart on reload** — with `PERSIST_STATE=1`, restart used to leave persisted DB instances marked `available` with no backing container (zombie metadata that `StartDBInstance` couldn't recover). The restore path now spawns a daemon thread per persisted instance, removes any stale `ministack-rds-` container, runs a fresh container with the persisted volume + saved credentials, and transitions `creating → available/failed` based on container start. Each daemon thread inherits the original account's `_request_account_id` contextvar so multi-tenant restores land writes on the right account. **Cognito `/oauth2/idpresponse` and `/saml2/idpresponse` diagnostics** — distinct error messages for missing `code`, missing `state`, and unknown/expired relay (previously all opaque `InvalidParameterException`); server-side WARNING log when the relay key from the IdP doesn't match any pending authorize flow (5-minute TTL, single-use), naming the exact remediation. Configuration drift in Keycloak / Auth0 / Okta is now diagnosable from the response body alone. Reported by @ocr-lasagna. **Cognito `.well-known/*` no longer shadows S3** — `GET //.well-known/jwks.json` and `GET //.well-known/openid-configuration` fall through to the S3 handler when `poolId` isn't a registered user pool, so apps storing their own OIDC discovery doc as an S3 object aren't shadowed by a fake Cognito JWKS body. Real AWS only serves these for actual pools. - [v1.3.46 — May 21, 2026](https://ministack.org/blog/changelog-v1-3-46): One new S3 feature and one Cognito JWT correctness fix. **S3 `PutObject` conditional writes** — `If-None-Match: "*"` gives create-once semantics (write only if no object exists at the key), `If-Match: ""` gives optimistic concurrency (write only if the current etag matches). Both are now enforced on `PutObject`, matching the AWS feature shipped November 2024. Precondition violations return `412 PreconditionFailed`, with one documented exception per the AWS user guide: `If-Match: ""` against a missing key returns `404 NoSuchKey`. ETag comparison strips surrounding quotes on both sides so quoted and unquoted clients both work. The symmetric `x-amz-copy-source-if-match` headers on `CopyObject` were already supported; this closes the gap on plain `PutObject`. Contributed by @mattcookio. **Cognito JWT `iss` claim uses the pool's region, not the request region** — when a SigV4 scope carried a different region from the pool's creation region, the JWT `iss` was stamped with the request region, so `iss == https://cognito-idp..amazonaws.com/` mismatched the pool ID prefix and standards-compliant validators rejected the token. A new `_pool_region(pool_id)` resolver parses the region directly from the pool ID (`{region}_{suffix}`) and is applied to the JWT `iss`, the PreTokenGeneration trigger event region, the user-pool ARN, the OIDC discovery `issuer`, and the hosted-UI CloudFront URL returned by `CreateUserPoolDomain` / `DescribeUserPoolDomain`. Accepts 3-segment commercial regions and 4-segment GovCloud / ISO regions (`us-gov-east-1`, `us-iso-east-1`, etc.). Contributed by @subrotosanyal. - [v1.3.45 — May 20, 2026](https://ministack.org/blog/changelog-v1-3-45): Three reported bugs fixed. **CloudWatch Logs `GetLogEvents` / `FilterLogEvents` accept `logGroupIdentifier`** — both ops now resolve the target log group from either `logGroupName` or `logGroupIdentifier` (bare name or a full `arn:aws:logs:::log-group:[:*]` ARN) per the AWS API reference. Calls passing an ARN no longer fail with `ResourceNotFoundException: The specified log group does not exist: None`. The wildcard `:*` suffix on the ARN form is stripped before lookup. `StartQuery` and `StartLiveTail` use a different plural shape (`logGroupIdentifiers`) and stay out of scope. Reported by @msulima. **ElastiCache `DescribeCacheClusters` emits the full `CacheNode` shape** — per-node XML now includes `CacheNodeCreateTime` (ISO8601), `ParameterGroupStatus`, `CustomerAvailabilityZone` (derived from the cluster's `PreferredAvailabilityZone`), and `SourceCacheNodeId` (when non-empty), in addition to the previous `CacheNodeId` / `CacheNodeStatus` / `Endpoint`. `hashicorp/terraform-provider-aws` v6.45.0 reads `CacheNodeCreateTime` without a nil check after `aws_elasticache_cluster` apply, so the previous response caused `Unexpected nil pointer in: {CacheNodeCreateTime: ...}` and stranded Terraform on a deployed-but-unconfirmed cluster. `CustomerOutpostArn` stays unset — real AWS omits the element rather than emitting it empty. Reported by @trackme-ddisley. **API Gateway v1 `UpdateStage` boolean fields parsed from patch strings** — AWS's `UpdateStage` API doc is explicit that every `patchOperations[].value` is a string, even for boolean fields like `tracingEnabled` and `cacheClusterEnabled`; SDK v2 clients read the stage back and expect `*bool`, failing deserialization with `expected Boolean to be of type *bool, got string instead`. The v1 PATCH handler now coerces patch values to `bool` when the path is exactly `/tracingEnabled` or `/cacheClusterEnabled` — stage variables whose name happens to be `tracingEnabled` aren't affected because the match is exact, not substring. Method-settings patches (which already coerced their own booleans on per-method paths) are unchanged. Contributed by @duc12597. - [v1.3.44 — May 19, 2026](https://ministack.org/blog/changelog-v1-3-44): Three ships. **Step Functions JSONata standard library expansion** — the evaluator now ships ~30 built-in functions on top of the existing core: string (`$uppercase`, `$lowercase`, `$substring`, `$trim`, `$contains`, `$split`, `$join`, `$replace`, `$pad`), numeric (`$sum`, `$average`, `$max`, `$min`, `$abs`, `$floor`, `$ceil`, `$round`, `$power`, `$sqrt`, `$formatNumber`), array (`$sort` including the `function($l, $r){...}` comparator form, `$reverse`, `$distinct`, `$append`), object (`$keys`, `$values`, `$lookup` over both objects and arrays-of-objects, `$exists`), type (`$type`, `$boolean`), date/time (`$now()` / `$now(picture)` / `$now(picture, timezone)` with the XPath-3.1 picture-string subset, `$millis`), utility (`$uuid`, `$base64encode`, `$base64decode`). `$contains`/`$split`/`$replace` accept JSONata regex literals (`/pattern/flags`); `$replace` supports `$1`/`$&` substitution refs. `$exists` distinguishes a missing path from an explicit `null` per the JSONata spec — the motivating Choice condition `{% $exists($states.input.userId) %}` routes correctly whether the field is present, explicitly null, or missing. `$round` uses banker's rounding (round-half-to-even). Implemented natively in Python with no new runtime dependency. **RDS Data API readiness fix**: when a Docker-backed RDS instance is still bootstrapping, `ExecuteStatement` / `BatchExecuteStatement` previously fell back to the in-memory SQL stub on any connection error and returned a 200 acknowledging `CREATE USER` / `GRANT` statements that never reached MySQL. The fallback now only applies to control-plane-only clusters; container-backed clusters whose endpoint can't be reached surface `DatabaseUnavailableException` (HTTP 504, the canonical AWS error code). Real SQL errors (lock-wait timeout, etc.) still surface as `BadRequestException`. **Non-blocking `CreateDBInstance`**: returns immediately with `DBInstanceStatus="creating"` matching real AWS — readiness finalisation (authenticated-connection probe, MySQL master-user `GRANT`, transition to `available`, Aurora cluster endpoint sync) runs on a daemon thread with the request's contextvars snapshot. No wall-clock timeout — the daemon tracks backing-container liveness instead, so the instance stays `creating` while the container is up and flips to `failed` if it exits before becoming reachable. Image-side password mismatches log at WARNING level with a remediation hint. **Standard AWS ECS Docker labels on `RunTask` containers**: every container MiniStack spawns for an ECS task now carries the five canonical `com.amazonaws.ecs.*` labels real ECS sets (cluster ARN, container-name, task-arn, task-definition-family, task-definition-version), matching the AWS ECS container metadata file spec. Host-side log shippers, monitoring agents, and `docker ps --filter "label=…"` queries identify MiniStack-spawned containers the same way they would against real ECS. - [v1.3.43 — May 18, 2026](https://ministack.org/blog/changelog-v1-3-43): Three ships. **AWS IoT Core (Phase 1)** is a new service covering the control plane (Things / ThingTypes / ThingGroups, certificates issued by an in-process Local CA, IoT Policies with versioning + attach/detach, `DescribeEndpoint`) and a WebSocket-only MQTT 3.1.1 data plane multiplexed on the gateway port (HTTP `iot-data Publish` at `POST /topics/{topic}` with QoS 0/1 + retain; clients connect over `mqtt` Sec-WebSocket-Protocol). Persistent sessions (`cleanSession=0`), QoS 1 with in-flight tracking and DUP-flag retransmits, Last Will and Testament on ungraceful disconnect, duplicate-client-id force-disconnect, retained-message delivery on subscribe — all per the MQTT 3.1.1 spec. Multi-tenancy is enforced by account-prefixed topics at the bridge layer: the account ID is resolved from the SigV4 credential at the WebSocket upgrade and every PUBLISH/SUBSCRIBE topic is prefixed before it hits the in-process pub/sub registry, so two accounts publishing to the same topic name never see each other's traffic. Local CA root certificate exposed at `GET /_ministack/iot/ca.pem`; CA + issued certs + broker state (retained messages, persistent sessions) persist across restarts when `PERSIST_STATE=1`. Requires the `cryptography` package (declared in `[full]`); slim image users hit a clean `RuntimeError` on first IoT call. Deferred to later phases: Device Shadows, mTLS on 8883, retained-message queries, Rules Engine, Jobs, Fleet Provisioning. IoT policies are stored but not enforced on the data plane. Plain TCP 1883 is intentionally not exposed (real AWS IoT requires TLS or SigV4 on every connection). **Athena ↔ Glue catalog integration + S3 result persistence**: `StartQueryExecution` now resolves `database.table` references against Glue's `GetTable` to find the underlying S3 location, so queries against Glue-managed tables work without hand-written `read_csv('s3://...')` paths. Completed query results write to the configured `OutputLocation` as `.csv` plus a `.csv.metadata` companion (column names + Athena-mapped types), and the CSV file begins with the column-name header row (matching real Athena's output format). DuckDB execution is offloaded to a worker thread via `asyncio.to_thread`, so multiple concurrent Athena queries run on parallel threads while the event loop stays free. **EventBridge rule targets pointing at Step Functions state machines** — targets with `arn:aws:states:::stateMachine:` previously fell through to the "unsupported target type" warning and silently dropped events; the dispatcher now routes them through `stepfunctions._start_execution`, which runs on a daemon thread with a `contextvars.copy_context()` snapshot so the request's account context is preserved. The transformed payload (post `Input` / `InputPath` / `InputTransformer`) is passed verbatim as the execution input. - [v1.3.42 — May 16, 2026](https://ministack.org/blog/changelog-v1-3-42): Four ships. **MWAA** (Managed Workflows for Apache Airflow) emulates the REST control plane and spawns real `apache/airflow:` containers in standalone mode on the same Docker network as MiniStack — both Airflow 2.x and 3.x are supported. `CreateEnvironment` provisions the container, syncs DAGs from the configured `SourceBucketArn` + `DagS3Path` into `/opt/airflow/dags/` once it reaches AVAILABLE, and forces an aggressive scan interval so DAGs become visible within seconds. `CreateWebLoginToken` and `CreateCliToken` return the correct field names per the boto3 MWAA model (`WebToken` / `CliToken`). `InvokeRestApi` proxies straight through to Airflow's REST API — `/api/v2/` for v3 (open via Simple Auth Manager with `ALL_ADMINS=true`), `/api/v1/` for v2 (Basic auth using the standalone-generated admin password captured from the container after boot). Full lifecycle: `GetEnvironment`, `UpdateEnvironment`, `ListEnvironments`, `DeleteEnvironment` (stops + removes the container, releases the host port so long-running stacks don't leak ports). The boto3 host prefix (`api.airflow.`) is correctly bypassed by the S3 vhost extractor so requests reach the MWAA handler instead of being misread as bucket names. End-to-end verified with real DAGs visible via `InvokeRestApi GET /dags` on both `apache/airflow:2.10.4` and `apache/airflow:3.0.6`. **CloudWatch alarm actions** now publish to SNS on every `OK` ↔ `ALARM` ↔ `INSUFFICIENT_DATA` state transition. `AlarmActions` / `OKActions` / `InsufficientDataActions` lists are dispatched per the matching destination state, SNS topic ARNs receive the AWS-shaped JSON payload (`AlarmName`, `NewStateValue`, `NewStateReason`, `StateChangeTime`, `Region`, `OldStateValue`, `Trigger` sub-object with metric/threshold/comparison). Fires on both `SetAlarmState` (manual flip) and the auto-evaluation path triggered by `PutMetricData`; `ActionsEnabled=False` (or `DisableAlarmActions`) suppresses dispatch. Closes the largest single inter-service integration gap — alerting-driven test scenarios now work end-to-end against MiniStack. **Lambda → CloudWatch metrics**: every invocation now publishes the four canonical `AWS/Lambda` metrics dimensioned by `FunctionName` — `Invocations` (Count, 1 per call), `Errors` (Count, 1 on handled/unhandled failure), `Duration` (Milliseconds, wall-clock around the worker call), `Throttles` (Count, 1 when reserved-concurrency rejected the call). Recorded for both `RequestResponse` and `Event` invocation types and queryable via standard `GetMetricStatistics`. Combined with the alarm-action fix, end-to-end Lambda observability tests (invoke → error → alarm transitions to ALARM → SNS notification arrives) work in one local run. **CloudFormation `AWS::ApiGateway::Account`** is now a supported resource type — the singleton CFN resource that stores `CloudWatchRoleArn` for the API Gateway account. Previously failed with `Unsupported resource type`, which blocked any CDK stack using `new RestApi({ cloudWatchRole: true })` — a very common pattern. The handler writes the role ARN into the same store the runtime `UpdateAccount` / `GetAccount` API reads from, so the value round-trips end-to-end. - [v1.3.41 — May 16, 2026](https://ministack.org/blog/changelog-v1-3-41): KMS `Decrypt` error code parity. When the caller omitted `KeyId` and the `CiphertextBlob` was too short or otherwise unparseable, MiniStack returned `NotFoundException` ("Unable to find the key for decryption"); real AWS returns `InvalidCiphertextException` in that case because the request can't even reach key lookup. Wrapper libraries that catch encryption faults separately from key-lookup faults (retry on `NotFoundException`, surface `InvalidCiphertextException` immediately) now see the same code locally as in production. The `KeyId`-given branch is unchanged — explicit-key-not-found still returns `NotFoundException`, also matching AWS. Encrypt/Decrypt round-trips, asymmetric key paths (`RSAES_OAEP_SHA_256` etc.), and every other KMS operation are untouched. - [v1.3.40 — May 15, 2026](https://ministack.org/blog/changelog-v1-3-40): Cognito's invitation and verification mail now flows through MiniStack's in-process SES emulator: `AdminCreateUser`, `SignUp`, `ResendConfirmationCode` (previously missing — shipped alongside), `ForgotPassword`, and `AdminResetUserPassword` hand their welcome / temporary-password / verification messages to SES, so tests observe them at `/_ministack/ses/messages` and they relay via SMTP when `SMTP_HOST` is set. `MessageAction=SUPPRESS` skips, `RESEND` re-sends, `DesiredDeliveryMediums=["SMS"]` excludes email, `{username}` / `{####}` placeholders expand in `InviteMessageTemplate` and `VerificationMessageTemplate`, sender resolves to `EmailConfiguration.From` falling back to the AWS-canonical `no-reply@verificationemail.com` (overridable via `COGNITO_DEFAULT_FROM`); set `COGNITO_EMAIL_ENABLED=false` to short-circuit globally. Step Functions JSONata gains state-level `Assign` + an execution-scoped variable store; values bound on one state can be referenced as `$name` (with dotted-path access like `$user.email`) in any later JSONata expression. Pass `$states.result` resolves to the computed Output; Task `$states.result` to the raw API result; Catch handlers expose `$states.errorOutput`. Undefined refs surface as `States.QueryEvaluationError`, matching AWS's documented error code for JSONata evaluation failures. Cognito sign-in honors `AliasAttributes` and `UsernameAttributes`: users can sign in by `email` / `phone_number` / `preferred_username` and the lookup resolves correctly. Email and phone aliases require the corresponding `_verified` attribute to equal `"true"` (matches AWS); `preferred_username` has no verification gate. SQS `RedrivePolicy` is validated at `CreateQueue` / `SetQueueAttributes` — a parseable JSON object with a non-empty `deadLetterTargetArn` and a numeric `maxReceiveCount` between 1 and 1000. Malformed values return 400 `InvalidAttributeValue` instead of silently corrupting the queue and crashing `ReceiveMessage` with an `'str' object has no attribute 'get'` `InternalError`. DynamoDB `SET v = (if_not_exists(v, :d) - :amt)` now subtracts correctly — the outer parens used to pin every token at depth > 0, so the top-level operator scan never saw the `-` and silently dropped the arithmetic. S3 → Lambda notifications fire for non-boto3 SDK clients: the notification XML parser now accepts both `` (botocore's wire form) and `` (AWS SDK for Java v2, Go SDK, Terraform, hand-crafted XML). - [v1.3.39 — May 15, 2026](https://ministack.org/blog/changelog-v1-3-39): Step Functions JSONata is now wired across Task, Pass, and Choice states with a real operator surface. Task states with `QueryLanguage: "JSONata"` evaluate `Arguments` before dispatching `aws-sdk` integrations (previously bypassed local payload construction and called services with empty payloads) and evaluate success/Catch `Output` against `$states.input`, `$states.result`, `$states.errorOutput`. Pass states evaluate `Output` (was silently ignored, passing input through unchanged). Choice states evaluate per-branch `Condition` and per-branch `Output` (was always treating `{% ... %}` conditions as falsy, falling through to `Default`). The evaluator gained the operators real workflows actually use: comparison (`= != < <= > >=`), arithmetic (`+ - * / %`), string concat (`&`), boolean (`and or in`), unary minus, paren grouping, and `$count` / `$length` / `$not` / `$string` / `$number` functions. Left-associative parsing throughout. Step Functions executions no longer stall at `ExecutionStarted` under non-default 12-digit account IDs — `_executions` is an `AccountScopedDict` keyed by a `ContextVar`, and `threading.Thread` doesn't propagate contextvars, so the background worker was looking up the execution under the default account and silently returning. Fixed with `contextvars.copy_context().run` on each thread target, with per-thread snapshots at the Parallel and Map spawn sites (a single `Context` cannot be entered by two threads concurrently). Cognito OIDC federation completes: `/oauth2/idpresponse` exchanges the IdP's `code` against its `token_url`, decodes the `id_token` (no signature verification, same posture as SAML), applies `AttributeMapping`, provisions the `{provider}_{sub}` federated user, and 302s back to the app with a MiniStack-issued auth code (SAML federation continues to use `/saml2/idpresponse` unchanged). Node.js Lambda handlers can now `require('@aws-sdk/client-*')` the same way real AWS-managed runtimes do: `@aws-sdk/client-lambda` gets a dedicated REST stub; 28 `awsJson1.x` services (SSM, SFN, Logs, SecretsManager, EventBridge, Kinesis, ECS, DynamoDB, SQS, Glue, Athena, Firehose, Cognito IDP/Identity, EMR, ECR, ACM, WAFv2/WAF/WAF-Regional, Organizations, KMS, CodeBuild, Transfer, ServiceDiscovery, Resource Groups Tagging, CloudTrail) resolve via a generic `X-Amz-Target` Proxy stub; errors expose `err.name` for the v3 catch-by-name convention; HTTPS→HTTP localhost downgrade extended to CDK Provider Framework's `cfn-response.js` PUT. Real packages (e.g. via a Lambda Layer) still take precedence. - [v1.3.38 — May 13, 2026](https://ministack.org/blog/changelog-v1-3-38): Five new CloudFormation provisioners closing the long-standing gaps for HTTPS, ALB, RDS, and CDK Step Functions stacks. `AWS::CertificateManager::Certificate` provisions a Certificate matching `RequestCertificate` shape (Ref returns ARN; honours DomainName, SubjectAlternativeNames, ValidationMethod, Tags, KeyAlgorithm, CertificateTransparencyLoggingPreference). `AWS::ElasticLoadBalancingV2::TargetGroup` and `AWS::ElasticLoadBalancingV2::ListenerRule` complete the ALB CFN story (LoadBalancer and Listener already existed but had nothing to forward to); ListenerRule conditions accept both the flat `{Field, Values}` shape and the per-field nested form (`PathPatternConfig.Values`, `HostHeaderConfig.Values`, `HttpHeaderConfig`, `HttpRequestMethodConfig`, `QueryStringConfig`, `SourceIpConfig`); actions support `forward`/`redirect`/`fixed-response`. `AWS::RDS::DBInstance` provisions standalone DB instances and Aurora cluster members, metadata-only like the existing `AWS::RDS::DBCluster` handler; Aurora cluster members inherit master credentials from the cluster automatically; `Fn::GetAtt` returns `Endpoint.Address`, `Endpoint.Port`, `DbiResourceId`, `DBInstanceArn`. `AWS::StepFunctions::StateMachine` now accepts the inline `Definition` object and `DefinitionS3Location` (fetched from the in-memory S3 service), and applies `DefinitionSubstitutions` (`${KEY}` placeholders) — so CDK's `DefinitionBody.fromFile()` stops producing `InvalidDefinition: StartAt state 'None' not found`. ECS task IAM role credentials endpoint at `GET /v2/credentials/` returns the AWS-strict 5-field document (`AccessKeyId`, `SecretAccessKey`, `Token`, `Expiration`, `RoleArn`) — distinct from the IMDS shape served at `/latest/meta-data/iam/security-credentials/`. `RunTask` injects `AWS_CONTAINER_CREDENTIALS_FULL_URI`, `AWS_CONTAINER_AUTHORIZATION_TOKEN` (satisfies botocore's allow-list for non-loopback gateway hosts), and `AWS_ENDPOINT_URL` so unmodified AWS SDKs running inside an emulated ECS task use MiniStack end-to-end with no client config. ECS `connectivityAt` and `stoppingAt` now wire as JSON numbers (Go AWS SDK v2 strict timestamp parsing). CFN `AWS::ECS::TaskDefinition` populates `registeredAt`, `registeredBy`, and `compatibilities`. - [v1.3.37 — May 12, 2026](https://ministack.org/blog/changelog-v1-3-37): CloudFormation `AWS::ApiGateway::Authorizer` (TOKEN / REQUEST / COGNITO_USER_POOLS) now provisions against the existing apigateway_v1 store instead of failing with `Unsupported resource type`; maps `Name`, `Type`, `AuthorizerUri`, `AuthorizerCredentials`, `IdentitySource`, `IdentityValidationExpression`, `AuthorizerResultTtlInSeconds`, `ProviderARNs`, `RestApiId`. SQS `AddPermission` / `RemovePermission` wire through to the queue's `Policy` attribute in AWS canonical shape (bare 12-digit account IDs in `Principal.AWS`, lowercase `sqs:` action namespace, `/SQSDefaultPolicy` Id); duplicate `Label` rejected with `InvalidParameterValue`; RemovePermission idempotent. RDS `DescribePendingMaintenanceActions` accepts the call and returns an empty list (unblocks brownfield state-capture tooling). SQS `SendMessage` validates body byte length against the queue's `MaximumMessageSize` attribute and returns `InvalidParameterValue` (400) on oversize. SNS `Publish` and `PublishBatch` enforce the 256 KiB Message+MessageAttributes limit (262144 bytes); Publish returns `InvalidParameter` (400); PublishBatch surfaces each oversized entry as a per-entry failure. EventBridge SQS targets stamp `SqsParameters.MessageGroupId` on FIFO queues (was dropped at dispatch); a content-based `MessageDeduplicationId` and `fifo_seq` are also stamped. SQS `DeleteQueue` raises 400 `QueueDoesNotExist` (awsQueryCompatible `AWS.SimpleQueueService.NonExistentQueue`) for missing queues (was silently 200). S3 `UploadPartCopy` validates `x-amz-copy-source-range` and returns 400 `InvalidArgument` for malformed/reversed/out-of-bounds inputs (was 500/silent 200); out-of-bounds includes object size in the message. S3 `_parse_bucket_key` strips absolute-form request targets so AWS SDK for .NET v4's HTTP/1.1 `PUT http://ministack:4566/bucket/key` no longer hits `NoSuchBucket: http:`. - [v1.3.36 — May 11, 2026](https://ministack.org/blog/changelog-v1-3-36): IAM AWS-managed policies (`arn:aws:iam::aws:policy/`) now resolve from any session account, pre-seeded with 20 of the most commonly referenced canonical documents (AdministratorAccess, PowerUserAccess, ReadOnlyAccess, SecurityAudit, AWSLambdaBasicExecutionRole, AWSLambdaVPCAccessExecutionRole, AmazonS3FullAccess/ReadOnlyAccess, AmazonEC2FullAccess/ReadOnlyAccess, AmazonSSMManagedInstanceCore, AmazonDynamoDBFullAccess, AmazonSQSFullAccess, AmazonSNSFullAccess, AmazonECSTaskExecutionRolePolicy, CloudWatchAgentServerPolicy, CloudWatchLogsFullAccess, AWSCloudFormationFullAccess, IAMFullAccess, IAMReadOnlyAccess) carrying their canonical AWS documents verbatim. Unknown AWS-managed ARNs return `NoSuchEntity` by default so typos like `AdminstratorAccess` surface locally the way they do against real AWS; opt in to permissive autovivify with `MINISTACK_AUTOCREATE_AWS_MANAGED=1`. `AttachmentCount` is tracked per-(session-account, arn) via an account-scoped sidecar so `GetPolicy` reflects the calling account's own attachments, matching real AWS. `ListPolicies` respects `Scope=All`/`AWS`/`Local`; mutation operations on AWS-managed ARNs return `AccessDenied` / `InvalidInput`. Cost and Usage Reports service ships with the full 7-operation surface (`PutReportDefinition`, `DescribeReportDefinitions`, `ModifyReportDefinition`, `DeleteReportDefinition`, `TagResource`, `UntagResource`, `ListTagsForResource`); report definitions persist but report file generation is intentionally not emulated — targets IaC validation for stacks that include `aws_cur_report_definition`. Lambda `ruby4.0` runtime wired to AWS's official `public.ecr.aws/lambda/ruby:4.0` base image (tracks botocore 1.42.94). RDS `DescribeDBClusters` serialization corrected for `DatabaseName` (now elided when unset instead of emitted as `""`), `NetworkType` (now defaults to `IPV4` instead of being absent), and `EngineLifecycleSupport` (now defaults to `open-source-rds-extended-support` instead of being absent). RDS `DescribeDBClusterParameters` emits the `` element so botocore materializes `Parameters[].Source` correctly. Two warm-boot persistence gaps closed: CUR module never called `load_state("cur")` at import (state was written on shutdown but never read on restart); IAM `_aws_managed_attachment_counts` sidecar was missing from `get_state` / `restore_state`. - [v1.3.35 — May 11, 2026](https://ministack.org/blog/changelog-v1-3-35): EKS `CreateCluster` works again — the k3s server container is now launched with `privileged=True`. The previous granular `cap_add` list could not grant the `/sys/fs/cgroup` remount k3s server mode requires, so containers exited on boot with `failed to evacuate root cgroup: mkdir /sys/fs/cgroup/init: read-only file system`. The cap_add list is retained as defence-in-depth; the privileged trade-off is documented in the EKS README section. SNS FIFO topic → standard SQS queue subscriptions now succeed; the stale validation that returned `InvalidParameterException: Topic with FIFO requires a subscription to a FIFO SQS Queue` is removed, matching AWS behaviour since 2023-09-14 (consumers of a standard queue subscribed to a FIFO topic may receive messages out of order and more than once). RDS `CreateDBInstance` now honours caller-supplied `PreferredMaintenanceWindow` instead of hardcoding `sun:05:00-sun:06:00` — `ModifyDBInstance` and cluster-level windows already worked, so the divergence was per-instance on create only. - [v1.3.34 — May 11, 2026](https://ministack.org/blog/changelog-v1-3-34): ECR now serves the Docker Registry HTTP API V2 protocol on the same gateway as the AWS API, matching real ECR. `docker push` and `docker pull` work end-to-end: `/v2/` ping, `/v2/_catalog`, chunked and single-shot blob uploads (`POST` / `PATCH` / `PUT /v2//blobs/uploads/[]`), cross-repo blob mount, blob `HEAD`/`GET`/`DELETE`, manifest `PUT`/`GET`/`HEAD`/`DELETE` by tag or digest, and `/tags/list`. Layer and manifest bytes persist under `PERSIST_STATE=1`; in-flight uploads are intentionally ephemeral. The bundled routing fix matches only registry-shaped paths (`/blobs/`, `/manifests/`, `/tags/list`) so API Gateway v2, AppSync Events, and SES v2 are untouched. CloudFormation `Custom::*` and `AWS::CloudFormation::CustomResource` run the full Create / Update / Delete lifecycle through a local `/_ministack/cfn-response/{token}` intercept; the provisioner runs in `asyncio.to_thread` so the event loop stays free for the Lambda's `PUT` callback — required for CDK `cr.Provider`-backed Lambdas. Cognito OAuth2 `id_token` now echoes the client-supplied `nonce` per OIDC Core 1.0 §3.1.3.7; strict OIDC libraries (`oidc-client-ts`, `react-oidc-context`, Auth0 / Microsoft client SDKs) silently discard tokens missing an expected nonce. - [v1.3.33 — May 9, 2026](https://ministack.org/blog/changelog-v1-3-33): CloudFormation `AWS::DynamoDB::GlobalTable` covers the schema CDK `TableV2` emits. Honours `KeySchema`, `AttributeDefinitions`, `BillingMode`, `StreamSpecification`, `GlobalSecondaryIndexes`, `LocalSecondaryIndexes`, `SSESpecification`, `TimeToLiveSpecification`, `TableName`. For PROVISIONED billing, `WriteProvisionedThroughputSettings.WriteCapacityAutoScalingSettings.MinCapacity` and `ReadProvisionedThroughputSettings.ReadCapacityAutoScalingSettings.MinCapacity` are translated to the engine's static `ProvisionedThroughput.{Write,Read}CapacityUnits` (single-process emulator doesn't simulate auto-scaling, so the floor becomes the constant). `Replicas` (required by CFN) and the other multi-region / AWS-side auto-scaling properties (`MultiRegionConsistency`, `GlobalTableWitnesses`, `GlobalTableSourceArn`, `WarmThroughput`, `ReadOnDemandThroughputSettings`, `WriteOnDemandThroughputSettings`) are accepted and ignored. Stacks that mix `AWS::DynamoDB::Table` and `AWS::DynamoDB::GlobalTable` deploy unmodified. - [v1.3.32 — May 9, 2026](https://ministack.org/blog/changelog-v1-3-32): Cognito OIDC autodiscovery now returns reachable URLs at the MiniStack gateway instead of unreachable `cognito-idp..amazonaws.com` URLs; `response_types_supported` advertises both `code` and `token`. Cognito OAuth2 / OIDC endpoints (`/oauth2/authorize`, `/oauth2/token`, `/oauth2/userInfo`, `/logout`, `/.well-known/*`) now send wildcard `Access-Control-Allow-Origin: *` so Amplify, `oidc-client-ts`, and `react-oidc-context` work cross-origin from a browser. EC2 VPN Connection support (`CreateVpnConnection`, `DescribeVpnConnections`, `DeleteVpnConnection`, `CreateVpnConnectionRoute`, `DeleteVpnConnectionRoute`) plus `DescribeRouteTables` now emits `propagatingVgwSet` set by `EnableVgwRoutePropagation`. EC2 `RunInstances` honours `--private-ip-address` and `--iam-instance-profile` (both were silently dropped; default IPs were malformed due to a missing dot separator in the prefix). DynamoDB GSI Query pagination now orders by `(INDEX_SORT, BASE_PK, BASE_SK)` so `ExclusiveStartKey` doesn't drop or cycle items when GSI sort keys collide — common with single-table designs / ElectroDB collections. - [v1.3.31 — May 7, 2026](https://ministack.org/blog/changelog-v1-3-31): Lambda multi-account isolation — function workers spawned under non-default accounts now receive `AWS_ACCESS_KEY_ID` derived from the function ARN instead of the host process env var, so `STS GetCallerIdentity` and internal SDK calls inside the handler resolve to the correct account; warm-worker pool key is now `{account}:{function}:{qualifier}`. EC2 `RunInstances` and `DescribeInstances` emit a default root `BlockDeviceMappings` entry (auto-attached `/dev/xvda` EBS volume, gp3, 8 GiB, `DeleteOnTermination: true`) so Cloud Custodian, AWS Config, and any policy tool that classifies instances by BDM works against MiniStack. S3 `GetObject` by `VersionId` emits RFC 7231 HTTP-date `Last-Modified` (instead of internal ISO-8601), fixing AWS SDK for JavaScript v3's strict header parser. EC2 AWS-managed prefix lists (`DescribePrefixLists`, `DescribeManagedPrefixLists`, `GetManagedPrefixListEntries`) return deterministic CIDRs for `s3`, `dynamodb`, `s3express`, `vpc-lattice`, `route53-healthchecks`, `ec2-instance-connect`, `cloudfront`, `groundstation` (IPv4 in CGNAT `100.64.0.0/10`, IPv6 in `64:ff9b:1::/48`). - [v1.3.30 — May 6, 2026](https://ministack.org/blog/changelog-v1-3-30): Step Functions REST-JSON `aws-sdk` integrations (e.g. `aws-sdk:rdsdata:executeStatement`) now expose output keys with the same PascalCase convention used by the query and REST-XML dispatchers (`Records`, `NumberOfRecordsUpdated`, `GeneratedFields`, `StringValue`) instead of raw camelCase wire keys, so `ResultSelector` paths like `$.Records` resolve correctly. - [v1.3.29 — May 6, 2026](https://ministack.org/blog/changelog-v1-3-29): EC2 `DescribeVpcEndpointServices` returns the standard catalog of 2 Gateway services (`s3`, `dynamodb`) and 17 Interface PrivateLink services with region-templated DNS names and stable per-service IDs; `ServiceNames`, `service-name`, `service-type` filters supported. DynamoDB legacy `AttributeUpdates` (pre-expression `UpdateItem` parameter with `PUT` / `DELETE` / `ADD` actions; mutually exclusive with `UpdateExpression`; .NET SDK upserts now round-trip non-key fields). Step Functions `aws-sdk:ec2` security-group dispatch uses EC2-shaped numbered lists (`Filter.1.Value.1`) instead of `member.N`, maps `Description` → `GroupDescription`, and exposes `SecurityGroups` rather than raw `SecurityGroupInfo`. Step Functions `aws-sdk:s3` REST-XML dispatcher covers `ListBuckets`, `CreateBucket`, `DeleteBucket`, `HeadBucket`, `GetBucketVersioning`, `ListObjectsV2`, `ListObjects`, `HeadObject`, `CopyObject`, `DeleteObject`, `GetObjectTagging`, `PutObjectTagging`. SQS `ReceiveMessage` honours the modern `MessageSystemAttributeNames` field (AWS SDK v2 / Java / Kotlin). CFN `AWS::SNS::Subscription` honours `RawMessageDelivery`. - [v1.3.28 — May 5, 2026](https://ministack.org/blog/changelog-v1-3-28): ECS Task Metadata V4 — every container started by `RunTask` gets `ECS_CONTAINER_METADATA_URI_V4` injected; gateway serves `/v4/` (current container), `/v4//task` (sibling `Containers` array), and `/stats` + `/task/stats` stub. `RunTask` also translates `privileged`, `linuxParameters.capabilities.add`, `pidMode: host`, and `volumes` + `mountPoints` into Docker bind mounts. DynamoDB legacy `Expected` (PutItem / UpdateItem / DeleteItem) and `KeyConditions` (Query) now evaluated correctly with all 13 comparison operators (`EQ`, `NE`, `LE`, `LT`, `GE`, `GT`, `NOT_NULL`, `NULL`, `CONTAINS`, `NOT_CONTAINS`, `BEGINS_WITH`, `IN`, `BETWEEN`) and type-aware numeric compare. `TransactWriteItems` `CancellationReasons` now reports `ConditionalCheckFailed` for every failing item, not just the first. - [v1.3.27 — May 4, 2026](https://ministack.org/blog/changelog-v1-3-27): AWS CloudTrail (in-memory audit log + control plane; opt-in via `CLOUDTRAIL_RECORDING=1`; ring-buffered per account; all 8 `LookupAttributes`; `IsLogging` flips on `Start`/`StopLogging`; `ListTrails` and `UpdateTrail` handlers) and AWS Resource Groups (19 of 23 spec ops covering group CRUD, resource queries, configuration, membership, tagging, account settings; tag-sync ops omitted — not exposed by AWS CLI / Terraform). Plus AWS-spec audit fixes: API Gateway v1 `GetUsagePlanKey` per-key handler, HTTP_PROXY `{paramName}` substitution from `integration.request.path.X` mappings + query-string forwarding, `UpdateModel` (`PATCH /restapis/{id}/models/{name}`); Transfer Family `LOGICAL` root home-directory mappings (`Entry="/"`); STS `Credentials.Expiration` is int epoch in the JSON path; DynamoDB `ConditionalCheckFailedException` populates `Item` on `ReturnValuesOnConditionCheckFailure="ALL_OLD"` (PutItem / UpdateItem / DeleteItem / TransactWriteItems); CloudFormation `AWS::S3::Bucket` preserves physical resource id on stack update; CloudFormation `AWS::Lambda::Function` returns real `CodeSize` and `CodeSha256`. - [v1.3.26 — May 4, 2026](https://ministack.org/blog/changelog-v1-3-26): S3 Files (`s3files-2025-05-05`) routes and shapes verified against `botocore/data/s3files/2025-05-05/service-2.json` — `CreateFileSystem` is `PUT /file-systems` (not `POST`), camelCase request/response (`bucket`, `roleArn`, `fileSystemId`, `creationTime` int epoch), tagging at `/resource-tags/{resourceId}`, `PutSynchronizationConfiguration` optimistic concurrency via `latestVersionNumber`, AWS-standard error codes; resolves the reported `Unknown S3 Files route: PUT /file-systems` failure from the AWS CLI / Terraform. OpenSearch non-VPC domains stop emitting empty `VPCOptions` alongside `Endpoint` (Terraform AWS provider was misclassifying them as VPC-backed); VPC-shaped domains return `Endpoints["vpc"]` instead of `Endpoint`. CloudFormation `AWS::CloudFront::KeyValueStore` provisioning with in-place `Comment` updates via the new per-type CFN engine `update` handler; native `CreateKeyValueStore` accepts the optional `ImportSource` (`SourceType` + `SourceARN`). - [v1.3.25 — May 3, 2026](https://ministack.org/blog/changelog-v1-3-25): AWS AppSync Events API (HTTP publish + WebSocket subscribe/publish on the `aws-appsync-event-ws` subprotocol with full Lambda authorizer payload parity); CloudFront KeyValueStore management plane (under `cloudfront`) and the separate `cloudfront-keyvaluestore` data-plane SDK service (atomic `UpdateKeys`, opaque `NextToken`, `MaxResults` capped at 50, `DeleteKey` 404 on missing); EventBridge `cron()` full AWS parity with `L`, `LW`, `W`, `L`, `#` operators and DoM/DoW mutual-exclusion enforced at `PutRule`; 8 EventBridge AWS-spec divergences fixed (`CreatedBy`/`ManagedBy` on `DescribeRule`, `PutEvents` 10-entry cap, int-epoch `Time`, content-filter `exists:false` matches absent keys, `ListRules` pagination, opaque `NextToken` on `ListRuleNamesByTarget`, omitted empty `Policy`, `EventSource` state in `PENDING`/`ACTIVE`/`DELETED` enum). - [v1.3.24 — May 2, 2026](https://ministack.org/blog/changelog-v1-3-24): bug-fix release. `x-amzn-errortype` response header on every JSON-protocol error (Java SDK v2 / Go SDK v2 / Rust SDK now see the actual error code, not "unknown error type"). AppConfig 404 bodies include `__type` alongside `Code`/`Message`. Three previously-stateless services (`account`, `waf-classic`, `resourcegroupstaggingapi`) expose a no-op `reset()`. - [v1.3.23 — May 1, 2026](https://ministack.org/blog/changelog-v1-3-23): OpenSearch Service with full management plane plus optional real `opensearchproject/opensearch` cluster + Dashboards sidecar; EventBridge `rate()` rules now auto-fire on AWS-anchored `CreationTime` countdown; AWS Organizations, Account, Batch, WAF v1 stubs; EC2 `DescribeRegions`; Lambda `FileSystemConfigs` accepts S3 ARNs; APIGW v1 TLS-1.3 enum; idle RAM cut ~30% via `PYTHONOPTIMIZE=2` + `MALLOC_ARENA_MAX=2`. - [v1.3.22 — April 30, 2026](https://ministack.org/blog/changelog-v1-3-22): EC2 IMDS v1 + v2 (SDK credential chains resolve via `AWS_EC2_METADATA_SERVICE_ENDPOINT`); Cognito PreTokenGeneration Lambda invocation (V2_0 + V1_0 response handling); S3 PostObject for browser-based form uploads with `content-length-range` enforcement; full S3 `StorageClass` round-trip; per-script init-script env vars. - [v1.3.21 — April 29, 2026](https://ministack.org/blog/changelog-v1-3-21): real Redis cluster mode for ElastiCache (`redis-cli --cluster create`, real `CLUSTER SLOTS` / `MOVED`); 16-site ElastiCache `` → AWS-spec element-name fix that unbreaks aws-sdk-go-v2 and Java SDK v2; RDS error-code wire fixes; opaque base64url pagination on ten REST API list ops. - [Full release archive on GitHub](https://github.com/ministackorg/ministack/blob/master/CHANGELOG.md): every release with full attribution. - [Service timeline](https://ministack.org/blog/service-timeline): when each AWS service first shipped in MiniStack. ## Source - [GitHub repository](https://github.com/ministackorg/ministack): MIT-licensed source, issues, PRs, full CHANGELOG. - [r/ministack on Reddit](https://www.reddit.com/r/ministack/): community Q&A, release announcements. ## Optional - [Blog index](https://ministack.org/blog/): all guides, release posts, and feature deep-dives in one hub. - [LinkedIn](https://www.linkedin.com/company/ministackorg/): release announcements, ecosystem news. - [Sitemap](https://ministack.org/sitemap.xml): every public URL with `lastmod` timestamps.