Metadata-Version: 2.4
Name: localemu
Version: 1.0.0
Summary: The core library and runtime of LocalEmu
Author-email: LocalEmu Contributors <info@localemu.cloud>
License-Expression: Apache-2.0
Project-URL: Homepage, https://localemu.cloud
Project-URL: Documentation, https://localemu.cloud/docs
Project-URL: Repository, https://github.com/localemu/localemu.git
Project-URL: Issues, https://github.com/localemu/localemu/issues
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: System :: Emulators
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: asn1crypto>=1.5.1
Requires-Dist: click>=8.2.0
Requires-Dist: cachetools>=5.0
Requires-Dist: cryptography>=46.0.7
Requires-Dist: PyJWT[crypto]>=2.8.0
Requires-Dist: dnspython>=1.16.0
Requires-Dist: plux>=1.14.0
Requires-Dist: psutil>=5.4.8
Requires-Dist: python-dotenv>=0.19.1
Requires-Dist: pyyaml>=5.1
Requires-Dist: rich>=12.3.0
Requires-Dist: requests>=2.20.0
Requires-Dist: semver>=2.10
Provides-Extra: base-runtime
Requires-Dist: boto3==1.42.59; extra == "base-runtime"
Requires-Dist: botocore==1.42.59; extra == "base-runtime"
Requires-Dist: awscrt!=0.27.1,>=0.13.14; extra == "base-runtime"
Requires-Dist: cbor2>=6.0; extra == "base-runtime"
Requires-Dist: dill==0.3.6; extra == "base-runtime"
Requires-Dist: dnspython>=1.16.0; extra == "base-runtime"
Requires-Dist: docker>=6.1.1; extra == "base-runtime"
Requires-Dist: jsonpatch>=1.24; extra == "base-runtime"
Requires-Dist: jsonpointer>=3.0.0; extra == "base-runtime"
Requires-Dist: jsonschema>=4.25.1; extra == "base-runtime"
Requires-Dist: hypercorn>=0.14.4; extra == "base-runtime"
Requires-Dist: Twisted[tls]>=26.4.0; extra == "base-runtime"
Requires-Dist: openapi-core>=0.19.2; extra == "base-runtime"
Requires-Dist: pydantic>=2.11.9; extra == "base-runtime"
Requires-Dist: pyopenssl>=23.0.0; extra == "base-runtime"
Requires-Dist: python-dateutil>=2.9.0; extra == "base-runtime"
Requires-Dist: readerwriterlock>=1.0.7; extra == "base-runtime"
Requires-Dist: requests-aws4auth>=1.0; extra == "base-runtime"
Requires-Dist: urllib3>=2.7.0; extra == "base-runtime"
Requires-Dist: Werkzeug>=3.1.3; extra == "base-runtime"
Requires-Dist: xmltodict>=0.13.0; extra == "base-runtime"
Requires-Dist: rolo>=0.8.1; extra == "base-runtime"
Provides-Extra: runtime
Requires-Dist: localemu[base-runtime]; extra == "runtime"
Requires-Dist: awscli==1.44.49; extra == "runtime"
Requires-Dist: airspeed-ext>=0.6.3; extra == "runtime"
Requires-Dist: antlr4-python3-runtime==4.13.2; extra == "runtime"
Requires-Dist: apispec>=5.1.1; extra == "runtime"
Requires-Dist: aws-sam-translator>=1.105.0; extra == "runtime"
Requires-Dist: crontab>=0.22.6; extra == "runtime"
Requires-Dist: cryptography>=46.0.7; extra == "runtime"
Requires-Dist: jinja2>=3.1.6; extra == "runtime"
Requires-Dist: jsonpath-ng==1.7.0; extra == "runtime"
Requires-Dist: jsonpath-rw>=1.4.0; extra == "runtime"
Requires-Dist: moto-ext[all]>=5.1.22; extra == "runtime"
Requires-Dist: opensearch-py>=2.4.1; extra == "runtime"
Requires-Dist: duckdb>=1.0; extra == "runtime"
Requires-Dist: sqlglot>=23; extra == "runtime"
Requires-Dist: pymongo>=4.2.0; extra == "runtime"
Requires-Dist: PyJWT[crypto]>=2.8.0; extra == "runtime"
Requires-Dist: pyopenssl>=23.0.0; extra == "runtime"
Requires-Dist: responses>=0.25.8; extra == "runtime"
Provides-Extra: test
Requires-Dist: localemu[runtime]; extra == "test"
Requires-Dist: coverage[toml]>=5.5; extra == "test"
Requires-Dist: httpx[http2]>=0.25; extra == "test"
Requires-Dist: json5>=0.12.1; extra == "test"
Requires-Dist: pluggy>=1.3.0; extra == "test"
Requires-Dist: pytest>=7.4.2; extra == "test"
Requires-Dist: pytest-split>=0.8.0; extra == "test"
Requires-Dist: pytest-httpserver>=1.1.2; extra == "test"
Requires-Dist: pytest-rerunfailures>=12.0; extra == "test"
Requires-Dist: pytest-tinybird>=0.5.0; extra == "test"
Requires-Dist: aws-cdk-lib>=2.88.0; extra == "test"
Requires-Dist: websocket-client>=1.7.0; extra == "test"
Requires-Dist: deepdiff; extra == "test"
Requires-Dist: jsonpath-ng>1.6; extra == "test"
Requires-Dist: pika>=1.3; extra == "test"
Requires-Dist: kafka-python>=2.0; extra == "test"
Provides-Extra: dev
Requires-Dist: localemu[test]; extra == "dev"
Requires-Dist: coveralls>=3.3.1; extra == "dev"
Requires-Dist: deptry>=0.13.0; extra == "dev"
Requires-Dist: Cython; extra == "dev"
Requires-Dist: networkx>=2.8.4; extra == "dev"
Requires-Dist: openapi-spec-validator>=0.7.1; extra == "dev"
Requires-Dist: pandoc; extra == "dev"
Requires-Dist: pre-commit>=3.5.0; extra == "dev"
Requires-Dist: pypandoc; extra == "dev"
Requires-Dist: ruff>=0.3.3; extra == "dev"
Requires-Dist: rstr>=3.2.0; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: watchdog>=6; extra == "dev"
Provides-Extra: typehint
Requires-Dist: localemu[dev]; extra == "typehint"
Requires-Dist: boto3-stubs[acm,acm-pca,amplify,apigateway,apigatewayv2,appconfig,appconfigdata,application-autoscaling,appsync,athena,autoscaling,backup,batch,ce,cloudcontrol,cloudformation,cloudfront,cloudtrail,cloudwatch,codebuild,codecommit,codeconnections,codedeploy,codepipeline,codestar-connections,cognito-identity,cognito-idp,dms,docdb,dynamodb,dynamodbstreams,ec2,ecr,ecs,efs,eks,elasticache,elasticbeanstalk,elbv2,emr,emr-serverless,es,events,firehose,fis,glacier,glue,iam,identitystore,iot,iot-data,iotwireless,kafka,kinesis,kinesisanalyticsv2,kms,lakeformation,lambda,logs,managedblockchain,mediaconvert,mq,mwaa,neptune,opensearch,organizations,pi,pinpoint,pipes,rds,rds-data,redshift,redshift-data,resource-groups,resourcegroupstaggingapi,route53,route53resolver,s3,s3control,sagemaker,sagemaker-runtime,secretsmanager,serverlessrepo,servicediscovery,ses,sesv2,sns,sqs,ssm,sso-admin,stepfunctions,sts,timestream-query,timestream-write,transcribe,verifiedpermissions,wafv2,xray]; extra == "typehint"
Dynamic: license-file

