Docker Development Workflow

Docker Development Workflow

The following files were used as context for generating this wiki page:

Purpose and Scope

This document covers the Docker-based development workflow for WSHawk contributors. It focuses on building, testing, and iterating on WSHawk using Docker and docker-compose for local development, as well as the automated CI/CD pipeline that builds and publishes multi-architecture images.

For deploying and using pre-built Docker images, see Docker Usage Guide. For general development environment setup without Docker, see Development Environment Setup. For CI/CD integration strategies, see CI/CD Integration.


Local Development Environment with docker-compose

The docker-compose.yml configuration provides a complete local development environment with both the WSHawk container and a test server for integration testing.

docker-compose Architecture

graph TB
    subgraph "Local Development Setup"
        DC[docker-compose.yml]
        
        subgraph "wshawk Service"
            WC["Container: wshawk<br/>network_mode: host<br/>entrypoint: /bin/bash"]
            WV["Volume Mount:<br/>./reports:/app/reports"]
            WE["Environment:<br/>PYTHONUNBUFFERED=1"]
        end
        
        subgraph "vulnerable-server Service"
            VS["Container: wshawk-test-server<br/>python:3.11-slim<br/>Port: 8765:8765"]
            VV["Volume Mount:<br/>./examples:/app"]
            VC["Command:<br/>python3 -m http.server 8765"]
        end
        
        subgraph "Network Layer"
            HN["host network<br/>for wshawk"]
            BN["wshawk-network<br/>bridge driver<br/>for vulnerable-server"]
        end
        
        subgraph "Host Filesystem"
            Reports["./reports/<br/>Scan output"]
            Examples["./examples/<br/>Test servers"]
        end
    end
    
    DC --> WC
    DC --> VS
    
    WC --> WV
    WC --> WE
    WC --> HN
    
    VS --> VV
    VS --> VC
    VS --> BN
    
    WV --> Reports
    VV --> Examples

Sources: docker-compose.yml:1-36

Starting the Development Environment

# Start services in detached mode
docker-compose up -d

# Access interactive shell in wshawk container
docker-compose exec wshawk /bin/bash

# Inside container, run development commands
wshawk ws://vulnerable-server:8765
wshawk-defensive ws://localhost:8765

# View logs
docker-compose logs -f wshawk

# Stop services
docker-compose down

The wshawk service uses network_mode: host docker-compose.yml:9 to simplify testing against local services, while the vulnerable-server operates on a bridge network for isolation.

Sources: docker-compose.yml:1-36, docs/DOCKER.md:87-98

Volume Mounts for Live Development

| Mount Point | Purpose | Read/Write | |-------------|---------|------------| | ./reports:/app/reports | Output directory for scan reports and screenshots | Read/Write | | ./examples:/app (vulnerable-server) | Test WebSocket servers and examples | Read-Only |

To mount source code for live editing:

# Modify docker-compose.yml to add source mount
volumes:
  - ./reports:/app/reports
  - ./wshawk:/app/wshawk  # Live source editing

Sources: docker-compose.yml:11-12, docker-compose.yml:26-27


Multi-Stage Dockerfile Build Process

The Dockerfile implements a two-stage build to minimize final image size while maintaining all build dependencies.

Build Stage Architecture

graph LR
    subgraph "Stage 1: builder"
        B1["FROM python:3.11-slim"]
        B2["Install gcc<br/>build dependencies"]
        B3["COPY setup.py<br/>pyproject.toml<br/>README.md<br/>wshawk/"]
        B4["pip install<br/>--no-cache-dir"]
        B5["Compiled packages in<br/>/usr/local/lib/python3.11/site-packages"]
    end
    
    subgraph "Stage 2: Final"
        F1["FROM python:3.11-slim"]
        F2["Install ca-certificates<br/>runtime dependencies"]
        F3["COPY --from=builder<br/>/usr/local/lib/python3.11/site-packages"]
        F4["COPY --from=builder<br/>/usr/local/bin/wshawk*"]
        F5["Create non-root user<br/>wshawk:1000"]
        F6["USER wshawk"]
        F7["ENTRYPOINT wshawk"]
    end
    
    B1 --> B2
    B2 --> B3
    B3 --> B4
    B4 --> B5
    
    F1 --> F2
    F2 --> F3
    F3 --> F4
    F4 --> F5
    F5 --> F6
    F6 --> F7
    
    B5 -.->|"COPY --from=builder"| F3
    B5 -.->|"COPY --from=builder"| F4

