diff --git a/.env.example b/.env.example index 2b94dc6..8372f7a 100644 --- a/.env.example +++ b/.env.example @@ -16,7 +16,9 @@ # Get your key at: https://console.anthropic.com/settings/keys # ANTHROPIC_API_KEY=sk-ant-... # -# DeepSeek (Reasonix) container (--profile deepseek / `make deepseek`): +# DeepSeek container (--profile deepseek / `make deepseek`): +# Runs the Claude Code image pointed at DeepSeek's Anthropic-compatible API. +# The key is passed to Claude Code as ANTHROPIC_AUTH_TOKEN at runtime. # Get your key at: https://platform.deepseek.com/api_keys # DEEPSEEK_API_KEY=sk-... diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index 6d8b71d..37b69af 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -52,10 +52,6 @@ jobs: dockerfile: docker/claude-code.Dockerfile tag_prefix: "claude-code-" scout: false - - service: deepseek - dockerfile: docker/deepseek.Dockerfile - tag_prefix: "deepseek-" - scout: false - service: hexstrike-ai dockerfile: docker/hexstrike-ai.Dockerfile tag_prefix: "hexstrike-ai-" diff --git a/DOCKER.md b/DOCKER.md index 0f024a1..b39c727 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -27,7 +27,6 @@ Seven custom images are published to `crhacky/blhackbox` on Docker Hub: | **WireMCP** | `crhacky/blhackbox:wire-mcp` | `docker/wire-mcp.Dockerfile` | `debian:bookworm-slim` | | **Screenshot MCP** | `crhacky/blhackbox:screenshot-mcp` | `docker/screenshot-mcp.Dockerfile` | `python:3.13-slim` | | **Claude Code** | `crhacky/blhackbox:claude-code` | `docker/claude-code.Dockerfile` | `node:22-slim` | -| **DeepSeek (Reasonix)** | `crhacky/blhackbox:deepseek` | `docker/deepseek.Dockerfile` | `node:22-slim` | | **HexStrike API** | `crhacky/blhackbox:hexstrike-ai` | `docker/hexstrike-ai.Dockerfile` | `kalilinux/kali-rolling` | | **HexStrike MCP** | `crhacky/blhackbox:hexstrike-mcp` | `docker/hexstrike-mcp.Dockerfile` | `python:3.11-slim` | | **BOAZ MCP** | `crhacky/blhackbox:boaz-mcp` | `docker/boaz-mcp.Dockerfile` | `python:3.11-slim` | @@ -197,7 +196,7 @@ Skills are available in the container via two mechanisms: | `boaz-mcp` | `crhacky/blhackbox:boaz-mcp` | `9005` | default | BOAZ-MCP Gamma server (Streamable HTTP) | | `portainer` | `portainer/portainer-ce:latest` | `9443` | default | Docker management UI (HTTPS) | | `claude-code` | `crhacky/blhackbox:claude-code` | — | `claude-code` | Claude Code CLI client (Docker) | -| `deepseek` | `crhacky/blhackbox:deepseek` | — | `deepseek` | DeepSeek (Reasonix) terminal agent (Docker) | +| `deepseek` | `crhacky/blhackbox:claude-code` | — | `deepseek` | DeepSeek agent — Claude Code image + DeepSeek API (Docker) | | `mcp-gateway` | `docker/mcp-gateway:latest` | `8080` | `gateway` | Single MCP entry point (host clients) | | `neo4j` | `neo4j:5` | `7474` / `7687` | `neo4j` | Cross-session knowledge graph | @@ -245,7 +244,7 @@ Requires `--profile gateway` (`make up-gateway`). | Variable | Default | Description | |:--|:--|:--| | `ANTHROPIC_API_KEY` | — | Required for the Claude Code container (`--profile claude-code`) | -| `DEEPSEEK_API_KEY` | — | Required for the DeepSeek/Reasonix container (`--profile deepseek`) | +| `DEEPSEEK_API_KEY` | — | Required for the DeepSeek container (`--profile deepseek`); passed to Claude Code as `ANTHROPIC_AUTH_TOKEN` | | `MCP_GATEWAY_PORT` | `8080` | MCP Gateway host port (optional) | | `MSF_TIMEOUT` | `300` | Metasploit command timeout in seconds | | `NEO4J_URI` | `bolt://neo4j:7687` | Neo4j connection URI (optional) | @@ -308,18 +307,19 @@ Requires `--profile gateway` (`make up-gateway`). The Claude Code container includes the full skills system. Skills (`.claude/skills/`) and project instructions (`CLAUDE.md`) are baked into the image at build time and overridden by volume mounts at runtime for live updates. -### DeepSeek / Reasonix — `crhacky/blhackbox:deepseek` +### DeepSeek — `deepseek` profile (reuses `crhacky/blhackbox:claude-code`) | | | |:--|:--| -| **Base** | `node:22-slim` | -| **Agent** | [Reasonix](https://github.com/esengine/DeepSeek-Reasonix) (DeepSeek-native), installed via `npm install -g reasonix` | -| **Entrypoint** | `deepseek-entrypoint.sh` (health checks + launch) | -| **MCP config** | Auto-reads the baked Claude-style `.mcp.json`; Direct Streamable HTTP to each server (no gateway dependency) | -| **Provider** | `reasonix.toml` → DeepSeek (`https://api.deepseek.com`), key from `DEEPSEEK_API_KEY` env (never written to disk) | +| **Image** | Same as Claude Code — `crhacky/blhackbox:claude-code` (no separate image) | +| **Agent** | Claude Code CLI, pointed at the DeepSeek API | +| **Entrypoint** | `claude-code-entrypoint.sh` (health checks + launch) | +| **MCP config** | Direct Streamable HTTP to each server (no gateway dependency) | +| **Provider** | `ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic` + `ANTHROPIC_AUTH_TOKEN` from `DEEPSEEK_API_KEY` env (never written to disk) | +| **Models** | `deepseek-v4-pro` (default), `deepseek-v4-flash` (Haiku tier) — per the [DeepSeek guide](https://github.com/deepseek-ai/awesome-deepseek-agent/blob/main/docs/claude_code.md) | | **Requires** | `DEEPSEEK_API_KEY` in `.env` | -Reasonix maps the `.mcp.json` `mcpServers` entries (`type: http`, `url: …/mcp`) field-for-field onto its plugins, so it reaches the same five MCP servers as the Claude Code container. Launch it with `make deepseek` or `docker compose --profile deepseek run --rm deepseek`. Note that Claude Code *skills* (slash commands) are not a Reasonix feature; the agent works from natural-language instructions and the mounted `CLAUDE.md` methodology. +The `deepseek` profile runs the **same Claude Code image** as `--profile claude-code`, only with environment variables that route the model backend to DeepSeek's Anthropic-compatible endpoint. There is no separate image to build, push, or maintain, and the full skills system (slash commands) works exactly as it does with Claude Code. Launch it with `make deepseek` or `docker compose --profile deepseek run --rm deepseek`. --- diff --git a/Makefile b/Makefile index e0ff770..9c6ccaa 100644 --- a/Makefile +++ b/Makefile @@ -119,9 +119,9 @@ claude-code: ## Build and launch Claude Code in a Docker container @echo "" $(COMPOSE) --profile claude-code run --rm claude-code -# ── DeepSeek / Reasonix (Docker) ──────────────────────────────── -deepseek: ## Build and launch the DeepSeek (Reasonix) agent in a Docker container - $(COMPOSE) --profile deepseek pull deepseek || $(COMPOSE) --profile deepseek build deepseek +# ── DeepSeek (Docker — Claude Code pointed at the DeepSeek API) ── +deepseek: ## Launch the DeepSeek agent in a Docker container (reuses the Claude Code image) + $(COMPOSE) --profile deepseek pull deepseek || $(COMPOSE) --profile claude-code build claude-code @echo "" @echo "\033[1m Pre-flight Container Status\033[0m" @echo "\033[2m ──────────────────────────────────────\033[0m" @@ -227,7 +227,6 @@ push-all: ## Build and push all custom images to Docker Hub docker build -f docker/wire-mcp.Dockerfile -t crhacky/blhackbox:wire-mcp . docker build -f docker/screenshot-mcp.Dockerfile -t crhacky/blhackbox:screenshot-mcp . docker build -f docker/claude-code.Dockerfile -t crhacky/blhackbox:claude-code . - docker build -f docker/deepseek.Dockerfile -t crhacky/blhackbox:deepseek . docker build -f docker/hexstrike-ai.Dockerfile -t crhacky/blhackbox:hexstrike-ai . docker build -f docker/hexstrike-mcp.Dockerfile -t crhacky/blhackbox:hexstrike-mcp . docker build -f docker/boaz-mcp.Dockerfile -t crhacky/blhackbox:boaz-mcp . @@ -235,7 +234,6 @@ push-all: ## Build and push all custom images to Docker Hub docker push crhacky/blhackbox:wire-mcp docker push crhacky/blhackbox:screenshot-mcp docker push crhacky/blhackbox:claude-code - docker push crhacky/blhackbox:deepseek docker push crhacky/blhackbox:hexstrike-ai docker push crhacky/blhackbox:hexstrike-mcp docker push crhacky/blhackbox:boaz-mcp diff --git a/README.md b/README.md index f177c80..e46f2a4 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ |---|---| | **Getting Started** | [How It Works](#how-it-works) · [Architecture](#architecture) · [Prerequisites](#prerequisites) · [Installation](#installation) | | **Skills** | [Skills Overview](#skills--slash-commands) · [Available Skills](#available-skills) · [How Skills Work](#how-skills-work) | -| **Tutorials** | [Claude Code (Docker)](#tutorial-1-claude-code-docker--recommended) · [DeepSeek (Reasonix)](#tutorial-1b-deepseek-reasonix-docker) · [Claude Code (Web)](#tutorial-2-claude-code-web) · [Claude Desktop](#tutorial-3-claude-desktop-host--gateway) · [ChatGPT / OpenAI](#tutorial-4-chatgpt--openai-host--gateway) | +| **Tutorials** | [Claude Code (Docker)](#tutorial-1-claude-code-docker--recommended) · [DeepSeek (Docker)](#tutorial-1b-deepseek-docker) · [Claude Code (Web)](#tutorial-2-claude-code-web) · [Claude Desktop](#tutorial-3-claude-desktop-host--gateway) · [ChatGPT / OpenAI](#tutorial-4-chatgpt--openai-host--gateway) | | **Advanced** | [Advanced Usage & FAQ](#advanced-usage--faq) | | **Reference** | [Components](#components) · [Output Files](#output-files) · [CLI Reference](#cli-reference) · [Makefile Shortcuts](#makefile-shortcuts) · [Docker Hub Images](#docker-hub-images) | | **Operations** | [Prompt Flow](#how-prompts-flow-through-the-system) · [MCP Gateway](#do-i-need-the-mcp-gateway) · [Portainer Setup](#portainer-setup) · [Neo4j](#neo4j-optional) · [Troubleshooting](#troubleshooting) | @@ -424,7 +424,7 @@ The entrypoint script checks each service and shows a status dashboard with avai You are now inside an interactive Claude Code session. -> **Prefer DeepSeek?** A drop-in alternative agent is available. Set `DEEPSEEK_API_KEY` in `.env` and run `make deepseek` (or `docker compose --profile deepseek run --rm deepseek`). It launches [Reasonix](https://github.com/esengine/DeepSeek-Reasonix), a DeepSeek-native terminal agent, wired to the same five MCP servers over Streamable HTTP. See [Tutorial 1b](#tutorial-1b-deepseek-reasonix-docker). +> **Prefer DeepSeek?** Set `DEEPSEEK_API_KEY` in `.env` and run `make deepseek` (or `docker compose --profile deepseek run --rm deepseek`). This runs the **same Claude Code image** pointed at DeepSeek's Anthropic-compatible API — same MCP wiring, same skills, only the model backend differs. See [Tutorial 1b](#tutorial-1b-deepseek-docker). ### Step 3 — Verify the connection @@ -470,13 +470,13 @@ Or use **Portainer** at `https://localhost:9443` for a unified dashboard. --- -## Tutorial 1b: DeepSeek (Reasonix, Docker) +## Tutorial 1b: DeepSeek (Docker) -Prefer a DeepSeek-powered agent over Claude? [Reasonix](https://github.com/esengine/DeepSeek-Reasonix) is a DeepSeek-native terminal coding agent that connects to the **same five MCP servers** over Streamable HTTP — it reads a Claude-style `.mcp.json`, so the wiring is identical to the Claude Code container. It is added as a separate `deepseek` profile and does **not** replace Claude Code. +Prefer a DeepSeek-powered agent over Claude? The `deepseek` profile runs the **same Claude Code image** as Tutorial 1, just pointed at DeepSeek's Anthropic-compatible API via `ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` (following the [official DeepSeek guide](https://github.com/deepseek-ai/awesome-deepseek-agent/blob/main/docs/claude_code.md)). The MCP wiring, the skills system, and the entrypoint are identical — only the model backend changes. There is no separate image to build or maintain. ### Step 1 — Set your DeepSeek key -Put `DEEPSEEK_API_KEY` in `.env` (get one at [platform.deepseek.com/api_keys](https://platform.deepseek.com/api_keys)). `setup.sh` prompts for it, or add it manually. The key is read from the environment at runtime and never written into the image. +Put `DEEPSEEK_API_KEY` in `.env` (get one at [platform.deepseek.com/api_keys](https://platform.deepseek.com/api_keys)). `setup.sh` prompts for it, or add it manually. The key is read from the environment at runtime, passed to Claude Code as `ANTHROPIC_AUTH_TOKEN`, and never written into the image. ### Step 2 — Launch the agent @@ -490,9 +490,9 @@ Or manually: docker compose --profile deepseek run --rm deepseek ``` -The entrypoint checks each MCP server, then drops you into an interactive Reasonix session with all the pentest tools available. The default model is **DeepSeek-V4-Flash**; type `/pro` for a single Pro turn or `/preset max` to use Pro for the whole session. +The entrypoint checks each MCP server, then drops you into an interactive session with all the pentest tools available. The default model is **deepseek-v4-pro** (background tasks use **deepseek-v4-flash**); switch the active model in-session with `/model`. -> **Note:** Slash-command *skills* (`/full-pentest`, `/quick-scan`, …) are a Claude Code feature. With Reasonix, describe your authorized target and goal in natural language and the agent calls the MCP tools directly; the methodology in `CLAUDE.md` is mounted at `/root/CLAUDE.md` for reference. +> **Note:** Because this is Claude Code under the hood, the full skills system works — `/full-pentest`, `/quick-scan`, and the rest of the slash commands behave exactly as in Tutorial 1. --- @@ -761,7 +761,7 @@ STEP 7 ─ (OPTIONAL) RESULTS STORED IN NEO4J | MCP Client | Gateway? | How it connects | |:--|:--:|:--| | **Claude Code (Docker)** | No | Direct Streamable HTTP to each MCP server over Docker network | -| **DeepSeek / Reasonix (Docker)** | No | Direct Streamable HTTP to each MCP server over Docker network | +| **DeepSeek (Docker)** | No | Claude Code image + DeepSeek API; direct Streamable HTTP to each MCP server over Docker network | | **Claude Code (Web)** | No | Stdio MCP server from `.mcp.json` | | **Claude Desktop** | **Yes** | Host GUI app → `localhost:8080/mcp` gateway | | **ChatGPT / OpenAI** | **Yes** | Host GUI/web app → `localhost:8080/mcp` gateway | @@ -882,7 +882,7 @@ blhackbox mcp # Start MCP server | `make up-gateway` | Start with MCP Gateway for Claude Desktop (8 containers) | | `make down` | Stop all services | | `make claude-code` | Build and launch Claude Code in Docker | -| `make deepseek` | Build and launch the DeepSeek (Reasonix) agent in Docker | +| `make deepseek` | Launch the DeepSeek agent in Docker (Claude Code image + DeepSeek API) | | `make status` | Container status table | | `make health` | Quick health check of all services | | `make test` | Run tests | @@ -920,8 +920,7 @@ All custom images are published to `crhacky/blhackbox`: | `crhacky/blhackbox:hexstrike-ai` | HexStrike Gamma API container | | `crhacky/blhackbox:hexstrike-mcp` | Upstream HexStrike Gamma MCP server over Streamable HTTP | | `crhacky/blhackbox:boaz-mcp` | Upstream BOAZ-MCP Gamma server over Streamable HTTP | -| `crhacky/blhackbox:claude-code` | Claude Code CLI client (direct Streamable HTTP to MCP servers) | -| `crhacky/blhackbox:deepseek` | DeepSeek (Reasonix) terminal agent (direct Streamable HTTP to MCP servers) | +| `crhacky/blhackbox:claude-code` | Claude Code CLI client (direct Streamable HTTP to MCP servers); also used by the `deepseek` profile pointed at the DeepSeek API | Official images pulled directly: @@ -986,10 +985,8 @@ blhackbox/ │ ├── kali-mcp.Dockerfile Kali Linux + Metasploit Framework │ ├── wire-mcp.Dockerfile │ ├── screenshot-mcp.Dockerfile -│ ├── claude-code.Dockerfile MCP client container -│ ├── claude-code-entrypoint.sh Startup script with health checks -│ ├── deepseek.Dockerfile DeepSeek (Reasonix) MCP client container -│ └── deepseek-entrypoint.sh DeepSeek startup script with health checks +│ ├── claude-code.Dockerfile MCP client container (also used by the deepseek profile) +│ └── claude-code-entrypoint.sh Startup script with health checks ├── kali-mcp/ Kali MCP server (70+ tools + Metasploit) ├── wire-mcp/ WireMCP server (tshark, 7 tools) ├── screenshot-mcp/ Screenshot MCP server (Playwright, 4 tools) diff --git a/docker-compose.yml b/docker-compose.yml index 762e9cf..aea8e9a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ # docker compose up -d Start default stack (Kali, WireMCP, Screenshot, HexStrike, BOAZ, Portainer) # docker compose --profile gateway up -d Start with MCP Gateway # docker compose --profile claude-code up -d Start with Claude Code container -# docker compose --profile deepseek run --rm deepseek Run the DeepSeek (Reasonix) agent +# docker compose --profile deepseek run --rm deepseek Run the DeepSeek agent (Claude Code + DeepSeek API) # docker compose --profile neo4j up -d Start with Neo4j # docker compose build Build all custom images locally # @@ -372,26 +372,37 @@ services: networks: - blhackbox_net - # -- DEEPSEEK / REASONIX (OPTIONAL) ---------------------------------------- - # DeepSeek-native MCP client running inside Docker -- no host install needed. + # -- DEEPSEEK (OPTIONAL) --------------------------------------------------- + # DeepSeek-powered agent running inside Docker -- no host install needed. # Enable with: docker compose --profile deepseek run --rm deepseek # (or `make deepseek`) # - # Reasonix (https://github.com/esengine/DeepSeek-Reasonix) connects DIRECTLY - # to each MCP server via Streamable HTTP over the Docker network by reading - # its baked .mcp.json (Claude Code's mcpServers schema). Does NOT require the - # MCP Gateway. Requires DEEPSEEK_API_KEY (read from env, never written to disk). + # Reuses the Claude Code image and points it at DeepSeek's Anthropic-compatible + # API via ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN, following the official + # DeepSeek guide: + # https://github.com/deepseek-ai/awesome-deepseek-agent/blob/main/docs/claude_code.md + # Same MCP wiring, skills, and entrypoint as the claude-code service — only the + # model backend differs, so there is no separate image to build or maintain. + # Requires DEEPSEEK_API_KEY (read from env, never written to disk). deepseek: - image: crhacky/blhackbox:deepseek - build: - context: . - dockerfile: docker/deepseek.Dockerfile + image: crhacky/blhackbox:claude-code container_name: blhackbox-deepseek profiles: ["deepseek"] stdin_open: true tty: true environment: - DEEPSEEK_API_KEY: "${DEEPSEEK_API_KEY:-}" + # Route Claude Code at DeepSeek's Anthropic-compatible endpoint. + # ANTHROPIC_AUTH_TOKEN is sent as the Authorization: Bearer header. + ANTHROPIC_BASE_URL: "https://api.deepseek.com/anthropic" + ANTHROPIC_AUTH_TOKEN: "${DEEPSEEK_API_KEY:-}" + # Map Claude's model tiers onto DeepSeek models (per the DeepSeek guide). + # Switch the active model in-session with /model. + ANTHROPIC_MODEL: "deepseek-v4-pro" + ANTHROPIC_DEFAULT_OPUS_MODEL: "deepseek-v4-pro" + ANTHROPIC_DEFAULT_SONNET_MODEL: "deepseek-v4-pro" + ANTHROPIC_DEFAULT_HAIKU_MODEL: "deepseek-v4-flash" + # Don't phone home to Anthropic for telemetry/auto-update. + CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1" # Bypass egress proxies (e.g. GitHub Codespaces) for internal Docker traffic no_proxy: "mcp-gateway,kali-mcp,wire-mcp,screenshot-mcp,hexstrike-ai,hexstrike-bridge-mcp,boaz-mcp,localhost,127.0.0.1" NO_PROXY: "mcp-gateway,kali-mcp,wire-mcp,screenshot-mcp,hexstrike-ai,hexstrike-bridge-mcp,boaz-mcp,localhost,127.0.0.1" @@ -404,7 +415,8 @@ services: - ./output/sessions:/root/results # Shared working data from Kali MCP (recon files, tool artifacts) - shared-output:/root/kali-data:ro - # Mount project instructions so the agent has the latest methodology + # Mount skills and project instructions so Claude Code discovers them + - ./.claude/skills:/root/.claude/skills:ro - ./CLAUDE.md:/root/CLAUDE.md:ro depends_on: kali-mcp: diff --git a/docker/deepseek-entrypoint.sh b/docker/deepseek-entrypoint.sh deleted file mode 100755 index f3d0cc7..0000000 --- a/docker/deepseek-entrypoint.sh +++ /dev/null @@ -1,172 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# ── Colors ────────────────────────────────────────────────────────── -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -BOLD='\033[1m' -DIM='\033[2m' -NC='\033[0m' # No Color - -# ── Symbols ───────────────────────────────────────────────────────── -CHECK="${GREEN}OK${NC}" -CROSS="${RED}FAIL${NC}" -WARN="${YELLOW}WARN${NC}" -WAIT="${DIM}....${NC}" - -# ── Configuration ─────────────────────────────────────────────────── -MAX_RETRIES=20 -RETRY_INTERVAL=3 - -# Ensure internal Docker hostnames bypass any egress proxy. -export no_proxy="${no_proxy:+${no_proxy},}mcp-gateway,kali-mcp,wire-mcp,screenshot-mcp,hexstrike-ai,hexstrike-bridge-mcp,boaz-mcp,localhost,127.0.0.1" -export NO_PROXY="$no_proxy" - -# ── Functions ─────────────────────────────────────────────────────── - -print_banner() { - echo "" - echo -e "${CYAN}${BOLD} ╔══════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}${BOLD} ║ blhackbox v2.0 — DeepSeek (Reasonix) ║${NC}" - echo -e "${CYAN}${BOLD} ║ MCP-based Pentesting Framework ║${NC}" - echo -e "${CYAN}${BOLD} ╚══════════════════════════════════════════════╝${NC}" - echo "" -} - -# Check a single service. Returns 0 on success, 1 on failure. -check_service() { - local name="$1" - local url="$2" - local timeout="${3:-3}" - curl -s --max-time "$timeout" -o /dev/null "$url" 2>/dev/null - local rc=$? - # A bare GET to the Streamable HTTP endpoint (/mcp) returns an HTTP 4xx - # (no MCP session/headers) — curl still exits 0 because it received a - # response, which confirms the server is up. Exit code 28 (transfer - # timed out) is also treated as success for any endpoint that streams. - [ "$rc" -eq 0 ] || [ "$rc" -eq 28 ] -} - -# Wait for a service with retries. Prints status. -wait_for_service() { - local name="$1" - local url="$2" - local retries="${3:-$MAX_RETRIES}" - - printf " %-22s " "$name" - - for i in $(seq 1 "$retries"); do - if check_service "$name" "$url"; then - echo -e "[ ${CHECK} ]" - return 0 - fi - sleep "$RETRY_INTERVAL" - done - - echo -e "[ ${CROSS} ] (unreachable at $url)" - return 1 -} - -# ── Output directory symlinks ────────────────────────────────────── -# Report/session paths resolve to /root/output/* (WORKDIR is /root). -# Bind mounts are at /root/reports, /root/results, /tmp/screenshots. -# Create symlinks so both path conventions reach the bind mounts. -mkdir -p /root/output -ln -sfn /root/reports /root/output/reports -ln -sfn /root/results /root/output/sessions -ln -sfn /tmp/screenshots /root/output/screenshots - -# ── Main ──────────────────────────────────────────────────────────── - -print_banner - -# DeepSeek API key is required for Reasonix to authenticate against the -# DeepSeek API. It is read from the environment (reasonix.toml api_key_env). -if [ -z "${DEEPSEEK_API_KEY:-}" ]; then - echo -e " ${WARN} DEEPSEEK_API_KEY is not set — Reasonix cannot authenticate." - echo -e " ${DIM}Add it to .env and re-run, or pass -e DEEPSEEK_API_KEY=sk-...${NC}" - echo -e " ${DIM}Get a key at https://platform.deepseek.com/api_keys${NC}" - echo "" -fi - -echo -e "${BOLD}Checking service connectivity...${NC}" -echo -e "${DIM}Waiting for services to become healthy.${NC}" -echo "" - -MCP_OK=0 -MCP_FAIL=0 - -# -- MCP Servers (Reasonix connects via Streamable HTTP) -- -echo -e " ${BOLD}MCP Servers${NC}" -if wait_for_service "Kali MCP" "http://kali-mcp:9001/mcp"; then - MCP_OK=$((MCP_OK + 1)) -else - MCP_FAIL=$((MCP_FAIL + 1)) -fi - -# WireMCP shares kali-mcp's network namespace, so use kali-mcp hostname -if wait_for_service "WireMCP" "http://kali-mcp:9003/mcp"; then - MCP_OK=$((MCP_OK + 1)) -else - MCP_FAIL=$((MCP_FAIL + 1)) -fi - -if wait_for_service "Screenshot MCP" "http://screenshot-mcp:9004/mcp"; then - MCP_OK=$((MCP_OK + 1)) -else - MCP_FAIL=$((MCP_FAIL + 1)) -fi - -if wait_for_service "BOAZ MCP" "http://boaz-mcp:9005/mcp"; then - MCP_OK=$((MCP_OK + 1)) -else - MCP_FAIL=$((MCP_FAIL + 1)) -fi - -if wait_for_service "HexStrike MCP" "http://hexstrike-bridge-mcp:9006/mcp"; then - MCP_OK=$((MCP_OK + 1)) -else - MCP_FAIL=$((MCP_FAIL + 1)) -fi - -# Summary -echo "" -echo -e "${DIM}──────────────────────────────────────────────────${NC}" - -if [ "$MCP_FAIL" -eq 0 ]; then - echo -e "${GREEN}${BOLD} All $MCP_OK MCP servers connected.${NC}" -else - echo -e "${YELLOW}${BOLD} $MCP_OK/$((MCP_OK + MCP_FAIL)) MCP servers connected. $MCP_FAIL unreachable.${NC}" - echo -e "${DIM} Reasonix will start — unreachable servers simply won't expose tools.${NC}" - echo -e "${DIM} Use 'docker compose ps' in another terminal to check container health.${NC}" -fi - -echo "" -echo -e "${DIM}──────────────────────────────────────────────────${NC}" -echo -e " ${BOLD}MCP servers (connected via Streamable HTTP):${NC}" -echo -e " kali ${DIM}Kali Linux security tools + Metasploit (70+ tools)${NC}" -echo -e " wireshark ${DIM}WireMCP — tshark packet capture & analysis${NC}" -echo -e " screenshot ${DIM}Screenshot MCP — headless Chromium evidence capture${NC}" -echo -e " boaz ${DIM}BOAZ-MCP Gamma — agentic offensive security tools${NC}" -echo -e " hexstrike ${DIM}HexStrike Gamma — AI security automation tools${NC}" -echo "" -echo -e " ${BOLD}Model:${NC} ${DIM}DeepSeek-V4-Flash (default). Type ${NC}${CYAN}/pro${NC}${DIM} for one Pro turn,${NC}" -echo -e " ${DIM}or ${NC}${CYAN}/preset max${NC}${DIM} to use Pro for the whole session.${NC}" -echo "" -echo -e " ${BOLD}Methodology:${NC} ${DIM}Pentest workflow and rules are in ${NC}${CYAN}/root/CLAUDE.md${NC}${DIM}.${NC}" -echo -e " ${DIM}Describe your authorized target and goal; Reasonix will call the MCP tools.${NC}" -echo "" -echo -e " ${BOLD}Output files${NC} ${DIM}(mounted to host ./output/)${NC}${BOLD}:${NC}" -echo -e " ${DIM}output/reports/ → ./output/reports/ pentest reports${NC}" -echo -e " ${DIM}output/screenshots/ → ./output/screenshots/ PoC evidence (read-only)${NC}" -echo -e " ${DIM}output/sessions/ → ./output/sessions/ session data${NC}" -echo -e " ${DIM}/root/kali-data/ ← shared Kali MCP recon artifacts (read-only)${NC}" -echo -e "${DIM}──────────────────────────────────────────────────${NC}" -echo "" - -# Launch the Reasonix coding agent. `reasonix code` opens the interactive TUI; -# any args passed to the container are forwarded. -exec reasonix code "$@" diff --git a/docker/deepseek.Dockerfile b/docker/deepseek.Dockerfile deleted file mode 100644 index be74b7e..0000000 --- a/docker/deepseek.Dockerfile +++ /dev/null @@ -1,64 +0,0 @@ -# DeepSeek (Reasonix) MCP Client — runs inside the blhackbox Docker network. -# Usage: -# docker compose --profile deepseek run --rm deepseek -# -# Reasonix is a DeepSeek-native terminal coding agent (https://github.com/ -# esengine/DeepSeek-Reasonix). It connects DIRECTLY to each MCP server via -# Streamable HTTP on the internal blhackbox_net network by reading the baked -# .mcp.json (Claude Code's exact mcpServers schema). No MCP Gateway required, -# no host-side install. - -FROM node:22-slim - -# Reasonix ships a single Go binary delivered through npm. -RUN npm install -g reasonix - -# curl for health checks, python3/jq for data processing, -# and dnsutils for DNS resolution debugging -RUN apt-get update && apt-get install -y --no-install-recommends \ - curl \ - jq \ - python3 \ - dnsutils \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /root - -# DeepSeek provider config. The API key is read from the DEEPSEEK_API_KEY -# environment variable at runtime (api_key_env) and is never written to disk. -# Default model is the cost-efficient DeepSeek-V4-Flash; switch to Pro at -# runtime with /pro (next turn) or /preset max (whole session). -RUN printf '%s\n' \ - 'default_model = "deepseek-flash"' \ - '' \ - '[[providers]]' \ - 'name = "deepseek-flash"' \ - 'kind = "openai"' \ - 'base_url = "https://api.deepseek.com"' \ - 'model = "deepseek-v4-flash"' \ - 'api_key_env = "DEEPSEEK_API_KEY"' \ - > reasonix.toml - -# Reasonix auto-reads a Claude-Code .mcp.json from the project root and maps it -# field-for-field onto its plugins (type/url/headers, ${VAR} expansion). This is -# the same wiring the claude-code container uses. Wire-MCP shares kali-mcp's -# network namespace, so it's accessed via the kali-mcp hostname on port 9003. -RUN echo '{ \ - "mcpServers": { \ - "kali": { "type": "http", "url": "http://kali-mcp:9001/mcp" }, \ - "wireshark": { "type": "http", "url": "http://kali-mcp:9003/mcp" }, \ - "screenshot": { "type": "http", "url": "http://screenshot-mcp:9004/mcp" }, \ - "boaz": { "type": "http", "url": "http://boaz-mcp:9005/mcp" }, \ - "hexstrike": { "type": "http", "url": "http://hexstrike-bridge-mcp:9006/mcp" } \ - } \ -}' > .mcp.json - -# Project methodology, available on the filesystem for reference. A volume mount -# in docker-compose.yml overrides this at runtime with the latest version. -COPY CLAUDE.md /root/CLAUDE.md - -# Startup script: checks each MCP server, shows status, launches Reasonix. -COPY docker/deepseek-entrypoint.sh /usr/local/bin/deepseek-entrypoint.sh -RUN chmod +x /usr/local/bin/deepseek-entrypoint.sh - -ENTRYPOINT ["/usr/local/bin/deepseek-entrypoint.sh"] diff --git a/setup.sh b/setup.sh index 3de6d3a..1b6c732 100755 --- a/setup.sh +++ b/setup.sh @@ -167,7 +167,7 @@ usage() { echo "" echo "Options:" echo " --api-key KEY Set ANTHROPIC_API_KEY (Claude Code container)" - echo " --deepseek-key KEY Set DEEPSEEK_API_KEY (DeepSeek/Reasonix container)" + echo " --deepseek-key KEY Set DEEPSEEK_API_KEY (DeepSeek container)" echo " --minimal Core stack only (no prompts, no Neo4j/Gateway)" echo " --with-neo4j Enable local Neo4j knowledge graph (Docker)" echo " --with-gateway Enable MCP Gateway for Claude Desktop/ChatGPT" @@ -297,7 +297,7 @@ print_anthropic_help() { } print_deepseek_help() { - echo -e " ${BOLD}What it's for:${NC} authenticates the DeepSeek (Reasonix) agent in Docker." + echo -e " ${BOLD}What it's for:${NC} authenticates the DeepSeek agent (Claude Code + DeepSeek API) in Docker." echo -e " ${BOLD}Where it's used:${NC} the ${CYAN}deepseek${NC} container (DEEPSEEK_API_KEY)." echo -e " ${BOLD}How to get it:${NC}" echo -e " ${DIM}1.${NC} Sign in at ${CYAN}https://platform.deepseek.com${NC}" @@ -399,7 +399,7 @@ choose_ai_client() { ;; 3) # DeepSeek AI_VARIANT="deepseek"; AGENT_PROFILE="deepseek" - echo -e " ${ARROW} DeepSeek (Reasonix) runs containerized in Docker." + echo -e " ${ARROW} DeepSeek runs containerized in Docker (Claude Code + DeepSeek API)." configure_agent_key "DEEPSEEK_API_KEY" print_deepseek_help ;; esac @@ -714,7 +714,7 @@ print_launch_hint() { fi ;; deepseek) echo -e " ${BOLD}Launch your agent:${NC}" - echo -e " ${CYAN}make deepseek${NC} ${DIM}Start the DeepSeek (Reasonix) agent${NC}" + echo -e " ${CYAN}make deepseek${NC} ${DIM}Start the DeepSeek agent${NC}" if ! env_has_value DEEPSEEK_API_KEY; then echo -e " ${WARN} ${YELLOW}DEEPSEEK_API_KEY is not set${NC} — the deepseek container won't" echo -e " start until you add it to ${CYAN}.env${NC} (then re-run ${CYAN}make deepseek${NC})." @@ -782,7 +782,7 @@ ai_label() { claude-web) echo "Claude Code (Web — claude.ai/code)" ;; claude-desktop) echo "Claude Desktop (host app via MCP Gateway)" ;; chatgpt) echo "ChatGPT / OpenAI (host app via MCP Gateway)" ;; - deepseek) echo "DeepSeek / Reasonix (Docker container)" ;; + deepseek) echo "DeepSeek (Docker — Claude Code + DeepSeek API)" ;; *) echo "None selected (core stack only)" ;; esac } diff --git a/tests/test_compose_integrations.py b/tests/test_compose_integrations.py index ce0aea0..996168b 100644 --- a/tests/test_compose_integrations.py +++ b/tests/test_compose_integrations.py @@ -85,32 +85,21 @@ def test_claude_code_container_wires_all_default_mcp_servers() -> None: assert "hexstrike-bridge-mcp" in entrypoint -def test_deepseek_container_wires_all_default_mcp_servers() -> None: - dockerfile = (ROOT / "docker" / "deepseek.Dockerfile").read_text(encoding="utf-8") - entrypoint = (ROOT / "docker" / "deepseek-entrypoint.sh").read_text(encoding="utf-8") - - for expected in [ - "http://kali-mcp:9001/mcp", - "http://kali-mcp:9003/mcp", - "http://screenshot-mcp:9004/mcp", - "http://boaz-mcp:9005/mcp", - "http://hexstrike-bridge-mcp:9006/mcp", - ]: - assert expected in dockerfile - assert expected in entrypoint - - # Reasonix install + DeepSeek provider that reads the key from the env. - assert "npm install -g reasonix" in dockerfile - assert "reasonix.toml" in dockerfile - assert 'api_key_env = "DEEPSEEK_API_KEY"' in dockerfile - # Launches the Reasonix coding agent. - assert "reasonix code" in entrypoint +def test_deepseek_reuses_claude_code_image_without_separate_build() -> None: + # The DeepSeek profile is now just the Claude Code image pointed at the + # DeepSeek API — no separate Reasonix Dockerfile/entrypoint to maintain. + assert not (ROOT / "docker" / "deepseek.Dockerfile").exists() + assert not (ROOT / "docker" / "deepseek-entrypoint.sh").exists() def test_deepseek_service_is_in_compose_under_profile() -> None: compose = COMPOSE.read_text(encoding="utf-8") assert "deepseek:" in compose - assert "image: crhacky/blhackbox:deepseek" in compose + # Reuses the Claude Code image rather than building a dedicated one. + assert "image: crhacky/blhackbox:claude-code" in compose + assert "crhacky/blhackbox:deepseek" not in compose + assert "docker/deepseek.Dockerfile" not in compose assert 'profiles: ["deepseek"]' in compose - assert "docker/deepseek.Dockerfile" in compose - assert "DEEPSEEK_API_KEY" in compose + # Routes Claude Code at DeepSeek's Anthropic-compatible endpoint. + assert "https://api.deepseek.com/anthropic" in compose + assert 'ANTHROPIC_AUTH_TOKEN: "${DEEPSEEK_API_KEY:-}"' in compose