May 5, 2026 · v1.3.28
One new endpoint family and a DynamoDB parity fix that's been hiding for a while.
Every container started by RunTask now gets ECS_CONTAINER_METADATA_URI_V4 injected into its environment. The MiniStack gateway serves the standard task-metadata routes off the existing 4566 port, keyed by a per-container secrets.token_urlsafe(32) value:
GET /v4/<token> — current container metadata (DockerId, Name, Image, Labels, DesiredStatus, KnownStatus, Type).GET /v4/<token>/task — task metadata with the sibling Containers array, so multi-container tasks see each other.GET /v4/<token>/stats and /task/stats — empty-object stub for now.Standard com.amazonaws.ecs.* labels are stamped on the Docker container (task-arn, container-name, task-definition-family, task-definition-version, cluster) so anything that scrapes labels works the same way it does on real ECS. The token registry is volatile by design: it's stripped from persisted state and cleared by /_ministack/reset.
Unlocks running ECS instrumentation, security agents, and any application code that calls $ECS_CONTAINER_METADATA_URI_V4/task end-to-end against MiniStack — including in CI. Contributed by @YakirOren.
Same PR also extends RunTask to translate more of the task definition into Docker run options:
privileged → Docker privilegedlinuxParameters.capabilities.add → Docker cap_addpidMode: host → Docker pid_mode: hostnetworkMode: host → Docker network_mode: host (and the metadata URI uses loopback)volumes + mountPoints → Docker bind mounts (list-of-binds, so two ECS volumes that share a host SourcePath don't collide on dict-key dedup)$ aws --endpoint-url=http://localhost:4566 ecs run-task \
--cluster default --task-definition my-app
# inside the container:
$ wget -qO- "$ECS_CONTAINER_METADATA_URI_V4/task" | jq .Containers
Expected and KeyConditionsThe pre-expression DynamoDB API (Expected on PutItem / UpdateItem / DeleteItem, KeyConditions on Query, full ScanFilter / QueryFilter operator coverage) was previously ignored — only the modern expression form was honoured. SDKs and code paths still using the legacy parameters (older Boto2 ports, some Java SDK v1 callers, Terraform code paths that round-trip through legacy schemas, and AWS CLI scripts written before the expression API existed) silently passed conditions that should have failed, or vice-versa.
Fixed in this release. Every ComparisonOperator the legacy API supports now evaluates correctly with type-aware comparison (so numeric {"N":"10"} > {"N":"2"} is true, not the lexicographic "10" < "2" a string compare would give):
EQ, NE, LE, LT, GE, GT, NOT_NULL, NULL, CONTAINS, NOT_CONTAINS, BEGINS_WITH, IN, BETWEEN.
Mixing the legacy and expression forms in the same call now returns the AWS-shape ValidationException ("Can not use both expression and non-expression parameters in the same request") instead of silently honouring one and dropping the other. Expected shorthand forms ({"Exists": true/false}, {"Value": <attr>}) and ConditionalOperator: "OR" are honoured.
TransactWriteItems multi-failure reportingWhen a TransactWriteItems call had multiple items whose conditions failed, only the first failure was marked in CancellationReasons; every subsequent item was returned as Code: "None". AWS returns a ConditionalCheckFailed entry for every failing item in the transaction. MiniStack now evaluates all conditions in a first pass, then emits the cancellation array in one go — matching the AWS shape exactly. ReturnValuesOnConditionCheckFailure="ALL_OLD" still attaches the prior Item per failing reason where the per-op flag was set.
docker pull ministackorg/ministack:1.3.28 docker run -d -p 4566:4566 ministackorg/ministack:1.3.28
Or pin in compose.yaml:
services:
ministack:
image: ministackorg/ministack:1.3.28
ports:
- "4566:4566"
Shipped by the MiniStack community. Contributions credited throughout. GitHub · r/ministack