# syntax=docker/dockerfile:1 # # recon-triage — Docker-only build. Multi-stage: # go-builder : compiles pinned ProjectDiscovery Go tools (static binaries) # test : runs the fully-offline pytest suite (used by `make test`) # runtime : minimal Alpine image, non-root, with nmap + exploitdb + the app # # Alpine is used throughout (musl). All Python deps (pydantic v2 included) ship # musllinux wheels, so no Debian fallback is needed. # --------------------------------------------------------------------------- # Stage 1: build Go recon tools. Pinned for reproducibility. # --------------------------------------------------------------------------- FROM golang:1.23-alpine AS go-builder # libpcap-dev is required to compile naabu; git for go module fetches. RUN apk add --no-cache git build-base libpcap-dev ENV CGO_ENABLED=1 GOFLAGS=-buildvcs=false # Pinned tool versions (see README "Tool versions"). ARG SUBFINDER_VERSION=v2.6.6 ARG DNSX_VERSION=v1.2.1 ARG NAABU_VERSION=v2.3.1 ARG HTTPX_VERSION=v1.6.9 ARG NUCLEI_VERSION=v3.3.5 RUN go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@${SUBFINDER_VERSION} \ && go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@${DNSX_VERSION} \ && go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@${NAABU_VERSION} \ && go install -v github.com/projectdiscovery/httpx/cmd/httpx@${HTTPX_VERSION} \ && go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@${NUCLEI_VERSION} # --------------------------------------------------------------------------- # Stage 1b: fetch Exploit-DB + searchsploit at BUILD time (release-independent; # the Alpine `exploitdb` package is not in every release's stable repo). The DB # ships inside the image, so searchsploit needs NO network at runtime. # --------------------------------------------------------------------------- FROM alpine:3.20 AS exploitdb-builder ARG EXPLOITDB_REF=main RUN apk add --no-cache git \ && git clone --depth 1 --branch ${EXPLOITDB_REF} \ https://gitlab.com/exploit-database/exploitdb.git /opt/exploitdb \ && rm -rf /opt/exploitdb/.git # --------------------------------------------------------------------------- # Stage 2: offline test image. No Go tools, no network at runtime — the suite # is driven entirely by committed fixtures and an injected searchsploit stub. # --------------------------------------------------------------------------- FROM python:3.12-alpine AS test WORKDIR /app RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" COPY pyproject.toml README.md ./ COPY src ./src RUN pip install --no-cache-dir -e ".[dev]" COPY tests ./tests # Fully offline: -p no:cacheprovider keeps it hermetic. RUN python -m pytest -q -p no:cacheprovider # --------------------------------------------------------------------------- # Stage 3: runtime image. Non-root, connect-scan by default (no caps needed). # --------------------------------------------------------------------------- FROM python:3.12-alpine AS runtime # Runtime packages: # nmap service/version detection # libpcap naabu runtime dependency # bash, coreutils searchsploit is a bash script using standard text utilities # ca-certificates TLS roots for passive sources / optional LLM endpoint RUN apk add --no-cache \ nmap nmap-scripts \ libpcap \ ca-certificates \ bash coreutils # Copy compiled recon tools from the builder. COPY --from=go-builder /go/bin/subfinder /usr/local/bin/subfinder COPY --from=go-builder /go/bin/dnsx /usr/local/bin/dnsx COPY --from=go-builder /go/bin/naabu /usr/local/bin/naabu COPY --from=go-builder /go/bin/httpx /usr/local/bin/httpx COPY --from=go-builder /go/bin/nuclei /usr/local/bin/nuclei # Exploit-DB checkout (DB shipped in the image). searchsploit resolves its DB path # relative to the real script location, so a symlink onto PATH is sufficient. COPY --from=exploitdb-builder /opt/exploitdb /opt/exploitdb RUN ln -sf /opt/exploitdb/searchsploit /usr/local/bin/searchsploit \ && searchsploit --json apache >/dev/null 2>&1 || true # Install the app into an isolated venv. RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" WORKDIR /app COPY pyproject.toml README.md ./ COPY src ./src RUN pip install --no-cache-dir . # Export the JSON Schema into the image for inspection. COPY tests/fixtures ./tests/fixtures RUN python -m recon_triage.schema /app/schemas # Non-root user. Connect scans need no elevated capabilities. RUN addgroup -S app && adduser -S -G app -h /home/app app \ && mkdir -p /data/out /home/app/nuclei-templates \ && chown -R app:app /data /home/app /app/schemas USER app # nuclei templates cache to a mountable volume (not baked into the image). ENV NUCLEI_TEMPLATES_DIR=/home/app/nuclei-templates ENV HOME=/home/app ENTRYPOINT ["recon-triage"] CMD ["--help"]