diff --git a/Dockerfile b/Dockerfile index df949f7..d32ce8f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,51 +43,101 @@ RUN ARTEX_SKIP_FRONTEND=1 \ ARTEX_BUILD_VERSION="${ARTEX_VERSION}" \ bash ./build.sh --target "${TARGETOS:-linux}/${TARGETARCH:-amd64}" -# ---------------------------------------------------------------- runtime --- -FROM python:3.12-slim-bookworm +# ------------------------------------------------------- third-party tools --- +# Web-recon toolbox (drost-community take 1, #100): pinned release binaries, staged +# on the build platform and copied into /usr/local/bin of the runtime image so hunt +# workers can run them directly through their Bash tool. Versions pinned per tool; +# upgrade deliberately. Each archive is verified against the checksums file of its +# own GitHub release (exact asset name, sha256). That file comes from the same +# release channel as the archive, so it catches corrupted or swapped downloads and +# moved tags, not a compromised publisher. sqlmap has no release binaries: it is a +# shallow clone of a pinned tag, checked against the expected commit. +FROM --platform=$BUILDPLATFORM debian:bookworm-slim AS tools ARG TARGETARCH -# Common tools: ripgrep / curl / vim, plus a set of recon staples (add/remove as needed). -# Node 22.x comes from NodeSource: bookworm's apt nodejs is 18, Playwright requires >=20, -# and 20 is end-of-life. 22 matches the CI and release workflows. -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates ripgrep curl wget vim git jq unzip \ - dnsutils iputils-ping netcat-openbsd inetutils-telnet whois nmap \ - && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ - && apt-get install -y --no-install-recommends nodejs \ - && rm -rf /var/lib/apt/lists/* -# Web-recon toolbox (drost-community take 1, #100): pinned release binaries installed -# into /usr/local/bin so hunt workers can run them directly through their Bash tool. -# Versions pinned per tool; upgrade deliberately. sqlmap is a python checkout (no -# release binaries) symlinked into PATH. ARG NUCLEI_VERSION=v3.11.1 ARG HTTPX_VERSION=v1.12.0 ARG SUBFINDER_VERSION=v2.17.0 ARG KATANA_VERSION=v1.8.0 ARG FFUF_VERSION=v2.3.0 ARG DALFOX_VERSION=v3.2.4 +ARG SQLMAP_VERSION=1.9.9 +ARG SQLMAP_COMMIT=cceda39208b5aad478de2c3f731df4239d9881f6 +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl git unzip \ + && rm -rf /var/lib/apt/lists/* +RUN set -eux; \ + case "${TARGETARCH:-amd64}" in \ + amd64) PD_ARCH=amd64; FFUF_ARCH=amd64; DALFOX_ARCH=x86_64 ;; \ + arm64) PD_ARCH=arm64; FFUF_ARCH=arm64; DALFOX_ARCH=aarch64 ;; \ + *) echo "unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + mkdir -p /out; \ + fetch() { base="$1"; asset="$2"; sums="$3"; name="$4"; \ + rm -rf /tmp/t; mkdir -p /tmp/t/x; \ + curl -fsSL "$base/$asset" -o "/tmp/t/$asset"; \ + curl -fsSL "$base/$sums" -o /tmp/t/sums.txt; \ + want="$(awk -v a="$asset" '$2 == a || $2 == "*" a { print $1 }' /tmp/t/sums.txt)"; \ + if [ -z "$want" ]; then echo "no checksum entry for $asset" >&2; exit 1; fi; \ + got="$(sha256sum "/tmp/t/$asset" | cut -d' ' -f1)"; \ + if [ "$want" != "$got" ]; then echo "checksum mismatch for $asset: want $want got $got" >&2; exit 1; fi; \ + case "$asset" in *.zip) unzip -q "/tmp/t/$asset" -d /tmp/t/x ;; *) tar -xzf "/tmp/t/$asset" -C /tmp/t/x ;; esac; \ + find /tmp/t/x -type f -name "$name" -exec install -m 0755 {} /out/ \; ; \ + [ -x "/out/$name" ] || { echo "$name not found in $asset" >&2; exit 1; }; \ + rm -rf /tmp/t; }; \ + gh="https://github.com"; \ + fetch "$gh/projectdiscovery/nuclei/releases/download/$NUCLEI_VERSION" \ + "nuclei_${NUCLEI_VERSION#v}_linux_${PD_ARCH}.zip" "nuclei_${NUCLEI_VERSION#v}_checksums.txt" nuclei; \ + fetch "$gh/projectdiscovery/httpx/releases/download/$HTTPX_VERSION" \ + "httpx_${HTTPX_VERSION#v}_linux_${PD_ARCH}.zip" "httpx_${HTTPX_VERSION#v}_checksums.txt" httpx; \ + fetch "$gh/projectdiscovery/subfinder/releases/download/$SUBFINDER_VERSION" \ + "subfinder_${SUBFINDER_VERSION#v}_linux_${PD_ARCH}.zip" "subfinder_${SUBFINDER_VERSION#v}_checksums.txt" subfinder; \ + fetch "$gh/projectdiscovery/katana/releases/download/$KATANA_VERSION" \ + "katana_${KATANA_VERSION#v}_linux_${PD_ARCH}.zip" "katana-${KATANA_VERSION#v}-checksums.txt" katana; \ + fetch "$gh/ffuf/ffuf/releases/download/$FFUF_VERSION" \ + "ffuf_${FFUF_VERSION#v}_linux_${FFUF_ARCH}.tar.gz" "ffuf_${FFUF_VERSION#v}_checksums.txt" ffuf; \ + fetch "$gh/hahwul/dalfox/releases/download/$DALFOX_VERSION" \ + "dalfox-${DALFOX_VERSION}-linux-${DALFOX_ARCH}-musl.tar.gz" "dalfox-${DALFOX_VERSION}-linux-${DALFOX_ARCH}-musl.tar.gz.sha256" dalfox; \ + git clone --quiet --depth 1 --branch "$SQLMAP_VERSION" https://github.com/sqlmapproject/sqlmap /opt/sqlmap; \ + commit="$(git -C /opt/sqlmap rev-parse HEAD)"; \ + if [ "$commit" != "$SQLMAP_COMMIT" ]; then echo "sqlmap commit mismatch: want $SQLMAP_COMMIT got $commit" >&2; exit 1; fi; \ + rm -rf /opt/sqlmap/.git + +# ---------------------------------------------------------------- runtime --- +FROM python:3.12-slim-bookworm +ARG TARGETARCH +# Common tools: ripgrep / curl / vim, plus a set of recon staples (add/remove as needed). +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates ripgrep curl wget vim git jq unzip xz-utils \ + dnsutils iputils-ping netcat-openbsd inetutils-telnet whois nmap \ + && rm -rf /var/lib/apt/lists/* +# Node 22 from the official nodejs.org tarball, verified against its SHASUMS256.txt: +# bookworm's apt nodejs is 18, Playwright requires >=20, and 20 is end-of-life. +# 22 matches the CI and release workflows. +ARG NODE_VERSION=22.23.4 +RUN set -eux; \ + case "${TARGETARCH:-amd64}" in \ + amd64) NODE_ARCH=x64 ;; \ + arm64) NODE_ARCH=arm64 ;; \ + *) echo "unsupported architecture: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + base="https://nodejs.org/dist/v${NODE_VERSION}"; \ + asset="node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz"; \ + curl -fsSL "$base/$asset" -o "/tmp/$asset"; \ + curl -fsSL "$base/SHASUMS256.txt" -o /tmp/SHASUMS256.txt; \ + want="$(awk -v a="$asset" '$2 == a { print $1 }' /tmp/SHASUMS256.txt)"; \ + if [ -z "$want" ]; then echo "no checksum entry for $asset" >&2; exit 1; fi; \ + got="$(sha256sum "/tmp/$asset" | cut -d' ' -f1)"; \ + if [ "$want" != "$got" ]; then echo "checksum mismatch for $asset: want $want got $got" >&2; exit 1; fi; \ + tar -xJf "/tmp/$asset" -C /usr/local --strip-components=1 --no-same-owner; \ + rm -f "/tmp/$asset" /tmp/SHASUMS256.txt; \ + node --version; npm --version +# Pinned, checksum-verified recon binaries and the sqlmap checkout from the tools stage. +COPY --from=tools /out/ /usr/local/bin/ +COPY --from=tools /opt/sqlmap /opt/sqlmap RUN set -eux; \ - base="https://github.com"; \ - pd_fetch() { repo="$1"; ver="$2"; name="$3"; nov="${ver#v}"; \ - curl -fsSL "$base/$repo/releases/download/$ver/${name}_${nov}_linux_${TARGETARCH}.zip" -o /tmp/t.zip \ - && unzip -o -q /tmp/t.zip -d /tmp/td \ - && find /tmp/td -type f -name "$name" -exec install -m 0755 {} /usr/local/bin/ \; \ - && rm -rf /tmp/t.zip /tmp/td; }; \ - case "$TARGETARCH" in amd64) FFUF_ARCH=amd64; DALFOX_ARCH=x86_64;; arm64) FFUF_ARCH=arm64; DALFOX_ARCH=aarch64;; esac; \ - pd_fetch projectdiscovery/nuclei "$NUCLEI_VERSION" nuclei; \ - pd_fetch projectdiscovery/httpx "$HTTPX_VERSION" httpx; \ - pd_fetch projectdiscovery/subfinder "$SUBFINDER_VERSION" subfinder; \ - pd_fetch projectdiscovery/katana "$KATANA_VERSION" katana; \ - tar_fetch() { url="$1"; name="$2"; \ - curl -fsSL "$url" -o /tmp/t.tgz \ - && mkdir -p /tmp/td && tar -xzf /tmp/t.tgz -C /tmp/td \ - && find /tmp/td -type f -name "$name" -exec install -m 0755 {} /usr/local/bin/ \; \ - && rm -rf /tmp/t.tgz /tmp/td; }; \ - tar_fetch "$base/ffuf/ffuf/releases/download/$FFUF_VERSION/ffuf_${FFUF_VERSION#v}_linux_${FFUF_ARCH}.tar.gz" ffuf; \ - tar_fetch "$base/hahwul/dalfox/releases/download/$DALFOX_VERSION/dalfox-${DALFOX_VERSION}-linux-${DALFOX_ARCH}-musl.tar.gz" dalfox; \ - git clone --depth 1 https://github.com/sqlmapproject/sqlmap /opt/sqlmap; \ ln -s /opt/sqlmap/sqlmap.py /usr/local/bin/sqlmap; \ nuclei -version >/dev/null; httpx -version; subfinder -version; katana -version; \ - ffuf -V >/dev/null; dalfox --version >/dev/null 2>&1 || true; sqlmap --version >/dev/null + ffuf -V >/dev/null; dalfox --version >/dev/null; sqlmap --version >/dev/null # bbot recursive recon orchestrator (#117): blacklanternsecurity/bbot, AGPL-3.0 # (same license as ARTEX; standalone CLI dependency, not linked code). Pinned @@ -111,8 +161,11 @@ RUN set -eux; \ # @playwright/cli: provides playwright-cli, verified with --help right after install. # Then install playwright (browser management) and preinstall chromium plus its system # dependencies via --with-deps, so MCP/CLI work on first start inside the container -# without downloading browsers over the network. -RUN npm install -g @playwright/mcp@latest @playwright/cli@latest playwright@latest \ +# without downloading browsers over the network. All three are pinned; upgrade deliberately. +ARG PLAYWRIGHT_MCP_VERSION=0.0.83 +ARG PLAYWRIGHT_CLI_VERSION=0.1.22 +ARG PLAYWRIGHT_VERSION=1.64.1 +RUN npm install -g "@playwright/mcp@${PLAYWRIGHT_MCP_VERSION}" "@playwright/cli@${PLAYWRIGHT_CLI_VERSION}" "playwright@${PLAYWRIGHT_VERSION}" \ && playwright-cli --help \ && playwright install --with-deps chromium \ && rm -rf /var/lib/apt/lists/*