What's Changed
New Contributors
- @igorgawrys1 made their first contribution in #1273
- @Kiran01bm made their first contribution in #1297
- @sac-outsystems made their first contribution in #1312
[1.4.14] — 2026-08-07
Added
- CodeBuild - builds can really run (
MINISTACK_CODEBUILD_EXECUTE=1) -StartBuildreturned a build that was alreadySUCCEEDED, so a pipeline rehearsed against MiniStack reported a pass without a single phase having run, and a buildspec that fails on AWS still looked green locally. With the flag set,StartBuildreturnsIN_PROGRESSand the project's inline buildspec is handed to the official AWS CodeBuild local agent (public.ecr.aws/codebuild/local-builds), which runs the phases in the project'senvironment.imagethe way CodeBuild does - the phase semantics come from AWS's own agent instead of a reimplemented executor.BatchGetBuildsreflects progress while the build runs: the agent'sPhase complete: <PHASE> State: <STATUS>lines becomephasesentries, and the container's exit status maps toSUCCEEDED/FAILED, withFAULTwhen Docker is unreachable.environment.environmentVariables,privilegedMode, and theCODEBUILD_BUILD_ID/_ARN/_NUMBER/_INITIATORvariables reach the build. The build reaches back into MiniStack:AWS_ENDPOINT_URL(plus placeholder credentials) is injected unless the project declares its own, soaws s3 cpinside a build hits this emulator rather than real AWS.timeoutInMinutesis enforced (the build is stopped and its phase reportedTIMED_OUT), and a restored build that was in flight when MiniStack stopped is reportedFAULTrather than polling as running forever.StopBuildis honoured deterministically: it records the intent before removing the container, so the worker reports the requestedSTOPPEDinstead of racing it toFAULT. Build output also reaches CloudWatch Logs: the record already advertisedlogs.groupName/logs.streamName, and an executed build now writes the agent output there, soaws logs get-log-eventsandaws logs tailread back a real build log instead of an empty stream. Default behaviour is unchanged - without the flag builds stay metadata-only. Requires the Docker socket; the agent image and workspace path are fixed internals, not configurable. Contributed by @igorgawrys1. - EventBridge Pipes — the SDK data plane is now reachable — Pipes was fully built (pipe store, background poller, region scoping, persistence, CloudFormation provisioner) but had no REST route, so
aws pipes list-pipesfell through to S3 virtual-host addressing and returnedNoSuchBucket.ListPipes,CreatePipe,DescribePipe,UpdatePipe,DeletePipe,StartPipe,StopPipe, and the tag operations are now served over boto3 / Terraform / CDK atpipes.<region>and/v1/pipes, reusing the existing store. - AWS Config — control plane for config rules, configuration recorders, and delivery channels:
PutConfigRule/DescribeConfigRules/DeleteConfigRule, recorder and delivery-channel CRUD plus their status reads,StartConfigurationRecorder/StopConfigurationRecorder, and the compliance and evaluation-status reads. - Cloud Control API (
cloudcontrol) — the generic resource control plane behind Terraform'sawsccprovider and CDK L1 constructs:CreateResource/GetResource/UpdateResource/DeleteResource/ListResourcesplus the resource-request status and cancel operations, with the AWSProgressEventandResourceDescriptionshapes (Propertiesas a JSON string). - Cognito — choice-based sign-in in the Hosted UI (
ALLOW_USER_AUTH) — the Hosted UI served a single password form regardless of the user pool's sign-in policy. A client whoseExplicitAuthFlowsincludesALLOW_USER_AUTHnow drives a multi-step choice-based flow driven byPolicies.SignInPolicy.AllowedFirstAuthFactors: username, then a challenge-selection screen (skipped when only one factor is allowed), thenPASSWORDorEMAIL_OTPentry, ending in the standard authorization-code redirect.EMAIL_OTPcodes are fixed at123456(consistent with the existing confirmation/reset codes) but verified against the session;WEB_AUTHNandSMS_OTPare out of scope. Clients withoutALLOW_USER_AUTHkeep the single-page form unchanged. Contributed by @kjdev. - KMS —
UpdateKeyDescription— the action was not registered, so every call returnedInvalidAction: Unknown action(HTTP 400) and terraform-provider-aws failed the whole update whenever anaws_kms_keydescription drifted. It now resolves the key by id or ARN, updates the description (an explicit empty string clears it, as on AWS), returns an empty body on success, andNotFoundExceptionfor an unknown key. Contributed by @sac-outsystems.
Fixed
- SNS —
$oroperator in subscription filter policies — a filter policy with a top-level$orkey was matched with plain AND semantics, so$ornever matched and every message was silently dropped as non-matching.$oris now evaluated the way AWS does: a recognized$or(an array of at least two objects whose field names are not reserved rule keywords) matches when any of its member policies matches, sibling keys are AND-ed with it, member keys are AND-ed internally, and nested$oris supported; an unrecognized$oris treated as a literal attribute name, as on AWS. Applies to theMessageAttributesfilter scope. Reported by @StiliyanDr. - CloudWatch —
GetMetricDatahonoursMetricStatdimensions —GetMetricDataresolved a query by namespace and metric name alone, ignoringMetricStat.Metric.Dimensions, so it aggregated across every dimension set and even returned data for a dimension value that was never published. Each(namespace, name, dimension-set)is a distinct metric;GetMetricDatanow filters by the query's exact dimensions, matching whatGetMetricStatisticsandListMetricsalready do. Reported by @boesing. - RDS —
StopDBCluster/StartDBClusternow stop and start Aurora compute — both operations only flipped metadata: a "stopped" cluster's backing container kept running and accepting SQL connections, and its members never leftavailable.StopDBClusternow stops the cluster's shared container — preserving the container, volume, and data, exactly like Aurora keeps the cluster volume — and marks the cluster and every memberstopped.StartDBClusterrestarts the preserved container (recreating compute from the persistent named volume when the container is gone or unrestartable) and, likeCreateDBInstance, returns immediately with a transitional status while a readiness worker flips the cluster and members toavailableonce the database accepts authenticated connections. Invalid transitions return the AWS-exactInvalidDBClusterStateFaultmessages — includingCreateDBInstance/DeleteDBInstanceagainst a stopped cluster — and a warm boot keeps an intentionally stopped cluster stopped instead of reviving its compute. A start whose compute genuinely fails to come back lands the cluster back onstopped(retryable) instead of reporting a dead endpoint asavailable, and a stop that cannot stop the container surfaces an error instead of publishing a falsestopped. Contributed by @Kiran01bm. - RDS — Aurora PostgreSQL engine versions are validated at create time —
CreateDBCluster/CreateDBInstanceaccepted anyEngineVersionstring foraurora-postgresql: because the Docker image is derived from the major alone, a bogus minor like16.99silently ran PostgreSQL 16 while claiming to be16.99, and only an unknown major produced a visible image-pull failure. An unknown version — anythingDescribeDBEngineVersionsdoesn't advertise and that isn't a dot-boundary prefix of an advertised version (bare majors like16stay accepted, since real AWS resolves them server-side) — now fails immediately withInvalidParameterCombination/Cannot find version {version} for aurora-postgresql, matching real AWS and the existing aurora-mysql behavior;DescribeOrderableDBInstanceOptionsrejects unknown versions the same way instead of echoing a fabricated option. The advertised catalog is refreshed to the full creatable set real AWS returns (41 versions, 11.9 through 18.4, including-limitlessvariants, as of 2026-08-06) and is a single shared constant used by both the catalog and the validator; the defaultaurora-postgresqlversion is now17.7(AWS's current default) and the CloudFormationAWS::RDS::DBClusterprovisioner uses that shared default instead of a hard-coded15.4. Contributed by @Kiran01bm. - RDS — duplicate DB instance wire code matches AWS — a duplicate
CreateDBInstance,CreateDBInstanceReadReplica, orRestoreDBInstanceFromDBSnapshottarget returned wire codeDBInstanceAlreadyExistsFault, but real AWS omits theFaultsuffix for instance-level error codes (cluster-level codes such asDBClusterAlreadyExistsFaultkeep it). SDKs match the exact string to produce their typed error — aws-sdk-go-v2, for example, deserialized the response as a generic API error instead of the typedDBInstanceAlreadyExistsFault. The wire code is nowDBInstanceAlreadyExists. This deliberately reverts the v1.1.18 change, which mistook the SDK exception shape name for the wire code — the model'serror.codefield (DBInstanceAlreadyExists) is what SDKs match, and exact-string tests now pin the correct direction. Contributed by @Kiran01bm. - Query-protocol services MiniStack does not implement now return a parseable error — a call to an unimplemented Query service (
redshift,elasticbeanstalk,cloudsearch,sdb,importexport) fell through to S3 and returned a 405<Error>root that botocore's query parser can't read, raising a bareKeyError('Error')instead of aClientError. Such requests now return a Query<ErrorResponse>envelope (<Type>Sender</Type>, codeInvalidAction) at HTTP 400. - AWS Backup, CloudFront, Inspector2, and MediaConnect — unrouted read operations — services MiniStack ships whose REST sub-paths returned
Unknown path, so an SDK call reached the service and got an error where AWS returns data. Roughly 96 read operations across the four now return AWS-shaped responses (Backup 47, Inspector2 22, CloudFront 14, MediaConnect 13); operations that require a resource store MiniStack does not keep were left unrouted rather than given a fabricated shape. - CloudFormation —
AWS::KMS::KeyhonoursKeySpecand update semantics — the provisioner hard-codedSYMMETRIC_DEFAULTand droppedKeyPolicy,Tags,Enabled, andEnableKeyRotation, so a template asking for an asymmetric or otherwise-specced key reachedCREATE_COMPLETEwhileDescribeKeyreported a symmetric key, and had no update handler (a changed resource minted a brand-new key). It now delegates toCreateKeyso the CFN and API paths agree, translatesKeyPolicy/Tags, appliesEnabled/EnableKeyRotation/RotationPeriodInDays, adds an update handler that fails the immutableKeySpec/KeyUsage/Origin/MultiRegionproperties and applies the mutable ones in place, schedules deletion (withDeletionDate) instead of dropping the key, and fails the stack on an unimplemented spec rather than silently substituting a symmetric key.RSA_3072is now creatable viaCreateKey. Contributed by @hiddengearz. - CloudWatch Logs — Insights
toMillis(@timestamp)filters andGetQueryResultspagination — the Insights subset ignoredfilter toMillis(@timestamp) <=|>=|<|>|=|!= <epoch_ms>, so sort+limit alone returned the wrong edge of the stream, andGetQueryResultsreturned the full result set regardless ofmaxItems.toMillis(@timestamp)comparisons are now honoured, andGetQueryResultspages withmaxItems/nextToken. Contributed by @ovsteenb. - EC2 —
AuthorizeSecurityGroupIngress/AuthorizeSecurityGroupEgressecho the existing rule on a duplicate — both operations skip a rule that already exists (idempotency) but also dropped it from the response, returning an emptysecurityGroupRuleSet; terraform-provider-aws readsSecurityGroupRules[0]with no length check and panics. The already-present rule is still not re-appended, but it is now echoed insecurityGroupRuleSetwith the same idDescribeSecurityGroupRulesreports. This hits egress on the first apply, whereCreateSecurityGroupseeds the default allow-all rule that Terraform then re-declares. Contributed by @sac-outsystems.