services: # LiteLLM Proxy — LLM API Gateway # Handles model routing, authentication, usage tracking, billing litellm: image: ghcr.io/berriai/litellm:main-v1.82.3-stable.patch.2 container_name: decepticon-litellm volumes: - ./config/litellm.yaml:/app/config.yaml:ro command: ["--config", "/app/config.yaml", "--port", "4000"] ports: - "127.0.0.1:${LITELLM_PORT:-4000}:4000" env_file: .env environment: - LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY:-sk-decepticon-master} - LITELLM_SALT_KEY=${LITELLM_SALT_KEY:-sk-decepticon-salt} - DATABASE_URL=postgresql://decepticon:decepticon@postgres:5432/litellm depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:4000/health/readiness')"] interval: 5s timeout: 3s retries: 20 start_period: 10s networks: - decepticon-net restart: unless-stopped # PostgreSQL — Persistent storage for LiteLLM # Stores: virtual keys, spend logs, user budgets, rate limits postgres: image: postgres:17-alpine container_name: decepticon-postgres environment: POSTGRES_DB: litellm POSTGRES_USER: decepticon POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-decepticon} volumes: - postgres_data:/var/lib/postgresql/data # Auto-create decepticon_web DB on first startup (empty volume only). # Existing deployments: run the SQL manually or `docker volume rm postgres_data`. - ./containers/postgres-init:/docker-entrypoint-initdb.d:ro ports: - "127.0.0.1:${POSTGRES_PORT:-5432}:5432" networks: - decepticon-net restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U decepticon -d litellm"] interval: 10s timeout: 5s retries: 5 start_period: 10s # Neo4j — Attack Chain Graph (the agent's persistent working memory) # On sandbox-net so cypher-shell from inside sandbox reaches bolt://neo4j:7687 neo4j: image: neo4j:5.24-community container_name: decepticon-neo4j environment: NEO4J_AUTH: neo4j/${NEO4J_PASSWORD:-decepticon-graph} NEO4J_server_memory_heap_initial__size: 128m NEO4J_server_memory_heap_max__size: 384m NEO4J_server_memory_pagecache_size: 128m NEO4J_PLUGINS: '["apoc"]' NEO4J_dbms_security_procedures_unrestricted: apoc.* NEO4J_apoc_export_file_enabled: "true" NEO4J_apoc_import_file_enabled: "true" volumes: - neo4j_data:/data - neo4j_logs:/logs ports: - "127.0.0.1:7474:7474" - "127.0.0.1:7687:7687" networks: - sandbox-net - decepticon-net healthcheck: test: ["CMD-SHELL", "wget -q --spider http://localhost:7474 || exit 1"] interval: 15s timeout: 5s retries: 10 start_period: 30s restart: unless-stopped # Evasive Red Team Sandbox # Isolated container for executing red-team tools (nmap, whois, etc.) # Runs on sandbox-net only — NO access to infra (litellm, postgres, langgraph). # LangGraph reaches sandbox via docker exec (Docker socket), not the network. sandbox: image: ghcr.io/purpleailab/decepticon-sandbox:${DECEPTICON_VERSION:-latest} build: context: . dockerfile: containers/sandbox.Dockerfile container_name: decepticon-sandbox networks: - sandbox-net cap_add: - NET_RAW - NET_ADMIN - NET_BIND_SERVICE environment: - NEO4J_URI=bolt://neo4j:7687 - NEO4J_USER=neo4j - NEO4J_PASSWORD=${NEO4J_PASSWORD:-decepticon-graph} volumes: - ${DECEPTICON_HOME:-~/.decepticon}/workspace:/workspace mem_limit: 4g cpus: 2.0 pids_limit: 1024 depends_on: neo4j: condition: service_started restart: unless-stopped # LangGraph Platform — Agent API Server # Exposes all agents (decepticon, soundwave, recon, exploit, postexploit) # as a streaming API on port 2024. Ink CLI connects here. langgraph: image: ghcr.io/purpleailab/decepticon-langgraph:${DECEPTICON_VERSION:-latest} build: context: . dockerfile: containers/langgraph.Dockerfile container_name: decepticon-langgraph ports: - "${LANGGRAPH_PORT:-2024}:2024" env_file: .env environment: - DECEPTICON_LLM__PROXY_URL=http://litellm:4000 - DECEPTICON_LLM__PROXY_API_KEY=${LITELLM_MASTER_KEY:-sk-decepticon-master} - DECEPTICON_DOCKER__SANDBOX_CONTAINER_NAME=decepticon-sandbox - DECEPTICON_NEO4J_URI=bolt://neo4j:7687 - DECEPTICON_NEO4J_USER=neo4j - DECEPTICON_NEO4J_PASSWORD=${NEO4J_PASSWORD:-decepticon-graph} # Neo4j is the sole KG backend (no DECEPTICON_KG_BACKEND needed) volumes: - /var/run/docker.sock:/var/run/docker.sock:ro # Relaxed startup: langgraph has built-in retry for litellm/neo4j connections, # so we don't block on healthchecks — cuts cold start by ~30-40s. depends_on: litellm: condition: service_started sandbox: condition: service_started neo4j: condition: service_started networks: - decepticon-net restart: unless-stopped # Dev hot-reload: activate with `docker compose watch` (ignored by `docker compose up`) develop: watch: - action: sync path: ./decepticon target: /app/decepticon - action: sync path: ./skills target: /app/skills - action: sync path: ./langgraph.json target: /app/langgraph.json - action: rebuild path: ./pyproject.toml - action: rebuild path: ./containers/langgraph.Dockerfile # Web Dashboard — Next.js UI # Included in the default stack: docker compose up -d web: image: ghcr.io/purpleailab/decepticon-web:${DECEPTICON_VERSION:-latest} build: context: . dockerfile: containers/web.Dockerfile container_name: decepticon-web ports: - "${WEB_PORT:-3000}:3000" env_file: .env environment: - NEXT_PUBLIC_DECEPTICON_EDITION=oss - LANGGRAPH_API_URL=http://langgraph:2024 - DATABASE_URL=postgresql://decepticon:decepticon@postgres:5432/decepticon_web depends_on: langgraph: condition: service_started postgres: condition: service_healthy networks: - decepticon-net restart: unless-stopped develop: watch: - action: sync path: ./clients/web/src target: /app/clients/web/src - action: sync path: ./clients/web/public target: /app/clients/web/public - action: rebuild path: ./clients/web/package.json - action: rebuild path: ./containers/web.Dockerfile # Ink CLI — Interactive terminal UI # Runs via: docker compose run --rm cli cli: image: ghcr.io/purpleailab/decepticon-cli:${DECEPTICON_VERSION:-latest} build: context: . dockerfile: containers/cli.Dockerfile container_name: decepticon-cli stdin_open: true tty: true environment: - DECEPTICON_API_URL=http://langgraph:2024 - TERM=xterm-256color - COLORTERM=truecolor depends_on: langgraph: condition: service_started networks: - decepticon-net profiles: - cli develop: watch: - action: sync path: ./clients/cli/src target: /app/src - action: rebuild path: ./clients/cli/package.json - action: rebuild path: ./containers/cli.Dockerfile # ── C2 Infrastructure (profile-based, default: c2-sliver) ─────────── # Each C2 framework runs as a profile-based service on sandbox-net. # Default: COMPOSE_PROFILES=c2-sliver in .env → starts with `docker compose up -d` # Swap: change COMPOSE_PROFILES to c2-havoc, etc. # Agent connects via: sliver-client (pre-installed in sandbox) c2-sliver: image: ghcr.io/purpleailab/decepticon-c2-sliver:${DECEPTICON_VERSION:-latest} build: context: . dockerfile: containers/c2-sliver.Dockerfile container_name: decepticon-c2-sliver networks: - sandbox-net cap_add: - NET_BIND_SERVICE volumes: - sliver_data:/home/sliver/.sliver mem_limit: 2g cpus: 1.0 pids_limit: 512 restart: unless-stopped profiles: - c2-sliver # ── Victim Infrastructure (demo / testing only) ────────────────────── # DVWA — Damn Vulnerable Web Application # Web vulnerabilities: SQLi, XSS, Command Injection, File Inclusion, CSRF # Default creds: admin / password dvwa: image: vulnerables/web-dvwa container_name: decepticon-dvwa networks: - sandbox-net restart: unless-stopped profiles: - victims # Metasploitable 2 — intentionally vulnerable Linux host # Vulnerable services: vsftpd, SSH, Samba, MySQL, distccd, UnrealIRCd, Tomcat # Default creds: msfadmin / msfadmin metasploitable2: image: tleemcjr/metasploitable2 container_name: decepticon-msf2 networks: - sandbox-net tty: true restart: unless-stopped profiles: - victims volumes: postgres_data: sliver_data: neo4j_data: neo4j_logs: networks: decepticon-net: driver: bridge sandbox-net: driver: bridge