# Minimal image containing only the pgcommon-migrate CLI — for use as a Kubernetes init
# container or a CI/CD pre-deploy job. This is a utility image, not an application server.
# See README.md's "Migrations" section for the deployment patterns this is meant for.
#
# The library ships no migrations: mount the service's migrations directory and set
# MIGRATIONS_DIR, e.g.
#   docker run --rm -v "$PWD/migrations:/migrations:ro" -e MIGRATIONS_DIR=/migrations \
#     -e MIGRATION_DATABASE_URL='postgres://migrator:…@db:5432/app?sslmode=verify-full' \
#     ghcr.io/.../pgcommon-migrate up
#
# Base images are digest-pinned: a floating tag can be silently re-pointed upstream. Refresh
# every FROM line with `make pin-base-images` (it resolves each tag's current digest with
# `docker buildx imagetools inspect` and rewrites the pin).
#
# Reproducible contents: the runtime dependencies are installed from uv.lock (exported with
# hashes, installed with --require-hashes), and the wheel is built with the build backend
# hash-locked in build-constraints.txt — nothing is resolved at build time.

FROM ghcr.io/astral-sh/uv:0.11.32@sha256:df4cae8f3a96d175e2e5f992e597550000edbe78fdc2594d5cd8de1a217f504c AS uv

FROM python:3.14-slim@sha256:a2b82f3c48559aa0a8446d9af49826b6e2b2016f4cd2afabfe6013ec53729170 AS build

# SOURCE_DATE_EPOCH (commit time) is injected by CI so the wheel's file timestamps — and
# BuildKit's layer timestamps — are reproducible.
ARG SOURCE_DATE_EPOCH

COPY --from=uv /uv /usr/local/bin/uv

WORKDIR /src
# LICENSE: hatchling ships it in the wheel's dist-info (license-files default).
COPY pyproject.toml uv.lock build-constraints.txt README.md LICENSE ./
COPY src ./src

# --frozen: export uv.lock as is (fails rather than re-resolving); --no-dev / --no-emit-project:
# only the runtime dependencies of the package (the wheel is installed separately).
RUN uv export --frozen --no-dev --no-emit-project --no-header --format requirements-txt \
        -o requirements.txt \
    && uv build --wheel --no-cache --build-constraints build-constraints.txt --require-hashes

FROM python:3.14-slim@sha256:a2b82f3c48559aa0a8446d9af49826b6e2b2016f4cd2afabfe6013ec53729170

# BUILD_VERSION is injected by CI via --build-arg; defaults to "dev" for local builds. The CLI's
# own `version` command reports the installed package version.
ARG BUILD_VERSION=dev
LABEL org.opencontainers.image.title="pgcommon-migrate" \
      org.opencontainers.image.version="${BUILD_VERSION}"

# Again for this stage: with SOURCE_DATE_EPOCH set, the .pyc files pip compiles are
# hash-based (py_compile's default then), not stamped with the install time.
ARG SOURCE_DATE_EPOCH

# Debian security fixes newer than the pinned base image, pinned to exact versions so the
# build stays deterministic; drop a line once the base digest is refreshed past it (Trivy's
# gate in ci.yml flags any fixable one). apt's lists, logs and caches are removed so they do
# not vary the image between builds.
# DSA-6549-1 (xz-utils): liblzma5 5.8.1-1+deb13u1 -> 5.8.1-1+deb13u2.
RUN apt-get update \
    && apt-get install --yes --no-install-recommends liblzma5=5.8.1-1+deb13u2 \
    && rm -rf /var/lib/apt/lists/* /var/cache/apt/* /var/log/apt /var/log/dpkg.log \
        /var/cache/ldconfig/aux-cache

COPY --from=build /src/requirements.txt /src/dist/*.whl /tmp/pgcommon/
# Dependencies only from the hashed lock export; then the package itself, without resolving
# anything further (--no-deps). pip is removed afterwards: the CLI never needs it, and the
# copy the base image ships vendors its own urllib3 / msgpack / setuptools, which the
# Trivy gate would otherwise flag.
RUN pip install --no-cache-dir --require-hashes -r /tmp/pgcommon/requirements.txt \
    && pip install --no-cache-dir --no-deps /tmp/pgcommon/*.whl \
    && rm -rf /tmp/pgcommon \
    && pip uninstall --yes pip

# Numeric UID:GID (the distroless "nonroot" convention, 65532): Kubernetes can only verify
# runAsNonRoot for a numeric user, and a name may not resolve on the host (hadolint DL3066).
USER 65532:65532

# No default CMD: like the Go image, a bare `docker run` prints the usage and exits 1.
ENTRYPOINT ["pgcommon-migrate"]
