Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 33 additions & 22 deletions sandbox/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
# ethpandaops MCP Sandbox Container
# This container provides a secure execution environment for Python code
# with the ethpandaops library pre-installed for Ethereum network data analysis.
#
# Multi-stage: the builder holds uv and resolves the full dependency tree into a
# staging prefix; the final image copies that prefix as a complete install
# artifact (site-packages, console scripts, and package data) without ever
# shipping uv. Dependencies are installed --only-binary, so a missing wheel is a
# hard error rather than an unlocked source compile, and no C toolchain is
# needed in either stage.

FROM python:3.11-slim@sha256:a3ab0b966bc4e91546a033e22093cb840908979487a9fc0e6e38295747e49ac0
FROM python:3.11-slim@sha256:a3ab0b966bc4e91546a033e22093cb840908979487a9fc0e6e38295747e49ac0 AS builder

# Install uv and system dependencies
# uv (build-time only; never copied into the final image)
COPY --from=ghcr.io/astral-sh/uv:0.11.17@sha256:03bdc89bb9798628846e60c3a9ad19006c8c3c724ccd2985a33145c039a0577b /uv /uvx /bin/
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*

# Create non-root user for security
RUN useradd -m -s /bin/bash sandbox

# Create directories
RUN mkdir -p /shared /output && \
chown sandbox:sandbox /shared /output

# Install Python dependencies. requirements.txt is compiled from requirements.in
# with hashes (`uv pip compile --generate-hashes --universal`); --require-hashes
# makes pip refuse anything that doesn't match the lock.
# Install Python dependencies into a staging prefix. requirements.txt is compiled
# from requirements.in with hashes (`uv pip compile --generate-hashes
# --universal`); --require-hashes makes pip refuse anything that doesn't match
# the lock, and --only-binary=:all: forbids source builds (every dependency must
# resolve to a prebuilt wheel).
COPY sandbox/requirements.txt /tmp/requirements.txt
RUN uv pip install --system --no-cache --require-hashes -r /tmp/requirements.txt && \
rm /tmp/requirements.txt
RUN uv pip install --python /usr/local/bin/python3 --prefix /install --no-cache \
--require-hashes --only-binary=:all: -r /tmp/requirements.txt

# Install the ethpandaops platform library
# Install the ethpandaops platform library. Copied after the heavy dependency
# layer so edits to these (frequently changed) files don't bust the deps cache.
COPY sandbox/ethpandaops /opt/ethpandaops-pkg

# Copy extension Python modules into the package
COPY modules/benchmarkoor/python/benchmarkoor.py /opt/ethpandaops-pkg/ethpandaops/benchmarkoor.py
COPY modules/block_archive/python/block_archive.py /opt/ethpandaops-pkg/ethpandaops/block_archive.py
COPY modules/cbt/python/cbt.py /opt/ethpandaops-pkg/ethpandaops/cbt.py
Expand All @@ -40,8 +38,21 @@ COPY modules/ethnode/python/ethnode.py /opt/ethpandaops-pkg/ethpandaops/ethnode.
COPY modules/tracoor/python/tracoor.py /opt/ethpandaops-pkg/ethpandaops/tracoor.py

# --no-deps: the package's dependencies are already installed (hash-locked)
# above; resolving them here would bypass the lock.
RUN uv pip install --system --no-cache --no-deps /opt/ethpandaops-pkg && rm -rf /opt/ethpandaops-pkg
# above; resolving them here would bypass the lock. The package is pure Python,
# so no toolchain is required to build it.
RUN uv pip install --python /usr/local/bin/python3 --prefix /install --no-cache --no-deps /opt/ethpandaops-pkg

FROM python:3.11-slim@sha256:a3ab0b966bc4e91546a033e22093cb840908979487a9fc0e6e38295747e49ac0

# Create non-root user and runtime directories.
RUN useradd -m -s /bin/bash sandbox && \
mkdir -p /shared /output && \
chown sandbox:sandbox /shared /output

# Copy the resolved environment from the builder onto the runtime's /usr/local,
# bringing site-packages, console scripts, and package data. uv and the staging
# tooling are intentionally left behind.
COPY --from=builder /install /usr/local

# Set working directory
WORKDIR /home/sandbox
Expand Down
31 changes: 8 additions & 23 deletions sandbox/requirements.in
Original file line number Diff line number Diff line change
@@ -1,39 +1,24 @@
# Core data analysis libraries
# Core data analysis
pandas>=2.2.0
numpy>=2.0.0
polars>=1.20.0
scipy>=1.14.0
pyarrow>=22.0.0 # Parquet support, columnar data
fastparquet>=2025.12.0 # Alternative parquet engine
fastparquet>=2026.3.0 # Parquet read/write engine (~9MB vs pyarrow's ~140MB)

# Machine learning & statistics
scikit-learn>=1.8.0
statsmodels>=0.14.6

# Graph analysis
networkx>=3.6.0 # For transaction flow, address relationships

# Large dataset processing
dask>=2025.12.0 # Parallel pandas-like operations

# Visualization
# Visualization (chart artifacts are uploaded back to storage)
# matplotlib/seaborn render static PNGs headless with no system deps; plotly is
# kept for interactive HTML output. Static plotly export (kaleido) is omitted
# because it needs a full Chrome install.
matplotlib>=3.9.0
seaborn>=0.13.0
seaborn>=0.13.0 # statistical charts on top of matplotlib
plotly>=5.24.0
altair>=5.4.0
vl-convert-python>=1.7.0 # For Altair PNG/SVG export
bokeh>=3.6.0
kaleido>=0.2.1 # For Plotly image export
plotnine>=0.15.4 # ggplot2 grammar of graphics
pygwalker>=0.5.0 # Tableau-like drag-and-drop exploration

# ClickHouse client
clickhouse-connect>=0.8.0

# HTTP client for Prometheus/Loki
httpx>=0.28.0

# S3 client
# S3 client (block archive)
boto3>=1.35.0

# Utilities
Expand Down
Loading
Loading