<p align="center">
  <img src="https://raw.githubusercontent.com/localemu/localemu/main/docs/localemu-logo.png" alt="LocalEmu" width="120">
</p>

<h1 align="center">LocalEmu</h1>

<p align="center">
  A free, open-source AWS cloud emulator.
</p>

<p align="center">
  <a href="https://pypi.org/project/localemu/"><img alt="PyPI" src="https://img.shields.io/pypi/v/localemu?color=blue"></a>
  <a href="https://pypi.org/project/localemu/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/localemu"></a>
  <a href="https://hub.docker.com/r/localemu/localemu"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/localemu/localemu"></a>
  <a href="https://github.com/localemu/localemu/blob/main/LICENSE"><img alt="License: Apache 2.0" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg"></a>
</p>

<p align="center">
  <img alt="Emulates AWS" src="https://img.shields.io/badge/emulates-AWS-FF9900?logo=amazonwebservices&logoColor=white">
  <img alt="AWS services" src="https://img.shields.io/badge/AWS%20services-132-1f6feb">
  <a href="https://github.com/localemu/localemu/blob/main/CONTRIBUTING.md"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg"></a>
  <a href="https://github.com/astral-sh/ruff"><img alt="Ruff" src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json"></a>
  <a href="https://github.com/localemu/localemu/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/localemu/localemu?color=yellow"></a>
