# Multi-stage build: builder installs dependencies into a target dir,
# runtime copies only what's needed — keeps the final image smaller
# and avoids shipping build toolchains (gcc, headers) that some
# dependency wheels may need to compile against on platforms without
# prebuilt wheels.

# ---- Builder ----------------------------------------------------------------
FROM python:3.12-slim AS builder

WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends \
        build-essential \
    && rm -rf /var/lib/apt/lists/*

# README.md is required at build time, not just for humans reading the
# repo -- pyproject.toml declares it as the package's `readme`, and
# hatchling's build backend fails metadata validation without it
# (confirmed by actually running this build, which is how this was
# found: "OSError: Readme file does not exist: README.md"). Independent,
# previously-undiscovered reason this image never actually built, on
# top of the missing [pdf] extra below: this COPY line was missing
# entirely, and .dockerignore's blanket `*.md` rule excluded README.md
# from the build context even once added here — see its `!README.md`
# exception.
COPY pyproject.toml README.md ./
COPY src/ ./src/
# database/meridian.db + the 3 runtime JSONs are pyproject.toml's
# [tool.hatch.build.targets.wheel.force-include] targets -- hatchling
# fails the wheel build ("Forced include not found") without them
# actually present in the build context. A third, independent,
# previously-undiscovered reason this image never built: this COPY was
# also missing, and .dockerignore's blanket `*.db` rule would have
# excluded database/meridian.db even once added here — see its
# `!database/meridian.db` exception.
COPY database/ ./database/
COPY data/ ./data/

# [pdf]: Playwright's Python package — see below for why this was
# previously missing and broke the build entirely, not just PDF
# generation. [all-providers]: anthropic/openai/groq/boto3 SDKs for the
# Interpreter's one LLM call — openai is already a hard transitive
# dependency of litellm itself regardless, but boto3/Bedrock genuinely
# needs its own SDK, so bundling all four removes any per-deployment
# guesswork about which provider extra is actually needed.
RUN pip install --no-cache-dir --target=/build/deps ".[pdf,all-providers]"

# ---- Runtime ------------------------------------------------------------------
FROM python:3.12-slim AS runtime

# Playwright's headless Chromium (used by report/pdf_exporter.py) needs
# these OS libraries — without them, PDF report generation fails at
# runtime with an opaque "cannot open shared object file" error rather
# than at image-build time, so they're installed here rather than
# deferred to first use.
#
# git: two independent real reasons, not one. (1) context/builder.py
# shells out to `git rev-parse HEAD` for commit-hash provenance on
# every scan and silently swallows the failure when it's missing — this
# image never had git, so every scan run in it has silently been
# losing that provenance. (2) api/remote_clone.py's /scan/remote/*
# endpoints (2026-07-23) need it to clone a caller-supplied repo URL
# server-side at all.
RUN apt-get update && apt-get install -y --no-install-recommends \
        git \
        libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 \
        libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2 \
        libpango-1.0-0 libcairo2 ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# Real, non-root user — running an internet-facing API as root inside
# the container is an avoidable risk, not a convenience worth keeping.
RUN useradd --create-home --uid 1000 meridian

WORKDIR /app
COPY --from=builder /build/deps /usr/local/lib/python3.12/site-packages
COPY src/ ./src/

ENV PYTHONPATH=/app/src
ENV MERIDIAN_HOME=/data
ENV PYTHONUNBUFFERED=1

# Chromium for PDF report generation — see report/pdf_exporter.py,
# which reuses this same Playwright pattern from the legacy
# artifact_factory.py.
#
# Real bug caught by tracing through at build time, not assumed safe:
# `playwright install` runs here as root (before USER meridian below),
# and its DEFAULT install location is under root's home directory
# (~/.cache/ms-playwright), which the non-root meridian user cannot
# read at runtime — /root itself isn't world-traversable. Fixed by
# installing to an explicit, shared, world-readable path instead.
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
RUN python -m playwright install chromium \
    && chmod -R o+rX /opt/playwright-browsers

RUN mkdir -p /data && chown meridian:meridian /data
VOLUME ["/data"]

USER meridian
EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8000/health', timeout=3).status == 200 else 1)" || exit 1

ENTRYPOINT ["python", "-m", "meridian.docker_entrypoint"]
CMD ["api"]
