FROM debian@sha256:76b6251aaac0ebb6aca1afbc780717aab7e455038c07cb0cb23facb33d241c7d

ARG NODE_VERSION=24.18.0
ARG NODE_SHA256=55aa7153f9d88f28d765fcdad5ae6945b5c0f98a36881703817e4c450fa76742
ARG PNPM_VERSION=11.15.1
ARG BUN_VERSION=1.3.14
ARG BUN_SHA256=951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f
ARG UV_VERSION=0.12.2
ARG UV_SHA256=d66e96b5f1ca3b99806eee283a8125d33a0bd669e6e6d9bc4ab7ffda63c41bf4
ARG GH_VERSION=2.97.0
ARG GH_SHA256=7c7fa3bb890db0934baf65910d97b8c0fa437b2e590f7f7daf6bdf82c5c486d7
ARG CODEX_VERSION=0.146.0
ARG CODEX_SHA256=3c89125af1d7c98abec8beb551292ef99daca52e204e5852a9139feae2c467e5
ARG CLAUDE_VERSION=2.1.224
ARG CLAUDE_SHA256=a2b5add7dc4bcd8eaa029f4e8bdac4df7769b4073698db7989d206baf9419c2d
ARG CURSOR_AGENT_VERSION=2026.08.04-aaa8809
ARG CURSOR_AGENT_SHA256=e282068dcb5cdd668b8ce2e3456c58be13bb64a834e1ad49f8534b5cd7aa2fe5
ARG AGENT_UID=1000
ARG AGENT_GID=1000

ENV DEBIAN_FRONTEND=noninteractive \
    LANG=C.UTF-8 \
    HOME=/sandbox/home \
    PNPM_HOME=/sandbox/home/.local/share/pnpm \
    COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \
    PATH=/usr/local/node/bin:/sandbox/home/.local/share/pnpm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