</p>

<p align="center">
  Run AWS services locally. No account. No token. No sign-up.
</p>

---

## What is LocalEmu?

LocalEmu emulates 132 AWS services on your machine. Use the same AWS CLI, boto3, Terraform, or CDK you already know - just point to `localhost:4566`.

**Build and test against AWS APIs from your laptop with no account, no credentials, no internet.** The iteration loop is seconds instead of minutes; you can break, reset, and rebuild as often as you want at zero cost.

Where it counts, the behavior is real, not stubbed: Lambda runs your code in the official AWS runtime images, EC2 instances are real containers on a real VPC with security groups enforced by actual packet filtering, RDS is a real PostgreSQL or MySQL you can open a connection to, and (with `IAM_ENFORCEMENT=1`) your identity and resource policies actually deny.

## Install

```bash
pip install localemu[runtime]
```

That's it. No Java. No tokens. No accounts. Docker is required for services that emulate by running a real engine in a sidecar (Lambda, ECS, EKS via k3d, RDS, OpenSearch, EC2). Everything else is pure Python and needs no Docker.

## Start

```bash
# Foreground (see the banner and logs)
localemu start

# Detached mode (runs in background)
localemu start -d

# Custom port
localemu start --port 4567

# Stop
localemu stop
```

## Use

LocalEmu ships `awsemu` - a drop-in replacement for the AWS CLI that automatically points to LocalEmu. No configuration needed:

```bash
# S3
awsemu s3 mb s3://my-bucket
awsemu s3 cp file.txt s3://my-bucket/

# DynamoDB
awsemu dynamodb create-table --table-name Users \
  --key-schema AttributeName=id,KeyType=HASH \
  --attribute-definitions AttributeName=id,AttributeType=S \
  --billing-mode PAY_PER_REQUEST

# SQS
awsemu sqs create-queue --queue-name my-queue

# Lambda
awsemu lambda create-function --function-name hello \
  --runtime python3.12 --handler handler.handler \
  --role arn:aws:iam::000000000000:role/role \
  --zip-file fileb://function.zip

# Any of the 132 supported services...
awsemu ecs create-cluster --cluster-name my-cluster
awsemu rds describe-db-instances
awsemu cognito-idp create-user-pool --pool-name my-pool
```

`awsemu` sets credentials, region, and endpoint automatically. You can also use the standard AWS CLI, boto3, Terraform, CDK, or Pulumi - just point to `http://localhost:4566`.

## Documentation & examples

