@icedlongblack04/chaos-cli
v1.0.0
Published
CLI tool for chaos engineering on local AWS cloud infrastructure
Readme
Table of Contents
- Why ChaosCli?
- How It Works
- Quick Start
- Fault Types
- Config File
- CLI Reference
- Using with LocalStack / MiniStack
- Development
- License
Why ChaosCli?
Chaos engineering for local cloud infrastructure shouldn't require modifying your application code or SDK configuration. ChaosCli sits between your application and your local AWS emulator, intercepting traffic and injecting faults based on simple JSON rules.
- Plug & Play - Zero modifications needed, just direct current requests to ChaosCLI's drop-in proxy using
--endpoint-urland you good to go. - AWS Compatability - Works with any AWS-compatible emulators.
- Self-contained - Pure Node.js built-ins only; no extra packages required to run.
- Easy to use - Just create a JSON file with your fault rules and run
chaos start.
How It Works
ChaosCli runs as a transparent HTTP reverse proxy. Requests from your AWS CLI or SDK hit the proxy first. The proxy inspects each request, matches it against your fault rules, and either injects a fault or forwards the request unmodified to the upstream emulator.
Quick Start
# Install globally
npm install -g @icedlongblack04/chaos-cli
# Start your AWS emulator (e.g. MiniStack)
docker run -p 4566:4566 ministackorg/ministack
# Create a fault rules file
cat > chaos.json << 'EOF'
{
"rules": [
{
"service": "s3",
"operation": "*",
"faultType": "latency",
"probability": 0.5,
"params": { "delayMs": 2000 }
}
]
}
EOF
# Start the proxy and point it to your emulator
chaos start --target http://localhost:4566
# Point your AWS CLI at the proxy instead of your emulator directly
aws --endpoint-url=http://localhost:2705 s3 lsFault Types
Compute & Node Level
| Fault Type | Behaviour |
| ------------------------ | -------------------------------------------------------------------------------------- |
| latency | Delays the request by params.delayMs ms (default: 2000), then forwards normally |
| instance_failure | Responds immediately with params.statusCode (default: 503); upstream is never called |
| resource_exhaustion | Accepts the connection but never responds — simulates a hung or CPU-saturated process |
| processing_termination | Sends partial response headers, then destroys the socket mid-stream |
Network Layer
| Fault Type | Behaviour |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| packet_loss | Destroys the client socket immediately — simulates dropped packets or a silent timeout |
| packet_corruption | Forwards to upstream, then XOR-corrupts every params.corruptEvery-th byte of the response body (default: every 8th byte) |
| dns_failure | Responds with 503 and {"error":"NXDOMAIN","message":"Name resolution failed"} |
| network_partition | Closes the TCP connection immediately — simulates a full network split to the service |
Config File
Create one or more files matching chaos*.json in your working directory. The proxy discovers and merges all of them at startup.
{
"rules": [
{
"service": "dynamodb",
"operation": "PutItem",
"faultType": "latency",
"probability": 1.0,
"params": { "delayMs": 3000 }
},
{
"service": "s3",
"operation": "*",
"faultType": "instance_failure",
"probability": 0.3,
"params": { "statusCode": 503 }
},
{
"service": "*",
"operation": "*",
"faultType": "packet_corruption",
"probability": 0.1,
"params": { "corruptEvery": 8 }
}
]
}Rule fields:
| Field | Type | Required | Description |
| ------------- | ------ | -------- | ----------------------------------------------------------------------- |
| service | string | yes | AWS service name (e.g. s3, dynamodb, sqs) or * to match all |
| operation | string | yes | AWS operation name (e.g. PutItem, GetObject) or * to match all |
| faultType | string | yes | One of the 8 fault types listed above |
| probability | number | yes | Float between 0.0 and 1.0 — fraction of matching requests to affect |
| params | object | no | Fault-specific parameters (see tables above) |
Rules are evaluated in order. The first matching rule that fires (probabilistically) wins.
CLI Reference
chaos start [options]
Start the chaos proxy server
Options:
-p, --port Port for the proxy to listen on [number] [default: 2705]
-t, --target Upstream LocalStack/MiniStack URL [string] [default: "http://localhost:4566"]
-c, --config Directory to scan for chaos*.json files [string] [default: "."]
--help Show help
--version Show version numberUsing with LocalStack / MiniStack
# Start your local AWS emulator on the default port
docker run -p 4566:4566 localstack/localstack
# or
docker run -p 4566:4566 ministackorg/ministack
# Start ChaosCli in front of it
chaos start --target http://localhost:4566
# Configure the AWS CLI
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
# Use --endpoint-url pointing at the proxy (port 2705), not LocalStack directly
aws --endpoint-url=http://localhost:2705 s3 mb s3://my-bucket
aws --endpoint-url=http://localhost:2705 s3 cp ./file.txt s3://my-bucket/
aws --endpoint-url=http://localhost:2705 dynamodb list-tables
aws --endpoint-url=http://localhost:2705 sqs create-queue --queue-name my-queue
aws --endpoint-url=http://localhost:2705 sts get-caller-identityUsing with boto3
import boto3
def client(service):
return boto3.client(
service,
endpoint_url="http://localhost:2705", # proxy, not LocalStack directly
aws_access_key_id="test",
aws_secret_access_key="test",
region_name="us-east-1",
)
# S3 — 50% of requests will be delayed 2 seconds (if your chaos.json says so)
s3 = client("s3")
s3.create_bucket(Bucket="my-bucket")
s3.put_object(Bucket="my-bucket", Key="hello.txt", Body=b"Hello, ChaosCli!")
# DynamoDB
ddb = client("dynamodb")
ddb.put_item(TableName="Users", Item={"userId": {"S": "u1"}, "name": {"S": "Alice"}})
# SQS
sqs = client("sqs")
q = sqs.create_queue(QueueName="my-queue")
sqs.send_message(QueueUrl=q["QueueUrl"], MessageBody="hello")Development
git clone https://github.com/kaydenpham27/chaos-cli
cd chaos-cli
npm install
npm run build # compile TypeScript → dist/
npm test # run all unit + integration tests
npm run test:watch # watch mode
npm run test:coverage # coverage report
npm run lint # ESLint
npm run dev # run without compiling (ts-node)License
MIT
