github ministackorg/ministack v1.5.14

3 hours ago

What's Changed

New Contributors

[1.5.14] — 2026-09-20

Added

  • KMS — imported key material — a key created with Origin=EXTERNAL stayed unusable because there was no way to supply its material. GetParametersForImport, ImportKeyMaterial and DeleteImportedKeyMaterial now complete the flow: the key waits in PendingImport, all five wrapping algorithms unwrap, and ExpirationModel and ValidTo are reported on the key. Reported by @guymahieu.
  • API Gateway — REST request validators, API keys, throttling and quotas are enforced — the five RequestValidator operations are implemented, a method's requestValidatorId is applied to the body and parameters, and an API key is checked against its usage plan's rate, burst and quota. Reported by @iot-rocket.
  • CloudFormation — update handlers for twelve more types — a stack update of these types re-ran the create, so the resource came back under a new id or the change was lost. Each now updates in place where its reference allows, replaces otherwise, and refuses to replace a custom-named resource. Contributed by @iot-rocket.
  • RDS — resource-bound IAM database authentication — a verified token is now authorized against the policy's resource, so a grant scoped to one database user stops matching another. Contributed by @Areson.
  • RDS — PostgreSQL instances serve TLS — a generated CA signs a server certificate for each container, so a client connecting with sslmode=verify-full completes the handshake instead of failing. GET /_ministack/rds/ca.pem returns that CA, the local stand-in for AWS's certificate bundle. Reported by @jayjanssen.
  • Bedrock Agent Runtime — Retrieve applies vectorSearchConfiguration.filter — the filter was parsed and ignored, so every query returned the whole knowledge base. All eleven comparators plus andAll and orAll now select against the document's metadata, read from its .metadata.json sidecar. Reported by @Vidminas.
  • Bedrock Runtime — toolConfig reaches the backing model — a Converse call carrying tools was proxied without them, so the model could never answer with a tool use. Tools are forwarded, and a tool call comes back as a toolUse block, streamed as contentBlockStart when the caller streams. Reported by @Vidminas.
  • IoT — a job execution times outtimeoutConfig.inProgressTimeoutInMinutes and the device's own stepTimeoutInMinutes were stored and ignored, so an execution stayed IN_PROGRESS for ever. An execution past its timeout is now TIMED_OUT, and the device plane reports approximateSecondsBeforeTimedOut while it runs.
  • Health — the IoT mTLS listener is reported/_ministack/health carries iot_mtls, and /_ministack/ready waits for that listener, so a consumer polling readiness no longer races the MQTT port.

Changed

  • IAM — wildcard matching is case-sensitive where AWS makes it case-sensitiveResource, NotResource, StringLike, StringNotLike, ArnEquals and ArnLike compared case-insensitively, so a policy naming arn:aws:s3:::MyBucket also matched mybucket. Only Action stays case-insensitive, as on AWS.
  • SQS — the default MaximumMessageSize is 1 MiB — queues were created with AWS's old 256 KiB default, so a message between 256 KiB and 1 MiB was rejected where AWS accepts it. The bound accepted by SetQueueAttributes moves with it.

Removed

  • Four timing environment variablesTRANSCRIBE_JOB_RUN_SECONDS, GLUE_CRAWLER_RUN_SECONDS, MINISTACK_DDB_IMPORT_COMPLETE_AFTER_SEC and LAMBDA_STATE_TRANSITION_SECONDS paced emulator-only state transitions and had no AWS counterpart. The transitions keep their previous default pacing.