The full documentation lives at [localemu.cloud/docs](https://localemu.cloud/docs): prerequisites, install guide, per-service API reference, and end-to-end use case walkthroughs.

For runnable code, clone the companion examples repository:

```bash
git clone https://github.com/localemu/localemu-examples
```

It ships self-contained tutorials covering common patterns: public + private VPC with EC2 / nginx / NACL, image pipelines, scheduled jobs, IAM least-privilege drills, Step Functions sagas, EKS + kubectl, chaos resilience tests, and more.

## Explore

```bash
# List all supported services
localemu services

# Show operations for a specific service
localemu services s3
localemu services lambda
localemu services dynamodb

# Check running services
localemu status

# Stop
localemu stop
```

## Dashboard

LocalEmu includes a built-in web dashboard for monitoring and exploring your local AWS environment in real time.

```
http://localhost:4566/_localemu/dashboard
```

The dashboard shows:
- **Service overview** with resource counts and status indicators for all active services
- **Resource drill-down**: click any service to see tables, buckets, queues, functions, instances, and more
- **S3 object browser** and **DynamoDB item viewer** with click-through navigation
- **CloudTrail event history** with expandable request/response details
- **Live activity feed** showing API calls as they happen, filterable by service

The dashboard starts automatically with LocalEmu. No configuration needed.

## Simulation Features

Test real AWS behavior locally with opt-in feature flags:

```bash
# IAM policy enforcement (full AWS evaluation algorithm, see section below)
IAM_ENFORCEMENT=1 localemu start

# API throttling simulation (per-service AWS error codes)
SIMULATE_THROTTLING=1 THROTTLE_RATE=0.05 localemu start

# Network latency injection (realistic per-service delays)
SIMULATE_LATENCY=1 localemu start

# Lambda cold start simulation
LAMBDA_COLD_START_DELAY=3 localemu start

# EC2, ECS, and EKS use real containers automatically when Docker is
# available; no env var needed. Opt out via EC2_VM_MANAGER=none,
# ECS_DOCKER_BACKEND=0, or EKS_K8S_PROVIDER=off.

# Real RDS engines (PostgreSQL / MySQL / MariaDB in containers)
RDS_DOCKER_BACKEND=1 localemu start
```

Simulation features (IAM enforcement, throttling, latency, cold-start) are disabled by default; zero overhead when off. The container-backed services turn themselves off automatically when the Docker daemon is unavailable.

## IAM Policy Enforcement

Run your AWS workload against the same policy rules AWS applies in production. Useful for catching permission errors locally before they surface in a deployed environment.

```bash
# Strict mode: deny unauthorized requests with 403 AccessDenied
IAM_ENFORCEMENT=1 localemu start

# Audit mode: log would-be denials, allow the request through
IAM_ENFORCEMENT=soft localemu start

# Bypass enforcement for specific access keys (comma-separated allow-list)
ROOT_ACCESS_KEYS=AKIAIOSFODNN7EXAMPLE IAM_ENFORCEMENT=1 localemu start
```

**What gets evaluated** (full AWS algorithm, see [policy evaluation logic](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html)):

- Explicit `Deny` in any policy → deny (identity / resource / permission boundary / session).
- Same-account: either identity-policy `Allow` OR resource-policy `Allow` is sufficient.
- Permission boundary: must also `Allow` (intersection).
- Session policies (inline or managed) passed via `AssumeRole`: must also `Allow` (intersection).

**Policy elements**

| Element | Supported |
|---|---|
| `Action` / `NotAction` with wildcards `*` `?` | ✅ |
| `Resource` / `NotResource` ARN matching | ✅ |
| `Principal` / `NotPrincipal` (AWS / Service / Federated / CanonicalUser) | ✅ |
| IAM policy variables: `${aws:username}`, `${aws:userid}`, `${aws:PrincipalTag/*}` | ✅ |
| String / Numeric / Date / IpAddress / Bool / Arn / Null operators | ✅ |
| `IfExists` suffix | ✅ |
| `ForAllValues:` / `ForAnyValue:` set operators | ✅ |

**Condition context keys populated per request**

`aws:PrincipalArn`, `aws:PrincipalAccount`, `aws:PrincipalType`, `aws:SourceIp`, `aws:CurrentTime`, `aws:EpochTime`, `aws:SecureTransport` (from TLS scheme), `aws:UserAgent`, `aws:RequestedRegion`, `aws:username`, `aws:userid`, `aws:PrincipalTag/*`, `aws:RequestTag/*`, `aws:TagKeys`, and `aws:MultiFactorAuthPresent` (set to `"true"` only when the caller's session was minted by `AssumeRole` / `GetSessionToken` with `--serial-number`, otherwise absent per AWS spec).

**Temporary-credential validation**: temporary access keys (`ASIA*` / `LSIA*`) must include an `X-Amz-Security-Token`. Expired sessions return `ExpiredTokenException`.

**Limitations**

- Cross-account calls (caller account ≠ resource owner account) are currently treated as same-account. LocalEmu defaults to a single account so this rarely matters; if you emulate multi-account IAM flows, enforcement will be more permissive than AWS.
- Service-principal grants on resource policies (e.g. `Principal: {Service: lambda.amazonaws.com}`) are not auto-matched for internal service-to-service calls; use `AWS` principals or `*` for now.

## 132 Supported Services

Run `localemu services` to see the full list. Key services include: ACM, API Gateway, AppSync, Athena, Backup, Batch, Bedrock, CloudFormation, CloudFront, CloudTrail, CloudWatch, CodeBuild, CodeCommit, CodeDeploy, CodePipeline, Cognito, Config, DynamoDB, EC2, ECR, ECS, EFS, EKS, ElastiCache, ELB, ELBv2, Elasticsearch, EMR, EventBridge, Firehose, FSx, Glacier, Glue, GuardDuty, IAM, IoT, Kafka, Kinesis, KMS, Lambda, CloudWatch Logs, Neptune, OpenSearch, Organizations, Pipes, RDS, Redshift, Rekognition, Resource Groups, Route53, S3, SageMaker, Scheduler, Secrets Manager, SES, SESv2, SNS, SQS, SSM, Step Functions, STS, Textract, Transcribe, Transfer, WAFv2, X-Ray, and more.

## Python (boto3)

```python
import boto3

s3 = boto3.client("s3",
    endpoint_url="http://localhost:4566",
    aws_access_key_id="AKIAIOSFODNN7EXAMPLE",
    aws_secret_access_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    region_name="us-east-1",
)

s3.create_bucket(Bucket="my-bucket")
s3.put_object(Bucket="my-bucket", Key="hello.txt", Body=b"Hello!")
```

## Terraform

```hcl
provider "aws" {
  access_key                  = "AKIAIOSFODNN7EXAMPLE"
  secret_key                  = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  region                      = "us-east-1"
  skip_credentials_validation = true
  skip_metadata_api_check     = true

  endpoints {
    s3       = "http://localhost:4566"
    dynamodb = "http://localhost:4566"
    lambda   = "http://localhost:4566"
    sqs      = "http://localhost:4566"
    # all services on the same endpoint
  }
}
```

## Persistence

By default, LocalEmu state is ephemeral. To keep your resources across restarts:

```bash
# Local
PERSISTENCE=1 localemu start

# Docker
docker run -d --name localemu \
  -p 4566:4566 \
  -v localemu-data:/var/lib/localemu \
  -e PERSISTENCE=1 \
  --user root \
  localemu/localemu
```

State is saved on shutdown and restored on startup. S3 buckets, DynamoDB tables,
Lambda functions, SQS queues, Secrets Manager secrets. Everything survives.

**Save strategies** (set via `SNAPSHOT_SAVE_STRATEGY`):
- `ON_SHUTDOWN` (default): saves when LocalEmu stops
- `SCHEDULED`: saves every 15 seconds (configurable via `SNAPSHOT_FLUSH_INTERVAL`)
- `MANUAL`: save/load via `POST /_localemu/state/save` and `POST /_localemu/state/load`

**Check status:** `GET /_localemu/state/status`

## Docker (alternative)

```bash
# Linux
docker run --rm -d -p 4566:4566 -p 4510-4559:4510-4559 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --group-add docker \
  localemu/localemu

# macOS (Docker Desktop)
docker run --rm -d -p 4566:4566 -p 4510-4559:4510-4559 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --user root \
  localemu/localemu
```

> **Why `--user root` on macOS?** Lambda, ECS, and EC2 services spawn real
> Docker containers for function execution. On Docker Desktop for Mac the
> socket is owned by `root` inside the container regardless of host GID, so
> the non-root `localemu` user cannot access it. On Linux, adding the
> `docker` group (`--group-add docker`) is sufficient.

## Using the AWS CLI with Docker

When LocalEmu runs in Docker, use the standard AWS CLI from your host:

```bash
# Option A: set the endpoint once via env var (recommended)
export AWS_ENDPOINT_URL=http://localhost:4566
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=us-east-1

aws s3 ls
aws dynamodb list-tables
aws lambda list-functions
```

```bash
# Option B: create a host-side awsemu alias
alias awsemu='aws --endpoint-url=http://localhost:4566 --region us-east-1'
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

awsemu s3 ls
awsemu sqs list-queues
```

```bash
# Option C: use awsemu inside the container
docker exec localemu bash -c \
  '. /opt/code/localemu/.venv/bin/activate && awsemu s3 ls'
```

> **Tip:** Option A with `AWS_ENDPOINT_URL` is the cleanest: boto3 and the
> AWS CLI both read it automatically. Your code works identically on LocalEmu
> and real AWS by just unsetting the env var.

## Contributing

- [Open issues](https://github.com/localemu/localemu/issues)
- [Discussions](https://github.com/localemu/localemu/discussions)

## License

Copyright (c) 2026 TocConsulting and LocalEmu contributors.
Copyright (c) 2017-2026 LocalStack contributors.
Copyright (c) 2016 Atlassian and others.

Apache License, Version 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).

LocalEmu is a fork of [LocalStack](https://github.com/localstack/localstack), which was archived by its maintainers. We are grateful to all original contributors.