Sources: Dockerfile:1-66

Building Locally

# Standard build
docker build -t wshawk:dev .

# Build with specific tag
docker build -t wshawk:3.0.0-dev .

# Build with BuildKit cache
DOCKER_BUILDKIT=1 docker build --cache-from wshawk:latest -t wshawk:dev .

# Verify build
docker run --rm wshawk:dev --help
docker run --rm --entrypoint wshawk-defensive wshawk:dev --help

The multi-stage build removes 200MB+ of build dependencies (gcc, headers) from the final image Dockerfile:4-21.

Sources: Dockerfile:1-66, docs/DOCKER.md:29-37

Image Optimization with .dockerignore

The .dockerignore file excludes unnecessary files from the build context, reducing build time and image size:

| Category | Excluded Patterns | Reason | |----------|-------------------|--------| | Python artifacts | __pycache__/, *.pyc, *.egg-info/ | Generated files | | Virtual environments | venv/, env/, wshawk_venv/ | Not needed in container | | Development files | .vscode/, .idea/, *.swp | IDE-specific | | Test artifacts | .pytest_cache/, .coverage, .hypothesis/ | Testing output | | Reports | *.html, *.log, reports/ | Scan output | | Documentation | docs/, *.md (except README.md) | Not needed at runtime | | CI/CD | .github/, .gitlab-ci.yml | Workflow files |

Sources: .dockerignore:1-72


CI/CD Pipeline Architecture

The GitHub Actions workflow automates building, testing, and publishing Docker images for multiple architectures.

CI/CD Workflow Stages

graph TB
    subgraph "Trigger Events"
        T1["git push<br/>to main branch"]
        T2["git tag<br/>v*"]
        T3["Pull Request<br/>to main"]
        T4["Manual<br/>workflow_dispatch"]
    end
    
    subgraph "Build Environment"
        R["runs-on:<br/>ubuntu-latest"]
        P["Permissions:<br/>contents: read<br/>packages: write"]
    end
    
    subgraph "Setup Stage"
        S1["Checkout repository<br/>actions/checkout@v4"]
        S2["Setup QEMU<br/>docker/setup-qemu-action@v3<br/>for arm64 emulation"]
        S3["Setup Docker Buildx<br/>docker/setup-buildx-action@v3"]
        S4["Verify Secrets<br/>DOCKER_USERNAME<br/>DOCKER_PASSWORD"]
    end
    
    subgraph "Authentication"
        A1["Login Docker Hub<br/>docker/login-action@v3<br/>username: DOCKER_USERNAME<br/>password: DOCKER_PASSWORD"]
        A2["Login GHCR<br/>docker/login-action@v3<br/>registry: ghcr.io<br/>username: github.actor<br/>password: GITHUB_TOKEN"]
    end
    
    subgraph "Metadata Extraction"
        M["docker/metadata-action@v5<br/>Images:<br/>- rothackers/wshawk<br/>- ghcr.io/regaan/wshawk"]
        MT["Tag Strategy:<br/>- type=ref,event=branch<br/>- type=semver,pattern={{version}}<br/>- type=semver,pattern={{major}}.{{minor}}<br/>- type=raw,value=latest"]
    end
    
    subgraph "Build & Push"
        B["docker/build-push-action@v5<br/>Platforms:<br/>- linux/amd64<br/>- linux/arm64<br/>Cache:<br/>- cache-from: type=gha<br/>- cache-to: type=gha,mode=max"]
    end
    
    subgraph "Testing"
        T["docker pull<br/>docker run --rm --help<br/>docker run --rm<br/>--entrypoint wshawk-defensive<br/>--help"]
    end
    
    T1 --> R
    T2 --> R
    T3 --> R
    T4 --> R
    
    R --> S1
    R --> P
    S1 --> S2
    S2 --> S3
    S3 --> S4
    
    S4 --> A1
    S4 --> A2
    
    A1 --> M
    A2 --> M
    M --> MT
    MT --> B
    
    B --> T

Sources: .github/workflows/docker-build.yml:1-89

Multi-Architecture Build Process

