github ministackorg/ministack v1.4.14

4 hours ago

What's Changed

New Contributors

[1.4.14] — 2026-08-07

Added

  • CodeBuild - builds can really run (MINISTACK_CODEBUILD_EXECUTE=1) - StartBuild returned a build that was already SUCCEEDED, 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, StartBuild returns IN_PROGRESS and 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's environment.image the way CodeBuild does - the phase semantics come from AWS's own agent instead of a reimplemented executor. BatchGetBuilds reflects progress while the build runs: the agent's Phase complete: <PHASE> State: <STATUS> lines become phases entries, and the container's exit status maps to SUCCEEDED / FAILED, with FAULT when Docker is unreachable. environment.environmentVariables, privilegedMode, and the CODEBUILD_BUILD_ID / _ARN / _NUMBER / _INITIATOR variables reach the build. The build reaches back into MiniStack: AWS_ENDPOINT_URL (plus placeholder credentials) is injected unless the project declares its own, so aws s3 cp inside a build hits this emulator rather than real AWS. timeoutInMinutes is enforced (the build is stopped and its phase reported TIMED_OUT), and a restored build that was in flight when MiniStack stopped is reported FAULT rather than polling as running forever. StopBuild is honoured deterministically: it records the intent before removing the container, so the worker reports the requested STOPPED instead of racing it to FAULT. Build output also reaches CloudWatch Logs: the record already advertised logs.groupName / logs.streamName, and an executed build now writes the agent output there, so aws logs get-log-events and aws logs tail read 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-pipes fell through to S3 virtual-host addressing and returned NoSuchBucket. ListPipes, CreatePipe, DescribePipe, UpdatePipe, DeletePipe, StartPipe, StopPipe, and the tag operations are now served over boto3 / Terraform / CDK at pipes.<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's awscc provider and CDK L1 constructs: CreateResource / GetResource / UpdateResource / DeleteResource / ListResources plus the resource-request status and cancel operations, with the AWS ProgressEvent and ResourceDescription shapes (Properties as 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 whose ExplicitAuthFlows includes ALLOW_USER_AUTH now drives a multi-step choice-based flow driven by Policies.SignInPolicy.AllowedFirstAuthFactors: username, then a challenge-selection screen (skipped when only one factor is allowed), then PASSWORD or EMAIL_OTP entry, ending in the standard authorization-code redirect. EMAIL_OTP codes are fixed at 123456 (consistent with the existing confirmation/reset codes) but verified against the session; WEB_AUTHN and SMS_OTP are out of scope. Clients without ALLOW_USER_AUTH keep the single-page form unchanged. Contributed by @kjdev.
  • KMS — UpdateKeyDescription — the action was not registered, so every call returned InvalidAction: Unknown action (HTTP 400) and terraform-provider-aws failed the whole update whenever an aws_kms_key description 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, and NotFoundException for an unknown key. Contributed by @sac-outsystems.

