FROM python:3-alpine LABEL org.opencontainers.image.authors="socket.dev" # Language version arguments with defaults ARG GO_VERSION=system ARG JAVA_VERSION=17 ARG DOTNET_VERSION=8 # CLI and SDK arguments ARG CLI_VERSION ARG SDK_VERSION ARG PIP_INDEX_URL=https://pypi.org/simple ARG PIP_EXTRA_INDEX_URL=https://pypi.org/simple ARG USE_LOCAL_INSTALL=false # Install base packages first RUN apk update && apk add --no-cache \ git nodejs npm yarn curl wget \ ruby ruby-dev build-base strace # Install Go with version control RUN if [ "$GO_VERSION" = "system" ]; then \ apk add --no-cache go && \ echo "/usr/lib/go" > /etc/goroot; \ else \ cd /tmp && \ ARCH=$(uname -m) && \ case $ARCH in \ x86_64) GOARCH=amd64 ;; \ aarch64) GOARCH=arm64 ;; \ *) echo "Unsupported architecture: $ARCH" && exit 1 ;; \ esac && \ wget https://golang.org/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz && \ tar -C /usr/local -xzf go${GO_VERSION}.linux-${GOARCH}.tar.gz && \ rm go${GO_VERSION}.linux-${GOARCH}.tar.gz && \ echo "/usr/local/go" > /etc/goroot; \ fi # Install Java with version control RUN if [ "$JAVA_VERSION" = "8" ]; then \ apk add --no-cache openjdk8-jdk; \ elif [ "$JAVA_VERSION" = "11" ]; then \ apk add --no-cache openjdk11-jdk; \ elif [ "$JAVA_VERSION" = "17" ]; then \ apk add --no-cache openjdk17-jdk; \ elif [ "$JAVA_VERSION" = "21" ]; then \ apk add --no-cache openjdk21-jdk; \ else \ echo "Unsupported Java version: $JAVA_VERSION. Supported: 8, 11, 17, 21" && exit 1; \ fi # Install .NET with version control RUN if [ "$DOTNET_VERSION" = "6" ]; then \ apk add --no-cache dotnet6-sdk; \ elif [ "$DOTNET_VERSION" = "8" ]; then \ apk add --no-cache dotnet8-sdk; \ else \ echo "Unsupported .NET version: $DOTNET_VERSION. Supported: 6, 8" && exit 1; \ fi # Install PyPy (Alpine-compatible build for x86_64 only) # PyPy is an alternative Python interpreter that makes the Python reachability analysis faster. # This is a custom build of PyPy3.11 for Alpine on x86-64. ARG TARGETARCH # Passed by Docker buildx RUN if [ "$TARGETARCH" = "amd64" ]; then \ PYPY_URL="https://github.com/BarrensZeppelin/alpine-pypy/releases/download/alp3.23.1-pypy3.11-7.3.20/pypy3.11-v7.3.20-linux64-alpine3.21.tar.bz2" && \ PYPY_SHA256="60847fea6ffe96f10a3cd4b703686e944bb4fbcc01b7200c044088dd228425e1" && \ curl -L -o /tmp/pypy.tar.bz2 "$PYPY_URL" && \ echo "$PYPY_SHA256 /tmp/pypy.tar.bz2" | sha256sum -c - && \ mkdir -p /opt/pypy && \ tar -xj --strip-components=1 -C /opt/pypy -f /tmp/pypy.tar.bz2 && \ rm /tmp/pypy.tar.bz2 && \ ln -s /opt/pypy/bin/pypy3 /bin/pypy3 && \ pypy3 --version; \ fi # Install additional tools RUN npm install @coana-tech/cli socket -g && \ gem install bundler && \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \ . ~/.cargo/env && \ rustup component add rustfmt clippy # Set environment paths ENV PATH="/usr/local/go/bin:/usr/lib/go/bin:/root/.cargo/bin:${PATH}" ENV GOPATH="/go" # Install uv COPY --from=ghcr.io/astral-sh/uv:0.10.4 /uv /usr/local/bin/uv # Install pyenv # pyenv lets us build/install arbitrary Python versions on demand. We install # the build dependencies needed to compile CPython on Alpine, then install # pyenv itself. We deliberately only symlink the `pyenv` binary onto the PATH # and do NOT add pyenv's shims directory, so its shims don't shadow the system # Python that the CLI runs on. RUN apk add --no-cache \ bash \ bzip2-dev \ ca-certificates \ libffi-dev \ libxslt-dev \ linux-headers \ ncurses-dev \ openssl-dev \ readline-dev \ sqlite-dev \ xz-dev \ zlib-dev RUN curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | PYENV_GIT_TAG="v2.7.1" bash && \ ln -s ~/.pyenv/bin/pyenv /bin/pyenv && \ pyenv --version # Install Python dependencies from the lockfile with hash verification so the # image never resolves loose versions from PyPI at build time. COPY pyproject.toml uv.lock /tmp/socket-cli-lock/ # Index flags are passed explicitly (always production PyPI) so the # PIP_INDEX_URL/PIP_EXTRA_INDEX_URL ARGs used to point CLI/SDK preview installs # at TestPyPI don't leak into the locked dependency install via pip's env vars. RUN uv export --directory /tmp/socket-cli-lock --frozen --no-dev --no-emit-project \ --format requirements-txt -o /tmp/socket-cli-lock/requirements.txt && \ pip install --require-hashes --no-deps \ --index-url https://pypi.org/simple --extra-index-url https://pypi.org/simple \ -r /tmp/socket-cli-lock/requirements.txt # Install CLI based on build mode RUN if [ "$USE_LOCAL_INSTALL" = "true" ]; then \ echo "Using local development install"; \ else \ cli_installed=false; \ for i in $(seq 1 10); do \ echo "Attempt $i/10: Installing socketsecurity==$CLI_VERSION"; \ if pip install --no-deps --index-url ${PIP_INDEX_URL} --extra-index-url ${PIP_EXTRA_INDEX_URL} socketsecurity==$CLI_VERSION; then \ cli_installed=true; \ break; \ fi; \ if [ "$i" -lt 10 ]; then \ echo "Install failed, waiting 30s before retry..."; \ sleep 30; \ fi; \ done; \ if [ "$cli_installed" != "true" ]; then \ echo "Failed to install socketsecurity==$CLI_VERSION after 10 attempts"; \ exit 1; \ fi; \ pip check || exit 1; \ if [ ! -z "$SDK_VERSION" ]; then \ pip install --index-url ${PIP_INDEX_URL} --extra-index-url ${PIP_EXTRA_INDEX_URL} socketdev==${SDK_VERSION}; \ fi; \ fi # Copy local source and install in editable mode if USE_LOCAL_INSTALL is true COPY . /app WORKDIR /app RUN if [ "$USE_LOCAL_INSTALL" = "true" ]; then \ pip install --no-deps -e . && pip check; \ fi # Create workspace directory with proper permissions RUN mkdir -p /go/src && chmod -R 777 /go # Copy and setup entrypoint script COPY scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN chmod +x /usr/local/bin/docker-entrypoint.sh ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]