# syntax=docker/dockerfile:1.7
#
# Multi-stage build for the dataloader-util CLI.
#
#   docker build -t dataloader-util:dev .
#   docker run --rm -v "$PWD/config:/config:ro" dataloader-util:dev \
#       run --config /config/job.yaml
#
# The runtime image is based on python:3.14-slim-bookworm, runs as a
# dedicated non-root user, and uses tini for proper signal forwarding.

# ---- builder ---------------------------------------------------------------
FROM ghcr.io/astral-sh/uv:python3.14-bookworm-slim AS builder

# VIRTUAL_ENV points uv at a stable, relocatable venv path. UV_LINK_MODE=copy
# ensures every file in the venv is a real copy (no hardlinks), so the venv
# can be safely COPYed into the runtime stage. UV_COMPILE_BYTECODE pre-builds
# .pyc files for a small startup-time win.
ENV VIRTUAL_ENV=/opt/venv \
    UV_PROJECT_ENVIRONMENT=/opt/venv \
    UV_LINK_MODE=copy \
    UV_COMPILE_BYTECODE=1 \
    PYTHONDONTWRITEBYTECODE=1

WORKDIR /app

# Install runtime dependencies from the lockfile first. Skipping the project
# itself here means later source changes don't bust the deps layer.
COPY pyproject.toml uv.lock README.md ./
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --frozen --no-install-project --no-dev

# Now install the project (without re-resolving deps).
COPY src ./src
RUN --mount=type=cache,target=/root/.cache/uv \
    uv pip install --no-deps --no-config .

# ---- runtime ---------------------------------------------------------------
FROM python:3.14-slim-bookworm AS runtime

# tini is the only additional apt package we need: it forwards signals and
# reaps zombies, which matters when the CLI is invoked from a pipeline
# orchestrator. Upgrade base packages first so fixed Debian security updates
# (for example libgnutls30) are applied even before the upstream Python image
# is rebuilt.
# libssl3 and libpq5 are present in the base image (psycopg[binary] bundles
# libpq itself, and snowflake-connector links against the base libssl3).
RUN apt-get update \
    && apt-get upgrade -y \
    && apt-get install -y --no-install-recommends tini \
    && rm -rf /var/lib/apt/lists/*

# Dedicated non-root user and group. uid/gid 1000 matches the typical
# "first non-system user" on host systems, so volume mounts are writable.
RUN groupadd --system --gid 1000 dataloader \
    && useradd  --system --uid 1000 --gid dataloader \
                --home-dir /app --shell /usr/sbin/nologin \
                dataloader

ENV PATH="/opt/venv/bin:${PATH}" \
    PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1

# Bring across the relocatable venv from the builder stage.
COPY --from=builder /opt/venv /opt/venv

WORKDIR /app
USER dataloader

# Default invocation shows the CLI help so an untagged run is informative.
# In pipelines, override with:  docker run ... <image> run --config /config/...
ENTRYPOINT ["/usr/bin/tini", "--", "dataloader-util"]
CMD ["--help"]