Fixed

  • EventBridge — dynamic HTTP parameters for API destinationsHttpParameters JSON paths went to the endpoint as literal $. strings. They now resolve against the original event, before input transformation, array indexes and wildcards included. Contributed by @dmgarland.
  • RDS — restarting a cluster keeps its DNS endpoint — a restart reported the container's IP in place of the *.rds.amazonaws.com name handed out at creation, breaking connection strings and hostname-verified TLS. The restart now reports the registered network alias, and the reader endpoint derives its cluster-ro- name only when that name was registered. Contributed by @jayjanssen.
  • RDS Data — a PostgreSQL SELECT reports the rows it returnednumberOfRecordsUpdated carried the row count for a read, where AWS reports 0 and leaves the rows in records. Contributed by @jayjanssen.
  • IoT — the registered-certificate event comes from the device connectRegisterCertificate published it, and an mTLS connect with an unknown certificate got CONNACK 5 with nothing created. AWS creates the certificate PENDING_ACTIVATION on the connect, publishes the event with sourceIp, and closes without a CONNACK. Contributed by @iot-rocket.
  • IoT — DescribeEndpoint refuses the retired iot:Data and iot:Jobs types — both returned a hostname, so a client could keep using an endpoint type AWS no longer serves. AWS answers InvalidRequestException 400 and points to iot:Data-ATS; both types now get the same errors and messages. Contributed by @iot-rocket.
  • IoT Data — HTTPS Publish refuses the topics AWS refuses — any $ topic was accepted, so a caller could forge $aws/events/... lifecycle events. Reserved topics now answer InvalidRequestException 400 "Topic can't start with $", and the MQTT-only jobs, Device Defender and commands topics "Invalid publish to restricted topic using HTTP". Contributed by @iot-rocket.
  • CloudFormation — AWS::ECR::Repository keeps what the template declares — scanning and encryption read back empty, lifecycle and repository policies and tags were dropped, PutImage failed, and a delete left images behind. The resource now goes through the ECR store. Contributed by @iot-rocket.
  • CloudFormation — a rolled-back replacement keeps the old resource — the predecessor was deleted as soon as the replacement existed, so a later failure rolled back to a resource that was gone. It is now deleted after the update succeeds, and a rollback deletes only the replacement. Contributed by @iot-rocket.
  • API Gateway — REST API gateway responses reach the data plane — a customized response was stored and never applied, so a 401 or 403 carried none of the CORS headers a CDK stack declares. Gateway errors now resolve their type, then DEFAULT_4XX/DEFAULT_5XX, then the built-in default, with header mappings and x-amzn-ErrorType. Contributed by @iot-rocket.
  • API Gateway — REST API gateway errors answer with the AWS status and message — invented statuses and exception text went out. A failed authorizer is 500 AUTHORIZER_FAILURE with a null message, a missing backend 500 API_CONFIGURATION_ERROR Internal server error, and an unknown stage 403 Forbidden. Contributed by @iot-rocket.
  • API Gateway — a MOCK integration honours its statusCode — the 200 integration response was used whatever the request template set, so a MOCK method modelling an error returned 200. The template's statusCode now selects the integration response by selectionPattern. Contributed by @iot-rocket.
  • AppConfig — GetLatestConfiguration serves a feature-flag profile in retrieval-time format — the stored {flags, values, version} document was returned verbatim, so a client reading a flag found nothing at the top level. A AWS.AppConfig.FeatureFlags profile is now flattened to its values, disabled flags included. Reported by @dk-tanio.
  • Bedrock AgentCore — timestamps are ISO 8601 strings everywhereCreateAgentRuntime answered with a JSON number while ListAgentRuntimes answered with a string for the same field, so a typed SDK failed on one of the two. Both now match the model's iso8601 format. Reported by @ykalemi.
  • S3 — an omitted notification configuration Id is generated — a configuration sent without one read back without one, where AWS assigns base64 of a UUID. Reported by @jin-gizmo.
  • S3 — a notification configuration is stored in the form the wire uses — the request XML was echoed back, so a configuration sent with LambdaFunctionConfigurations read back empty for a client expecting the wire name CloudFunctionConfiguration, which also hid a CloudFormation-declared Lambda notification. Reported by @jin-gizmo.
  • CloudFormation — AWS::WAFv2::WebACL returns the Ref AWS returns — the bare id came back where AWS returns name|id|scope, so a template passing the Ref to another resource passed an unusable value.
  • Cognito — the OIDC discovery document follows the gateway's scheme — every endpoint in it was http even with USE_SSL=1, so the document contradicted its own https issuer and a discovery client refused it. Reported by @epcap90.
  • IoT — rule SQL accepts the grammar AWS accepts!= and == were evaluated, where AWS refuses both, and a nested SELECT in a WHERE clause was accepted, where AWS answers Unexpected token, 'SELECT'. clientid() now resolves to n/a for a publish that did not arrive over MQTT rather than dropping the field from the projection.
  • IoT — the rule error action document matches AWS — a failure was reported as {action, errorMessage}, where AWS names failedAction (DynamoDBv2Action, SnsAction) and failedResource (the table, topic, queue or function the action targeted). clientId is N/A for a non-MQTT publish rather than empty, and the document carries sourceIp.
  • IoT — CreateJob validates what AWS validates — a schedulingConfig time with seconds or a Z, an inProgressTimeoutInMinutes outside 1 to 10080, a document over 32768 characters, a documentSource outside 1 to 1350, and a request naming neither a document nor a source were all accepted. Each now answers InvalidRequestException with AWS's own sentence.
  • IoT — DescribeJob echoes the members it acceptedabortConfig, timeoutConfig, schedulingConfig, jobExecutionsRetryConfig, namespaceId, jobTemplateArn, documentParameters and destinationPackageVersions were stored and never reported, and isConcurrent and forceCanceled were missing. Job timestamps are whole epoch seconds, not fractions.
  • IoT Jobs data — two device-plane answers match AWSUpdateJobExecution with a status a device cannot set answered InvalidRequestException 400 instead of InvalidStateTransitionException 409, and an executionNumber naming an execution that does not exist was ignored instead of answering ResourceNotFoundException 404.
  • Auto Scaling — a duplicate group or launch configuration returns AlreadyExists — the wire code was AlreadyExistsFault, the shape name rather than the code, so an SDK caught nothing.
  • CloudFormation — ExecuteChangeSet returns InvalidChangeSetStatus — the shape name InvalidChangeSetStatusException went out as the error code.
  • CloudFormation — the Rules section refuses Fn::If — it was evaluated because the reference lists it, while a real account answers Following functions are not supported in the Rules block of the template: [Fn::If].
  • CloudFormation — the 60 dynamic references per template quota is enforced — a template over the limit was provisioned instead of being refused.
  • Lambda — an AWS-published extension layer resolves — a template referencing LambdaInsightsExtension, the Parameters and Secrets, AppConfig or OpenTelemetry extensions or AWSSDKPandas could not deploy, because the publisher account is unknown offline. It now resolves by layer name with CodeSize 0, so the extension does not run.
  • EC2 — a bare -e NAME docker flag takes the host value — it was passed through as an empty string, where docker either forwards the host's value or omits the variable.
  • S3 Control — an unknown /v20180820 path answers InvalidURI — it fell through to a generic answer instead of AWS's 400 inside an <ErrorResponse> echoing the bad segment.
  • Signer — the clientRequestToken replay cache is bounded — every distinct token was kept for ever and persisted with the service state.
  • CloudFormation — DeletionPolicy: Snapshot takes a snapshot — the policy was read and never acted on, so a resource declaring it was deleted with nothing kept, and an RDS cluster or standalone instance, which AWS defaults to Snapshot, defaulted to Delete here. Both now snapshot the resource and then delete it, on a stack delete and on an update that removes it from the template.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.