Fixed

  • SNS — $or operator in subscription filter policies — a filter policy with a top-level $or key was matched with plain AND semantics, so $or never matched and every message was silently dropped as non-matching. $or is 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 $or is supported; an unrecognized $or is treated as a literal attribute name, as on AWS. Applies to the MessageAttributes filter scope. Reported by @StiliyanDr.
  • CloudWatch — GetMetricData honours MetricStat dimensionsGetMetricData resolved a query by namespace and metric name alone, ignoring MetricStat.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; GetMetricData now filters by the query's exact dimensions, matching what GetMetricStatistics and ListMetrics already do. Reported by @boesing.
  • RDS — StopDBCluster / StartDBCluster now 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 left available. StopDBCluster now 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 member stopped. StartDBCluster restarts the preserved container (recreating compute from the persistent named volume when the container is gone or unrestartable) and, like CreateDBInstance, returns immediately with a transitional status while a readiness worker flips the cluster and members to available once the database accepts authenticated connections. Invalid transitions return the AWS-exact InvalidDBClusterStateFault messages — including CreateDBInstance/DeleteDBInstance against 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 on stopped (retryable) instead of reporting a dead endpoint as available, and a stop that cannot stop the container surfaces an error instead of publishing a false stopped. Contributed by @Kiran01bm.
  • RDS — Aurora PostgreSQL engine versions are validated at create timeCreateDBCluster / CreateDBInstance accepted any EngineVersion string for aurora-postgresql: because the Docker image is derived from the major alone, a bogus minor like 16.99 silently ran PostgreSQL 16 while claiming to be 16.99, and only an unknown major produced a visible image-pull failure. An unknown version — anything DescribeDBEngineVersions doesn't advertise and that isn't a dot-boundary prefix of an advertised version (bare majors like 16 stay accepted, since real AWS resolves them server-side) — now fails immediately with InvalidParameterCombination / Cannot find version {version} for aurora-postgresql, matching real AWS and the existing aurora-mysql behavior; DescribeOrderableDBInstanceOptions rejects 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 -limitless variants, as of 2026-08-06) and is a single shared constant used by both the catalog and the validator; the default aurora-postgresql version is now 17.7 (AWS's current default) and the CloudFormation AWS::RDS::DBCluster provisioner uses that shared default instead of a hard-coded 15.4. Contributed by @Kiran01bm.
  • RDS — duplicate DB instance wire code matches AWS — a duplicate CreateDBInstance, CreateDBInstanceReadReplica, or RestoreDBInstanceFromDBSnapshot target returned wire code DBInstanceAlreadyExistsFault, but real AWS omits the Fault suffix for instance-level error codes (cluster-level codes such as DBClusterAlreadyExistsFault keep 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 typed DBInstanceAlreadyExistsFault. The wire code is now DBInstanceAlreadyExists. This deliberately reverts the v1.1.18 change, which mistook the SDK exception shape name for the wire code — the model's error.code field (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 bare KeyError('Error') instead of a ClientError. Such requests now return a Query <ErrorResponse> envelope (<Type>Sender</Type>, code InvalidAction) 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::Key honours KeySpec and update semantics — the provisioner hard-coded SYMMETRIC_DEFAULT and dropped KeyPolicy, Tags, Enabled, and EnableKeyRotation, so a template asking for an asymmetric or otherwise-specced key reached CREATE_COMPLETE while DescribeKey reported a symmetric key, and had no update handler (a changed resource minted a brand-new key). It now delegates to CreateKey so the CFN and API paths agree, translates KeyPolicy/Tags, applies Enabled/EnableKeyRotation/RotationPeriodInDays, adds an update handler that fails the immutable KeySpec/KeyUsage/Origin/MultiRegion properties and applies the mutable ones in place, schedules deletion (with DeletionDate) instead of dropping the key, and fails the stack on an unimplemented spec rather than silently substituting a symmetric key. RSA_3072 is now creatable via CreateKey. Contributed by @hiddengearz.
  • CloudWatch Logs — Insights toMillis(@timestamp) filters and GetQueryResults pagination — the Insights subset ignored filter toMillis(@timestamp) <=|>=|<|>|=|!= <epoch_ms>, so sort+limit alone returned the wrong edge of the stream, and GetQueryResults returned the full result set regardless of maxItems. toMillis(@timestamp) comparisons are now honoured, and GetQueryResults pages with maxItems / nextToken. Contributed by @ovsteenb.
  • EC2 — AuthorizeSecurityGroupIngress / AuthorizeSecurityGroupEgress echo the existing rule on a duplicate — both operations skip a rule that already exists (idempotency) but also dropped it from the response, returning an empty securityGroupRuleSet; terraform-provider-aws reads SecurityGroupRules[0] with no length check and panics. The already-present rule is still not re-appended, but it is now echoed in securityGroupRuleSet with the same id DescribeSecurityGroupRules reports. This hits egress on the first apply, where CreateSecurityGroup seeds the default allow-all rule that Terraform then re-declares. Contributed by @sac-outsystems.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.