RUN apt-get update \
 && apt-get install -y --no-install-recommends \
      build-essential \
      ca-certificates \
      curl \
      fd-find \
      file \
      git \
      jq \
      less \
      libssl-dev \
      nftables \
      netcat-openbsd \
      openssh-client \
      pkg-config \
      procps \
      python3 \
      python3-venv \
      ripgrep \
      rsync \
      rustc \
      cargo \
      tini \
      tzdata \
      unzip \
      xz-utils \
      zstd \
 && rm -rf /var/lib/apt/lists/* \
 && ln -s /usr/bin/fdfind /usr/local/bin/fd

RUN curl -fsSLo /tmp/node.tar.xz "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" \
 && echo "${NODE_SHA256}  /tmp/node.tar.xz" | sha256sum -c - \
 && mkdir -p /usr/local/node \
 && tar -xJf /tmp/node.tar.xz -C /usr/local/node --strip-components=1 \
 && rm /tmp/node.tar.xz \
 && /usr/local/node/bin/corepack enable --install-directory /usr/local/node/bin \
 && /usr/local/node/bin/corepack prepare "pnpm@${PNPM_VERSION}" --activate

RUN curl -fsSLo /tmp/bun.zip "https://github.com/oven-sh/bun/releases/download/bun-v${BUN_VERSION}/bun-linux-x64.zip" \
 && echo "${BUN_SHA256}  /tmp/bun.zip" | sha256sum -c - \
 && unzip -q /tmp/bun.zip -d /tmp/bun \
 && install -m 0755 /tmp/bun/bun-linux-x64/bun /usr/local/bin/bun \
 && ln -s /usr/local/bin/bun /usr/local/bin/bunx \
 && rm -rf /tmp/bun.zip /tmp/bun

RUN curl -fsSLo /tmp/uv.tar.gz "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-x86_64-unknown-linux-gnu.tar.gz" \
 && echo "${UV_SHA256}  /tmp/uv.tar.gz" | sha256sum -c - \
 && tar -xzf /tmp/uv.tar.gz -C /tmp \
 && install -m 0755 /tmp/uv-x86_64-unknown-linux-gnu/uv /usr/local/bin/uv \
 && install -m 0755 /tmp/uv-x86_64-unknown-linux-gnu/uvx /usr/local/bin/uvx \
 && rm -rf /tmp/uv.tar.gz /tmp/uv-x86_64-unknown-linux-gnu

RUN curl -fsSLo /tmp/gh.deb "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.deb" \
 && echo "${GH_SHA256}  /tmp/gh.deb" | sha256sum -c - \
 && dpkg -i /tmp/gh.deb \
 && rm /tmp/gh.deb

RUN curl -fsSLo /tmp/codex.tar.gz "https://github.com/openai/codex/releases/download/rust-v${CODEX_VERSION}/codex-package-x86_64-unknown-linux-musl.tar.gz" \
 && echo "${CODEX_SHA256}  /tmp/codex.tar.gz" | sha256sum -c - \
 && mkdir -p /usr/local/lib/codex \
 && tar -xzf /tmp/codex.tar.gz -C /usr/local/lib/codex \
 && ln -s /usr/local/lib/codex/bin/codex /usr/local/bin/codex \
 && rm -f /tmp/codex.tar.gz

RUN curl -fsSLo /tmp/claude-code "https://downloads.claude.ai/claude-code-releases/${CLAUDE_VERSION}/linux-x64/claude" \
 && echo "${CLAUDE_SHA256}  /tmp/claude-code" | sha256sum -c - \
 && install -d /usr/local/lib/claude-code \
 && install -m 0755 /tmp/claude-code /usr/local/lib/claude-code/claude \
 && ln -s /usr/local/lib/claude-code/claude /usr/local/bin/claude \
 && rm -f /tmp/claude-code

RUN curl -fsSLo /tmp/cursor-agent.tar.gz "https://downloads.cursor.com/lab/${CURSOR_AGENT_VERSION}/linux/x64/agent-cli-package.tar.gz" \
 && echo "${CURSOR_AGENT_SHA256}  /tmp/cursor-agent.tar.gz" | sha256sum -c - \
 && mkdir -p /usr/local/lib/cursor-agent \
 && tar -xzf /tmp/cursor-agent.tar.gz -C /usr/local/lib/cursor-agent --strip-components=1 \
 && ln -s /usr/local/lib/cursor-agent/cursor-agent /usr/local/bin/cursor-agent \
 && rm -f /tmp/cursor-agent.tar.gz

RUN groupadd -g "${AGENT_GID}" agent \
 && useradd -u "${AGENT_UID}" -g "${AGENT_GID}" -M -d /sandbox/home -s /bin/bash agent \
 && mkdir -p /sandbox \
 && chown "${AGENT_UID}:${AGENT_GID}" /sandbox

COPY bin/ /usr/local/bin/
COPY lib/ /usr/local/lib/overdeck-sandbox/
COPY etc/toolgap.bash /etc/overdeck-sandbox/toolgap.bash

RUN chmod 0755 /usr/local/bin/cdx-k3s-worker /usr/local/bin/cdx-result-upload /usr/local/bin/e2e-remote /usr/local/bin/sandbox-toolgap /usr/local/bin/sandbox-e2e-pair /usr/local/bin/sandbox-egress-init /usr/local/bin/git \
 # nft stays world-executable: under --userns=keep-id the entrypoint's uid 0 does
 # not own image files, so 0700 blocks the egress-init itself. The agent user is
 # kept from mutating rules by the capability drop, not by file mode.
 && chmod 0755 /usr/sbin/nft \
 && printf '%s\n' '. /etc/overdeck-sandbox/toolgap.bash' >> /etc/bash.bashrc \
 && printf 'export PATH=/usr/local/node/bin:$PNPM_HOME:$PATH\n. /etc/overdeck-sandbox/toolgap.bash\n' \
      > /etc/profile.d/overdeck-sandbox.sh

ENV BASH_ENV=/etc/overdeck-sandbox/toolgap.bash \
    SANDBOX_TOOLGAP_FILE=/sandbox/toolgap/gaps.jsonl \
    PNPM_STORE_DIR=/sandbox/store/pnpm \
    PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \
    PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
    DISABLE_AUTOUPDATER=1

USER agent
WORKDIR /sandbox/workspace
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/bin/bash", "-l"]
