DEV Community

Cover image for MiniStack v1.1.2 — Cognito, EC2, EMR, 656 Tests, and Zero Docker Leaks
Nahuel Nucera
Nahuel Nucera

Posted on

MiniStack v1.1.2 — Cognito, EC2, EMR, 656 Tests, and Zero Docker Leaks

We just shipped MiniStack v1.1.2. This is the biggest release since the initial launch — full Amazon Cognito support, partial EC2, EMR, a complete test suite overhaul, and a pile of infrastructure fixes that make running MiniStack day-to-day significantly cleaner.

If you're not familiar: MiniStack is a free, open-source local AWS emulator. One port, no account, no license key. A drop-in replacement for LocalStack — which moved its core services behind a paid plan.


What's new in v1.1.0

Amazon Cognito — full emulation

This was the most requested feature since launch. v1.1.0 ships complete Cognito support across both planes:

User Pools (cognito-idp)

  • Full user lifecycle: SignUp, ConfirmSignUp, AdminCreateUser, AdminDeleteUser, AdminGetUser, ListUsers
  • Auth flows: USER_PASSWORD_AUTH, ADMIN_USER_PASSWORD_AUTH, REFRESH_TOKEN_AUTH, USER_SRP_AUTH (returns PASSWORD_VERIFIER challenge)
  • FORCE_CHANGE_PASSWORD challenge on first login
  • Self-service: ForgotPassword, ConfirmForgotPassword, ChangePassword, GetUser, DeleteUser
  • Groups, domains, MFA config, tags — all covered

Identity Pools (cognito-identity)

  • CreateIdentityPool, GetId, GetCredentialsForIdentity, GetOpenIdToken
  • SetIdentityPoolRoles, GetIdentityPoolRoles
  • Federated identity: MergeDeveloperIdentities, UnlinkIdentity

OAuth2

  • POST /oauth2/token — client_credentials flow, returns stub Bearer token

Stub JWTs are structurally valid base64url tokens — they pass format checks in most SDKs without needing real crypto.

import boto3

idp = boto3.client("cognito-idp", endpoint_url="http://localhost:4566",
                   aws_access_key_id="test", aws_secret_access_key="test",
                   region_name="us-east-1")

# Create a pool
pool = idp.create_user_pool(PoolName="my-app")
pool_id = pool["UserPool"]["Id"]

# Sign up a user
idp.sign_up(
    ClientId="local",
    Username="alice@example.com",
    Password="Password123!",
    UserAttributes=[{"Name": "email", "Value": "alice@example.com"}],
)

# Confirm and authenticate
idp.admin_confirm_sign_up(UserPoolId=pool_id, Username="alice@example.com")
resp = idp.initiate_auth(
    AuthFlow="USER_PASSWORD_AUTH",
    AuthParameters={"USERNAME": "alice@example.com", "PASSWORD": "Password123!"},
    ClientId="local",
)
print(resp["AuthenticationResult"]["AccessToken"])
Enter fullscreen mode Exit fullscreen mode

644 tests — one file, all passing

We merged a separate QA test file into the main suite and fixed every test bug we found along the way:

  • test_s3_list_v1_marker_paginationNextMarker only returned when Delimiter is set (AWS spec)
  • test_iam_inline_user_policy — boto3 deserialises PolicyDocument as a dict, not a string
  • test_kinesis_at_timestamp_iterator — boto3 already returns Data as bytes, no need to base64-decode
  • test_rds_snapshot_crud / test_rds_deletion_protection — added finally cleanup so containers are deleted after each test

644 tests across all 25 services. Single file. All passing.


Docker volume leak — fixed

This one was subtle. Every RDS (CreateDBInstance) and ElastiCache (CreateCacheCluster) call spins up a real Docker container. The postgres and mysql images declare VOLUME /var/lib/postgresql/data — so Docker was creating an anonymous volume for every container, even after the container was removed.

After 20 test runs: 30+ dangling volumes, 600MB+ of wasted space.

Two fixes:

  1. tmpfs on containers.run() — postgres/mysql data lives in container RAM. No volume created.
  2. container.remove(v=True) in reset() — volumes are removed with the container.
Before: 32 dangling volumes after 3 test runs
After:  2 volumes total (ministack + redis, always)
Enter fullscreen mode Exit fullscreen mode

Clean up what you already have:

make purge
Enter fullscreen mode Exit fullscreen mode

make purge — safe cleanup

purge: stop-compose
    docker rm -f $(docker ps -aq --filter "label=ministack") 2>/dev/null || true
    docker volume prune -f
    rm -rf ./data/s3/*
Enter fullscreen mode Exit fullscreen mode

Every container MiniStack spins up is labelled ministack=true. The purge target uses that label — it won't touch your other Redis, Postgres, or MySQL containers.


Bug fixes

  • Lambda GetFunctionConcurrency — was returning 404 after DeleteFunctionConcurrency. Now returns {} matching AWS behaviour
  • ElastiCache ModifyCacheParameterGroup — parameter key format was wrong (member vs ParameterNameValue). Modified params were silently ignored
  • RDS ModifyDBInstanceDeletionProtection=False with ApplyImmediately=True now correctly applies immediately
  • Cognito GetCredentialsForIdentity — response field is SecretKey (correct boto3 wire name)
  • Port conflict on pip installministack now prints a clear error if port 4566 is already in use instead of a raw uvicorn traceback

AWS CLI docs fix

A user reported credentials failing. The README was showing aws configure --profile local but then omitting --profile local from the example commands. Fixed — two working options now documented:

Option A — environment variables

export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1

aws --endpoint-url=http://localhost:4566 s3 mb s3://my-bucket
Enter fullscreen mode Exit fullscreen mode

Option B — named profile

aws configure --profile local
# Access Key: test / Secret: test / Region: us-east-1

aws --profile local --endpoint-url=http://localhost:4566 s3 mb s3://my-bucket
Enter fullscreen mode Exit fullscreen mode

Get it

# PyPI
pip install --upgrade ministack

# Docker
docker pull nahuelnucera/ministack:latest
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

GitHub: github.com/Nahuel990/ministack

25 AWS services. Free. MIT licensed. No account required.


What's next

  • SFN Activities (CreateActivity, GetActivityTask) — already requested
  • State persistence for Secrets Manager, SSM, DynamoDB — PERSIST_STATE=1 currently only covers API Gateway
  • ACM — last item on the original roadmap

Issues and PRs welcome.

Top comments (0)