This guide provides a complete, repeatable testing workflow for termiNATor using the chetz-playground AWS account. Scans are region-scoped: pick one region, then optionally narrow to one or more VPCs or NAT Gateways inside that region. The test infrastructure is designed to be:
Use this before E2E to verify CLI stream-mode wiring and validation:
./test/scripts/smoke-ui-stream.sh
What it validates:
scan quick and scan deep expose --ui--ui values fail fast--ui stream path is reachable for quick/deep commandsRun this checklist on both macOS and Linux terminals.
go build -o terminat .
COLUMNS=80 ./terminat scan demo --ui stream
Check:
COLUMNS=100 ./terminat scan demo --ui stream
Check:
COLUMNS=120 ./terminat scan demo --ui stream
Check:
./terminat scan demo
./terminat scan demo --ui tui
Check:
┌─────────────────────────────────────────────────────────────┐
│ Test VPC (10.0.0.0/16) │
├─────────────────────────────────────────────────────────────┤
│ │
│ Public Subnet (10.0.1.0/24) │
│ ├─ Internet Gateway │
│ └─ NAT Gateway (nat-test-xxx) │
│ │
│ Private Subnet (10.0.2.0/24) │
│ ├─ Route: 0.0.0.0/0 → NAT Gateway │
│ ├─ EC2 Test Instance (Amazon Linux 2023) │
│ │ └─ Generates S3 and DynamoDB traffic via NAT │
│ └─ Lambda Test Function (optional) │
│ └─ Generates S3 traffic via NAT │
│ │
└─────────────────────────────────────────────────────────────┘
Setup:
Expected behavior:
Validation:
pkt-dstaddr matching S3/DynamoDB IP rangesSetup:
Expected behavior:
Validation:
Setup:
Expected behavior:
Validation:
Setup:
Expected behavior:
Validation:
chetz-playground account accessus-east-1 (or configurable)# Deploy the test infrastructure
aws cloudformation create-stack \
--stack-name terminator-test-infra \
--template-body file://test/infrastructure/test-stack.yaml \
--capabilities CAPABILITY_IAM \
--region us-east-1
# Wait for stack creation
aws cloudformation wait stack-create-complete \
--stack-name terminator-test-infra \
--region us-east-1
# Get outputs (NAT Gateway ID, EC2 Instance ID, etc.)
aws cloudformation describe-stacks \
--stack-name terminator-test-infra \
--region us-east-1 \
--query 'Stacks[0].Outputs'
Stack creates:
# Run traffic generation script on EC2 instance
./test/scripts/generate-traffic.sh \
--instance-id <EC2_INSTANCE_ID> \
--duration 5 \
--s3-requests 100 \
--dynamodb-requests 50
Script does:
# Connect to EC2 instance
aws ssm start-session --target <EC2_INSTANCE_ID>
# Generate S3 traffic (download objects repeatedly)
for i in {1..100}; do
aws s3 cp s3://terminator-test-bucket-<ACCOUNT_ID>/test-file-0.bin /tmp/test-$i.bin
rm /tmp/test-$i.bin
done
# Generate DynamoDB traffic (scan table repeatedly)
for i in {1..50}; do
aws dynamodb scan --table-name terminator-test-table --max-items 100
done
# Check traffic is going through NAT
# (should see private IP as source, NAT Gateway as next hop)
# Run Quick Win Scan
./terminat scan quick --region us-east-1
# Expected findings:
# - Missing S3 gateway endpoint in VPC vpc-xxx
# - Missing DynamoDB gateway endpoint in VPC vpc-xxx
# Start continuous traffic generation
./test/scripts/continuous-traffic.sh start
# Run Deep Dive (5 min collection window)
./terminat scan deep \
--region us-east-1 \
--duration 5
# Expected results:
# - S3 traffic: > 0 GB (should match generated traffic volume)
# - DynamoDB traffic: > 0 GB
# - Estimated monthly savings: $X.XX (based on NAT data processing)
# Add S3 Gateway endpoint
aws ec2 create-vpc-endpoint \
--vpc-id <VPC_ID> \
--service-name com.amazonaws.us-east-1.s3 \
--route-table-ids <PRIVATE_RT_ID>
# Generate traffic again
./test/scripts/continuous-traffic.sh start
# Run Deep Dive
./terminat scan deep --region us-east-1 --duration 5
# Expected results:
# - S3 traffic: 0 GB (traffic now goes via endpoint)
# - DynamoDB traffic: > 0 GB (still via NAT)
# - Estimated savings reduced (only DynamoDB avoidable now)
# Add DynamoDB Gateway endpoint
aws ec2 create-vpc-endpoint \
--vpc-id <VPC_ID> \
--service-name com.amazonaws.us-east-1.dynamodb \
--route-table-ids <PRIVATE_RT_ID>
# Generate traffic again
./test/scripts/continuous-traffic.sh start
# Run Deep Dive
./terminat scan deep --region us-east-1 --duration 5
# Expected results:
# - S3 traffic: 0 GB
# - DynamoDB traffic: 0 GB
# - Estimated savings: $0 (no avoidable NAT traffic)
| Test Case | Expected Finding | Pass Criteria |
|---|---|---|
| No endpoints exist | Missing S3 and DynamoDB endpoints | Both flagged as missing |
| Endpoint exists but not associated | Endpoint not associated with private RT | Flagged with route table recommendation |
| Endpoints properly configured | No findings | No recommendations for S3/DynamoDB |
| Scenario | S3 Traffic (GB) | DynamoDB Traffic (GB) | Savings Estimate |
|---|---|---|---|
| Baseline (no endpoints) | > 0 | > 0 | > $0 |
| S3 endpoint added | 0 | > 0 | Reduced (DDB only) |
| Both endpoints added | 0 | 0 | $0 |
# Verify Flow Logs were created
aws ec2 describe-flow-logs \
--filter "Name=tag:CreatedBy,Values=termiNATor" \
--region us-east-1
# Verify Flow Logs contain pkt-dstaddr field
aws logs get-log-events \
--log-group-name <LOG_GROUP> \
--log-stream-name <LOG_STREAM> \
--limit 10 \
| jq '.events[].message' \
| grep pkt-dstaddr
# Verify cleanup removed Flow Logs
aws ec2 describe-flow-logs \
--filter "Name=tag:RunId,Values=<RUN_ID>" \
--region us-east-1
# Should return empty after cleanup
# Run complete test suite
./test/run-all-tests.sh
# This script:
# 1. Deploys test infrastructure
# 2. Runs baseline tests (no endpoints)
# 3. Adds S3 endpoint and reruns
# 4. Adds DynamoDB endpoint and reruns
# 5. Validates all results
# 6. Generates test report
# 7. Cleans up infrastructure
test/
├── infrastructure/
│ └── test-stack.yaml # CloudFormation template
├── scripts/
│ ├── continuous-traffic.sh # Traffic generation (start/stop/status)
│ ├── run-e2e-test.sh # Automated E2E test
│ ├── deploy-test-infra.sh # Deploy CloudFormation stack
│ ├── cleanup.sh # Cleanup helper
│ └── smoke-ui-stream.sh # Smoke test (no AWS needed)
├── results/
│ └── .gitkeep # Test results stored here
└── TESTING.md # This guide
# Delete CloudFormation stack (removes all resources)
aws cloudformation delete-stack \
--stack-name terminator-test-infra \
--region us-east-1
# Wait for deletion
aws cloudformation wait stack-delete-complete \
--stack-name terminator-test-infra \
--region us-east-1
# Run cleanup script
./test/scripts/cleanup.sh --region us-east-1
# Script removes:
# - VPC endpoints created during tests
# - Flow Logs created by termiNATor
# - CloudWatch Log Groups
# - Test S3 bucket contents
# - DynamoDB table
# - NAT Gateway (waits for deletion)
# - Elastic IP
# - VPC and subnets
# Check for orphaned resources
aws ec2 describe-nat-gateways \
--filter "Name=tag:Purpose,Values=termiNATor-test" \
--region us-east-1
aws ec2 describe-flow-logs \
--filter "Name=tag:CreatedBy,Values=termiNATor" \
--region us-east-1
aws logs describe-log-groups \
--log-group-name-prefix "/aws/vpc/flowlogs/terminator" \
--region us-east-1
| Resource | Cost | Notes |
|---|---|---|
| NAT Gateway (hourly) | ~$0.07 | $0.045/hour × 1.5 hours |
| NAT Gateway (data processing) | ~$0.05 | ~1 GB test traffic × $0.045/GB |
| VPC Flow Logs (CloudWatch) | ~$0.01 | ~20 MB logs × $0.50/GB |
| EC2 t3.micro (hourly) | ~$0.02 | $0.0104/hour × 1.5 hours |
| Total per test run | ~$0.15 | Approximate |
Symptoms: Deep Dive shows 0 bytes for S3/DynamoDB even without endpoints
Checks:
# Verify route table
aws ec2 describe-route-tables --route-table-ids <PRIVATE_RT_ID>
# Should show 0.0.0.0/0 → nat-xxx
# Verify EC2 instance subnet
aws ec2 describe-instances --instance-ids <INSTANCE_ID> \
--query 'Reservations[0].Instances[0].SubnetId'
# Should match private subnet
# Check security group allows outbound
aws ec2 describe-security-groups --group-ids <SG_ID>
Symptoms: Flow Logs exist but show no records
Checks:
# Verify Flow Log status
aws ec2 describe-flow-logs --flow-log-ids <FLOW_LOG_ID>
# Status should be "ACTIVE"
# Check CloudWatch Log Group
aws logs describe-log-streams \
--log-group-name <LOG_GROUP> \
--order-by LastEventTime \
--descending
# Should show recent log streams
# Verify log format includes pkt-dstaddr
aws ec2 describe-flow-logs --flow-log-ids <FLOW_LOG_ID> \
--query 'FlowLogs[0].LogFormat'
Symptoms: S3 traffic reported as “Other” or incorrect service
Checks:
# Manually inspect Flow Logs
aws logs filter-log-events \
--log-group-name <LOG_GROUP> \
--filter-pattern "ACCEPT" \
--limit 20
# Verify pkt-dstaddr matches S3 IP ranges
# Download AWS IP ranges
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json \
| jq '.prefixes[] | select(.service=="S3" and .region=="us-east-1")'
# Check if pkt-dstaddr falls in S3 ranges
name: termiNATor Integration Tests
on:
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * 1' # Weekly on Monday 2 AM
jobs:
integration-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::381491970320:role/GitHubActionsRole
aws-region: us-east-1
- name: Run integration tests
run: |
./test/run-all-tests.sh
- name: Upload test results
uses: actions/upload-artifact@v3
with:
name: test-results
path: test/results/
- name: Cleanup on failure
if: failure()
run: |
./test/scripts/cleanup.sh --region us-east-1
Before submitting a PR that changes detection logic, run:
test/results/test/infrastructure/test-stack.yaml)test/scripts/generate-traffic.sh)test/scripts/validate-results.sh)test/run-all-tests.sh)