The workflow builds for both linux/amd64 and linux/arm64 using QEMU emulation .github/workflows/docker-build.yml:80:

# QEMU setup enables cross-platform builds
- name: Set up QEMU
  uses: docker/setup-qemu-action@v3

# Buildx enables multi-platform support
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

# Build and push for both architectures
platforms: linux/amd64,linux/arm64

This allows the same workflow to produce images for Intel/AMD servers and ARM-based systems (Apple Silicon, ARM servers).

Sources: .github/workflows/docker-build.yml:29-33, .github/workflows/docker-build.yml:80

Image Tagging Strategy

The docker/metadata-action@v5 generates multiple tags based on Git events:

| Git Event | Generated Tags | Example | |-----------|----------------|---------| | push main | latest, main | rothackers/wshawk:latest | | tag v3.0.0 | 3.0.0, 3.0, 3, latest | rothackers/wshawk:3.0.0 | | pull_request #42 | pr-42 | rothackers/wshawk:pr-42 |

Tags are generated for both registries:

Sources: .github/workflows/docker-build.yml:56-70

GitHub Actions Cache Strategy

The workflow uses GitHub Actions cache (type=gha) to speed up subsequent builds:

cache-from: type=gha
cache-to: type=gha,mode=max

This caches Docker layers between workflow runs, reducing build time from ~10 minutes to ~2 minutes for unchanged layers.

Sources: .github/workflows/docker-build.yml:78-79


Integration Testing with Docker

Testing CLI Entrypoints in Containers

The CI/CD pipeline includes automated tests to verify all CLI entrypoints work correctly:

# Pull the built image
docker pull ghcr.io/regaan/wshawk:latest

# Test main entrypoint
docker run --rm ghcr.io/regaan/wshawk:latest --help

# Test defensive mode entrypoint
docker run --rm --entrypoint wshawk-defensive \
  ghcr.io/regaan/wshawk:latest --help

Sources: .github/workflows/docker-build.yml:82-88

Local Integration Testing Workflow

# 1. Start test environment
docker-compose up -d

# 2. Access wshawk container
docker-compose exec wshawk /bin/bash

# 3. Inside container, test against vulnerable-server
wshawk ws://vulnerable-server:8765
wshawk-defensive ws://vulnerable-server:8765
wshawk-advanced ws://vulnerable-server:8765 --smart-payloads

# 4. Verify reports are written to mounted volume
ls -la reports/

# 5. Test with host networking (for localhost testing)
exit
docker run --rm --network host wshawk:dev ws://localhost:8765

# 6. Clean up
docker-compose down

Sources: docker-compose.yml:1-36, docs/DOCKER.md:87-98


Development Best Practices

Non-Root User Considerations

The Dockerfile creates a non-root user wshawk:1000 Dockerfile:38-41:

RUN useradd -m -u 1000 wshawk && \
    chown -R wshawk:wshawk /app
USER wshawk

When mounting volumes, ensure the host directories are writable by UID 1000:

# Create reports directory with correct permissions
mkdir -p reports
chmod 755 reports

# Or run with current user (development only)
docker run --rm --user $(id -u):$(id -g) wshawk:dev ws://target.com

Sources: Dockerfile:37-41, docs/DOCKER.md:169-174

Plugin Development in Containers

To develop plugins using Docker:

# docker-compose.override.yml
version: '3.8'
services:
  wshawk:
    volumes:
      - ./plugins:/app/plugins
      - ./wshawk:/app/wshawk  # For plugin system code

Then test plugins:

docker-compose exec wshawk /bin/bash

# Inside container
cd plugins
cat > my_plugin.py << 'EOF'
from wshawk.plugin_system import PayloadPlugin, PluginMetadata

class MyPlugin(PayloadPlugin):
    def get_metadata(self):
        return PluginMetadata(
            name="my_plugin",
            version="1.0.0",
            description="Custom payloads"
        )
    
    def get_payloads(self, vuln_type):
        return ["<test>"]
EOF

# Test plugin loading
python3 -c "from wshawk.plugin_system import PluginManager; \
  m = PluginManager(); m.load_all_plugins(); print(m.list_plugins())"

Sources: wshawk/plugin_system.py:98-439, plugins/README.md:1-37

Healthcheck Configuration

The Dockerfile includes a healthcheck Dockerfile:48-49:

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD wshawk --help || exit 1

