October 29, 2026 · v1.5.34
v1.5.34 adds AWS IAM GRANT and AWS IAM REVOKE to Aurora DSQL and the glue:startJobRun optimized integration to Step Functions, accepts presigned S3 URLs like header-signed requests when AUTH=false, and fixes 19 behaviours across API Gateway, AppConfig, Athena, Auto Scaling, CloudFront, EventBridge Scheduler, Glue, HTTP/2, Kinesis, Lambda, RDS, Secrets Manager and Step Functions to match AWS.
AWS IAM GRANT and AWS IAM REVOKE. with DSQL_STRICT=1 both were a syntax error, so a migration that maps a Postgres role to an IAM role stopped there. Sent on their own over the simple query protocol (psql, psycopg2), a GRANT maps one or more ARNs to a role and a REVOKE unmaps them; the mappings read back through sys.iam_pg_role_mappings with DSQL's six columns and types, a rollback undoes a GRANT, and a GRANT after other DDL in the same transaction answers DSQL's 0A000. Re-granting raises DSQL's NOTICE and revoking a missing mapping its WARNING; an unknown role answers 42704, a value that is not an ARN 0P000, and granting the signed-in role to itself 42501. Contributed by @toby6578.glue:startJobRun optimized integration. arn:aws:states:::glue:startJobRun failed with "not yet implemented"; it now starts the job run and returns its JobName and JobRunId. With .sync the task waits for the run to end: a SUCCEEDED run returns the job run, with its timestamps in epoch milliseconds, and a FAILED, ERROR, TIMEOUT or STOPPED run fails the task with States.TaskFailed and the job run as the cause. Contributed by @mishukdutta-cz.AUTH=false a presigned URL is accepted like a header-signed request. SigV4 presigned URLs were verified whatever AUTH was set to, so a URL signed with a key MiniStack did not know, a wrong secret or a missing or wrong session token got 403 InvalidAccessKeyId, SignatureDoesNotMatch or 400 InvalidToken while the same client's header-signed calls succeeded. With AUTH=false the credential and signature are no longer checked; the key still selects the tenant and an expired URL still answers 403 AccessDenied. AUTH=true verifies presigned URLs as before. Contributed by @fabio-andre-rodrigues.domainNameStatus. CreateDomainName, GetDomainName and GetDomainNames had no domainNameStatus, so Terraform AWS provider 6.x waited for AVAILABLE until it timed out; they now answer AVAILABLE. A private custom domain name also has its domainNameId and the domainNameArn arn:aws:apigateway:<region>:<account>:/domainnames/<name>+<id>, which AWS::ApiGateway::DomainName DomainNameArn returns too. Reported by @cupidchan.CreateConfigurationProfile and UpdateConfigurationProfile dropped KmsKeyIdentifier, StartDeployment dropped KmsKeyIdentifier and Tags, and CreateHostedConfigurationVersion dropped its Description header, so Terraform re-planned the profile and replaced the hosted version and the deployment on every apply. The profile and the deployment now return KmsKeyIdentifier as given and the key's KmsKeyArn when MiniStack's KMS holds it, the version returns its Description on create, get and list, and the deployment's tags are readable with ListTagsForResource. Reported by @kharabasz.LocationUri is a secret (secretsmanager://<name or ARN> or its ARN) got an empty body from GetLatestConfiguration and its deployments reported ConfigurationLocationUri hosted. CreateConfigurationProfile now checks the RetrievalRoleArn, the type and the secret as AWS does, StartDeployment reads the secret version named by ConfigurationVersion and keeps its value, and GetLatestConfiguration serves it, typed application/json when it parses as JSON and application/octet-stream otherwise. A missing version or deleted secret answers "Secret <LocationUri> not found", and a secret under a customer managed key needs a KmsKeyIdentifier. Another account's secret must be named by its exact ARN, and under AUTH=true its resource policy must let the retrieval role call GetSecretValue. StartDeployment also reports AWS's member validation errors first and, for a deployment in progress, "Environment <id> currently has a state of DEPLOYING. The current deployment must finish before a new deployment can be started." Contributed by @kharabasz.EnforceWorkGroupConfiguration: true, StartQueryExecution now writes results to the workgroup's OutputLocation, even when the request gives its own ResultConfiguration.OutputLocation, as AWS does. Before, the request's location was used. Contributed by @mishukdutta-cz.OutputLocation. a query's <id>.csv and <id>.csv.metadata are now saved directly under the result location, at the path that GetQueryExecution reports, as AWS does. Before, they were saved one folder too deep, at <location>/<id>.csv/<id>.csv, so a client that read the reported path got NoSuchKey. Contributed by @mishukdutta-cz.LaunchTemplateName reported the name as its LaunchTemplateId, and UpdateAutoScalingGroup ignored LaunchTemplate. Both calls, and CloudFormation, now look the template up and report its id and name, with the Version as given (none when none was given), and refuse what AWS refuses with ValidationError: "The specified launch template, with template name <name>, does not exist.", "Malformed launch template Id: <id>" and "Could not find the specified version <n> for the launch template with ID <id>." Reported by @kharabasz.DescribeFunction and GetFunction without Stage answer the DEVELOPMENT stage instead of InvalidArgument, and a Stage other than DEVELOPMENT or LIVE answers MalformedXML "1 validation error detected: Value '<stage>' at 'stage' failed to satisfy constraint: Member must satisfy enum value set: [LIVE, DEVELOPMENT]". PublishFunction gives LIVE the DEVELOPMENT stage's ETag, both stages report UNASSOCIATED once published (DEPLOYED while a distribution uses the function) and an UpdateFunction no longer turns them back to UNPUBLISHED. ETags have AWS's form (E and 13 characters) and GetFunction answers application/octet-stream. Reported by @kharabasz.EventBridgeParameters. a schedule whose target is an event bus put its event on the bus as aws.scheduler / Scheduled Event, so a rule matching the target's own Source and DetailType never fired; the event now carries the EventBridgeParameters Source and DetailType, with Input as its detail. Reported by @kharabasz.GetSchedule, UpdateSchedule and DeleteSchedule for a missing schedule now answer Schedule <name> does not exist., and a duplicate CreateSchedule answers Schedule <name> already exists., as on AWS; the messages no longer name the group. Contributed by @kharabasz.--extra-py-files. a CSV (or other plain-file) write to that bucket stayed an open multipart upload, so the job succeeded but the output folder had only a 0-byte part-* marker under __magic_job-…/. spark-submit downloads s3:// --extra-py-files before Spark starts, and the S3A filesystem it makes for that bucket saved the magicv2 committer's upload list in S3, where the commit did not look. Every S3A filesystem now tracks these uploads in memory, so the commit completes them. Glue 4 jobs use DirectFileOutputCommitter and do not change. Contributed by @mishukdutta-cz.keep_alive_max_requests (1000) sent GOAWAY on an HTTP/2 connection's 1001st request and dropped its response, so a client that keeps one connection (Node's undici, gRPC) lost one request in every thousand (undici: other side closed). AWS closes client connections by keepalive duration, not request count; the limit is now 10,000,000, more than one connection sends in AWS's default hour. Contributed by @skialpine.PutResourcePolicy accepted most invalid documents. It now runs Kinesis's checks in AWS's order with its messages (size, JSON, Version, Statement, required and prohibited fields, Sid, actions per stream or consumer, wildcard and non-AWS principals, one Resource equal to the ARN) and, under AUTH=true, refuses principals that do not exist. GetResourcePolicy returns the document compact, as AWS stores it. Another account's ARN answers AccessDeniedException when MiniStack knows the account (it holds an IAM identity or a stream) and UnrecognizedClientException when it does not, and Kinesis authorization denials name the stream. Contributed by @Jolley71717.FunctionName. 123456789012:function:my-function[:qualifier] resolved to the account ID as the function name, so Invoke and the other function operations failed with Function not found: ...:function:123456789012; it now resolves as the full ARN in the caller's region, as on AWS, and gives the same result as that full ARN. Contributed by @mishukdutta-cz.BatchSize 100, MaximumRetryAttempts and MaximumRecordAgeInSeconds -1, BisectBatchOnFunctionError false, ParallelizationFactor 1, TumblingWindowInSeconds 0, DestinationConfig {"OnFailure": {}}), StateTransitionReason User action, and LastProcessingResult OK or PROBLEM: Function call failed instead of OK - N records and FAILED. An SQS mapping has no LastProcessingResult, as on AWS. Create, update and delete answer the transitional state (Creating, Updating, Enabling, Disabling, Deleting), UpdateEventSourceMapping answers 202, a second mapping for the same source and function is refused with ResourceConflictException, and an unknown mapping's message is AWS's. A mapping created by CloudFormation reports the same. MiniStack's states settle at once, where AWS's SQS mappings stay Creating for a few seconds. Contributed by @Jolley71717.-XXXXXX suffix) matched any secret whose ARN started with it, so with my-secret and my-secret-admin both stored, the partial ARN of my-secret returned my-secret-admin when that one was created first, and a partial ARN that names no secret, such as my-secret-adm, returned my-secret-admin instead of ResourceNotFoundException. It now matches only the secret whose ARN is the partial ARN plus the suffix, as on AWS. Contributed by @zach-tyl.aws-sdk:scheduler tasks. a Task with arn:aws:states:::aws-sdk:scheduler:<action> failed with States.Runtime ("Service 'scheduler' is not supported in MiniStack aws-sdk integrations"). createSchedule, getSchedule, updateSchedule, deleteSchedule, listSchedules, createScheduleGroup, getScheduleGroup, deleteScheduleGroup and listScheduleGroups now call EventBridge Scheduler in the execution's account and region, as on AWS. The output keeps Scheduler's member names, timestamps are ISO-8601 UTC strings, StartDate/EndDate are read from ISO-8601 strings with Z or a +hh:mm offset (cut to milliseconds), listSchedules filters by GroupName, NamePrefix and State, and a JSON object or array given as Target.Input is sent as compact JSON text. A failed call reports Scheduler.<ErrorCode> with the cause suffix (Service: Scheduler, Status Code: <status>, Request ID: <id>) (SDK Attempt Count: 1). Contributed by @kharabasz.Assign, and $name was not resolved in Parameters or intrinsic-function arguments, so a workflow that saved a result in a variable lost it. Assign now works in JSONPath states as AWS documents: $ is the result in Task, Map and Parallel states, the effective input in Choice and Wait, and the result in Pass; all assignments read the values from state entry (JSONata Assign too); and a Parallel branch's variables stay in the branch. Contributed by @jayjanssen.<Type>StateEntered or <Type>StateExited events, so GetExecutionHistory did not show them. They are now in the execution history, as on AWS; for a Distributed Map they are in each child execution's history and not in the parent's. Events added at the same time from several Map items or branches can no longer get the same id. Contributed by @mishukdutta-cz.docker pull ministackorg/ministack:1.5.34 docker run -d -p 4566:4566 ministackorg/ministack:1.5.34
Or pin in compose.yaml:
services:
ministack:
image: ministackorg/ministack:1.5.34
ports:
- "4566:4566"
Issues and PRs welcome on GitHub. Discussion on r/ministack.