A Docker-based solution for locally testing Echidna fuzzing configurations before deploying to Digital Ocean droplets via CloudExec. This tool helps you quickly validate that your fuzzing jobs will run successfully in the cloud by simulating the exact same environment locally.
- Overview
- Why Use This Tool?
- System Requirements
- Installation
- Quick Start
- Detailed Usage
- Configuration Options
- Understanding the Output
- Troubleshooting
- Architecture Details
- Team Distribution
This tool creates a Docker container that perfectly mirrors your Digital Ocean Ubuntu 22.04 droplets, complete with:
- Custom Echidna binary from DigitalOcean Spaces
- Foundry toolchain (forge, cast, anvil)
- Automatic repository cloning from GitHub
- Support for private repositories via GitHub tokens
- Dependency installation automation
- Configuration persistence for cloud deployment
When running Echidna fuzzing jobs on Digital Ocean droplets through CloudExec, it can take significant time to discover whether there's an error with the build or run configuration. Failed jobs waste both time and cloud resources.
This Docker environment allows you to:
- Test locally first - Validate your fuzzing configuration in seconds, not minutes
- Catch errors early - Identify build issues, missing dependencies, or incorrect entry points before cloud deployment
- Save cloud resources - Only deploy jobs that you know will run successfully
- Maintain consistency - Use the exact same environment as your cloud droplets
- Store configurations - Automatically save working configurations for cloud deployment
- Docker (version 20.10 or higher)
- Docker Compose (version 2.0 or higher)
- Operating System: macOS, Linux, or Windows with WSL2
- Memory: At least 4GB RAM available for Docker
- Disk Space: 2GB for Docker images + space for your repositories
This tool works on both Intel/AMD (x86_64) and Apple Silicon (ARM64) systems:
- Intel/AMD Macs & PCs: Native performance
- Apple Silicon Macs (M1/M2/M3): Uses x86_64 emulation via Rosetta 2
β οΈ Note: First build may take longer (~5-10 minutes) on Apple Siliconβ οΈ Performance: Fuzzing may run slower due to emulation overhead- The container uses
--platform=linux/amd64to ensure consistency
# Option 1: If distributing via git
git clone https://github.com/GuardianOrg/DockerBuildTest echidna-local-test
cd echidna-local-test
# Option 2: If distributing as a zip file
unzip echidna-local-test.zip
cd echidna-local-testdocker --version
docker-compose --versionIf Docker is not installed, visit Docker's official website for installation instructions.
chmod +x run.sh quick-test.sh./run.sh -iThis will prompt you for:
- GitHub repository URL
- GitHub token (if private repo)
- Commit hash (optional)
- Dependency setup command
- Echidna entry point
- Copy the example configuration:
cp env.example .env- Edit
.envwith your values:
nano .env # or use your preferred editor- Run the test:
./run.sh./quick-test.sh https://github.com/user/repo.git "test/fuzzing/Fuzz.sol --contract Fuzz"The main script for running tests with various options:
./run.sh [OPTIONS]Options:
-h, --help: Show help message-i, --interactive: Run in interactive mode (prompts for all values)-c, --config FILE: Use a specific .env file (default: .env)-s, --save: Save configuration to .env file (useful with -i)-l, --logs: Show container logs after starting-d, --detach: Run container in background
Examples:
# Interactive mode with config saving
./run.sh -i -s
# Use custom configuration file
./run.sh -c production.env
# Run in background and show logs
./run.sh -d -l
# Interactive mode for one-time test (no save)
./run.sh -iFor rapid testing when you know your parameters:
./quick-test.sh <github-url> <entry-point> [commit-hash] [dependency-setup]Examples:
# Basic usage
./quick-test.sh https://github.com/OpenZeppelin/openzeppelin-contracts.git \
"test/fuzzing/TestContract.sol --contract TestContract"
# With specific commit
./quick-test.sh https://github.com/user/repo.git \
"contracts/test/Fuzz.sol --contract FuzzTest" \
"abc123def456"
# With dependencies
./quick-test.sh https://github.com/user/repo.git \
"test/Fuzz.sol --contract Fuzz" \
"main" \
"npm install && forge build"Create a .env file with the following variables:
# Required
GITHUB_URL=https://github.com/username/repository.git
ENTRY_POINT=test/fuzzing/Fuzz.sol --contract Fuzz
# Optional
GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx # For private repositories
COMMIT_HASH=abc123def456789 # Specific commit to test
DEPENDENCY_SETUP=npm install && forge build # Commands to run before fuzzing- The full GitHub repository URL
- Supports both HTTPS and SSH formats
- Examples:
https://github.com/OpenZeppelin/openzeppelin-contracts.git[email protected]:user/private-repo.git(requires GITHUB_TOKEN)
- The Echidna command arguments (everything after
echidna) - Format:
path/to/contract.sol --contract ContractName [additional-flags] - Note:
--config echidna.yamlis automatically appended to all commands - Examples:
test/fuzzing/Fuzz.sol --contract Fuzzcontracts/test/InvariantTest.sol --contract InvariantTestsrc/TestContract.sol --contract TestContract --test-limit 10000
- Personal Access Token for private repositories
- Create one at: https://github.com/settings/tokens
- Required permissions:
repo(full control of private repositories) - The token is securely injected into the git URL for cloning
- Specific commit, branch, or tag to test
- If not provided, uses the default branch (usually
mainormaster) - Examples:
- Commit hash:
abc123def456789 - Branch:
develop - Tag:
v2.0.0
- Commit hash:
- Shell commands to run after cloning but before fuzzing
- Common examples:
npm install- Install Node.js dependenciesforge install- Install Foundry dependenciesforge build- Build Foundry projectnpm install && forge build- Combined setuppip install -r requirements.txt- Python dependenciesmake setup- Custom Makefile target
When everything works correctly, you'll see:
π Starting Echidna Local Test Environment
================================================
π¦ Repository: your-repo
π₯ Cloning repository...
π¦ Running dependency setup...
πΎ Saving configuration...
Configuration saved to: /workspace/fuzzing_config.json
{
"github_url": "https://github.com/user/repo.git",
"commit_hash": "abc123...",
"entry_point": "test/Fuzz.sol --contract Fuzz",
"dependency_setup": "forge build",
"timestamp": "2024-01-15T10:30:00Z"
}
================================================
π― Starting Echidna fuzzing...
Entry point: echidna test/Fuzz.sol --contract Fuzz
================================================
Analyzing contract: /workspace/repo/test/Fuzz.sol:Fuzz
Running tests...
[... Echidna output ...]
The tool saves your configuration in two places:
- Inside the container:
/workspace/fuzzing_config.json - On your host:
./output/fuzzing_config.json(if you mount the volume)
This JSON file contains all the parameters needed to replicate the test in the cloud:
{
"github_url": "https://github.com/user/repo.git",
"commit_hash": "abc123def456789...",
"entry_point": "test/Fuzz.sol --contract Fuzz",
"dependency_setup": "npm install && forge build",
"timestamp": "2024-01-15T10:30:00Z"
}Use these exact values when setting up your CloudExec jobs.
# View container logs
docker logs echidna-local-test
# Enter the container for debugging
docker exec -it echidna-local-test /bin/bash
# Check if Echidna is installed correctly
docker exec echidna-local-test echidna --version
# Check if Foundry is installed correctly
docker exec echidna-local-test forge --version
# Clean up all containers and images
docker-compose down
docker system prune -a
# Rebuild from scratch
docker-compose build --no-cacheThe Docker image is built on Ubuntu 22.04 (matching Digital Ocean droplets) and includes:
-
Base System:
- Ubuntu 22.04 LTS
- Git for repository cloning
- Python3 and pip
- Node.js and npm
- curl, unzip for downloading tools
-
Echidna Installation:
- Custom binary from:
https://guardianexec-echidna.nyc3.digitaloceanspaces.com/echidna - Installed to:
/usr/local/bin/echidna - Pre-compiled, no solc-select needed
- Custom binary from:
-
Foundry Toolchain:
- Specific nightly version for consistency
- Installed to:
/root/.foundry - Binaries linked globally: forge, cast, anvil
- Container Start: Docker container launches with Ubuntu 22.04
- Environment Check: Validates required environment variables
- Repository Clone: Clones the specified GitHub repository
- Commit Checkout: Switches to specified commit/branch/tag
- Dependency Installation: Runs user-specified setup commands
- Configuration Save: Stores configuration for cloud deployment
- Echidna Execution: Runs fuzzing with specified entry point
echidna-local-test/
βββ Dockerfile # Ubuntu 22.04 + Echidna + Foundry setup
βββ docker-compose.yml # Container orchestration
βββ entrypoint.sh # Container startup script
βββ run.sh # Main user interface script
βββ quick-test.sh # Quick testing script
βββ env.example # Configuration template
βββ .env # Your configuration (git-ignored)
βββ output/ # Output directory (created automatically)
β βββ fuzzing_config.json
βββ configs/ # Additional configs (created automatically)