This allows Docker to monitor container health. For long-running scans, customize the healthcheck:

# docker-compose.yml override
services:
  wshawk:
    healthcheck:
      test: ["CMD", "wshawk", "--help"]
      interval: 1m
      timeout: 30s
      retries: 5
      start_period: 10s

Sources: Dockerfile:47-49


Environment Variables for Development

Docker Build Arguments

# Build with custom Python version
docker build --build-arg PYTHON_VERSION=3.11 -t wshawk:dev .

# Build with build metadata
docker build \
  --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
  --build-arg VCS_REF=$(git rev-parse --short HEAD) \
  -t wshawk:dev .

Runtime Environment Variables

Key environment variables for development:

| Variable | Purpose | Default | Example | |----------|---------|---------|---------| | PYTHONUNBUFFERED | Disable Python output buffering | 1 | 1 | | PYTHONDONTWRITEBYTECODE | Prevent .pyc files | 1 | 1 | | WSHAWK_WEB_PASSWORD | Web dashboard password | none | secure123 | | WSHAWK_API_KEY | API authentication | none | api-key-123 |

docker run --rm \
  -e PYTHONUNBUFFERED=1 \
  -e WSHAWK_WEB_PASSWORD=dev123 \
  wshawk:dev --web

Sources: Dockerfile:43-45, docs/DOCKER.md:110-118


Troubleshooting Development Issues

Build Cache Issues

# Clear Docker build cache
docker builder prune -af

# Rebuild without cache
docker build --no-cache -t wshawk:dev .

# Clear docker-compose volumes
docker-compose down -v

Volume Permission Issues

# Check current permissions
ls -la reports/

# Fix permissions for container user (UID 1000)
sudo chown -R 1000:1000 reports/

# Alternative: Run as current user
docker run --rm --user $(id -u):$(id -g) \
  -v $(pwd)/reports:/app/reports \
  wshawk:dev ws://target.com

Sources: docs/DOCKER.md:169-191

Network Connectivity Issues

# Test from within container
docker run --rm -it wshawk:dev /bin/bash
curl -v ws://target.com  # Won't work - websocket
nc -zv target.com 80     # Test TCP

# Use host network for localhost testing
docker run --rm --network host wshawk:dev ws://localhost:8765

# Check container DNS
docker run --rm wshawk:dev nslookup target.com
docker run --rm wshawk:dev cat /etc/resolv.conf

Sources: docs/DOCKER.md:176-184


Development Workflow Summary

Typical Development Cycle

graph TD
    Start["Start Development"]
    
    Edit["Edit Code<br/>wshawk/*.py"]
    
    Build["Build Docker Image<br/>docker build -t wshawk:dev ."]
    
    Test["Run Tests<br/>docker run wshawk:dev<br/>--help"]
    
    Iterate{"Tests Pass?"}
    
    Compose["Integration Test<br/>docker-compose up<br/>Test against vulnerable-server"]
    
    CI["Push to GitHub<br/>Trigger CI/CD"]
    
    Review["Review CI Results<br/>Multi-arch builds<br/>Automated tests"]
    
    Success["Merge to main<br/>Auto-publish to<br/>Docker Hub + GHCR"]
    
    Start --> Edit
    Edit --> Build
    Build --> Test
    Test --> Iterate
    Iterate -->|No| Edit
    Iterate -->|Yes| Compose
    Compose --> CI
    CI --> Review
    Review --> Success

Quick Reference Commands

# Development cycle
docker-compose up -d                    # Start environment
docker-compose exec wshawk /bin/bash    # Interactive shell
docker-compose logs -f wshawk           # View logs
docker-compose down                     # Stop environment

# Building
docker build -t wshawk:dev .            # Build local image
DOCKER_BUILDKIT=1 docker build .        # Build with cache

# Testing
docker run --rm wshawk:dev --help       # Test CLI
docker run --rm --network host wshawk:dev ws://localhost:8765  # Test scan

# Cleanup
docker builder prune -af                # Clear build cache
docker-compose down -v                  # Remove volumes
docker system prune -af --volumes       # Full cleanup

Sources: docker-compose.yml:1-36, Dockerfile:1-66, .github/workflows/docker-build.yml:1-89, docs/DOCKER.md:1-240