# SPDX-FileCopyrightText: 2026 Bart Broere
# SPDX-License-Identifier: GPL-3.0-or-later

# boltage: neo4j-browser on top of PostgreSQL + Apache AGE.
#
# Two images can be built from this file:
#
#   full (the default): the Apache AGE image (PostgreSQL with the AGE extension)
#       plus boltage, neo4j-browser and pgAdmin, all in one container.
#   slim (--target slim): only boltage and neo4j-browser, for connecting to a
#       separate PostgreSQL server with AGE; see compose.yaml.
#
# boltage is the Python package that speaks the Bolt protocol to the browser and
# translates Cypher into AGE `cypher()` calls. The browser stage builds the
# neo4j-browser static frontend from source for both images.

ARG AGE_IMAGE=docker.io/apache/age:release_PG18_1.8.0
ARG SLIM_BASE_IMAGE=docker.io/library/debian:trixie-slim
# Commit of apache/age's release/PG18/1.8.0 branch, for AGE's LICENSE and NOTICE.
ARG AGE_SOURCE_REF=b570cf7c1486863f77c14e9c0e07b0e9bfd01bf4
ARG PGADMIN_VERSION=9.18

FROM docker.io/library/node:16.20.2-bullseye AS browser

ARG NEO4J_BROWSER_REPO=https://github.com/neo4j/neo4j-browser.git
ARG NEO4J_BROWSER_REF=3928c10fd6f148fd615b391d27d3fd6ce43a9044

WORKDIR /src
RUN git init -q . \
    && git remote add origin "$NEO4J_BROWSER_REPO" \
    && git fetch -q --depth 1 origin "$NEO4J_BROWSER_REF" \
    && git checkout -q FETCH_HEAD \
    && git archive --format=tar.gz --prefix=neo4j-browser/ -o /neo4j-browser-source.tar.gz HEAD
RUN yarn install --frozen-lockfile --network-timeout 600000
RUN yarn build && test -f dist/index.html


# Builds boltage's sdist from the git repository, because verri derives the version
# from the git history (see version.py). The unpacked sdist carries that version
# in PKG-INFO, so the images below can be built without git.
FROM ${SLIM_BASE_IMAGE} AS sdist

RUN apt-get update \
    && apt-get install -y --no-install-recommends git python3-build python3-venv \
    && rm -rf /var/lib/apt/lists/*

COPY . /src
RUN python3 -m build --sdist --outdir /dist /src \
    && mkdir /boltage \
    && tar -xzf /dist/boltage-*.tar.gz --strip-components=1 -C /boltage


FROM ${SLIM_BASE_IMAGE} AS slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends openssl python3 python3-psycopg python3-venv \
    && rm -rf /var/lib/apt/lists/*

# boltage itself, using Debian's psycopg and the other dependencies from PyPI. License
# notices: see THIRD_PARTY_NOTICES.md.
COPY container/collect-python-licenses.py /tmp/
COPY container/licenses/ /tmp/licenses/
COPY --from=sdist /boltage /tmp/boltage
RUN python3 -m venv --system-site-packages /opt/boltage/venv \
    && /opt/boltage/venv/bin/pip install --no-cache-dir "/tmp/boltage[browser]" \
    && /opt/boltage/venv/bin/python /tmp/collect-python-licenses.py \
        /usr/share/doc/boltage/boltage-python-licenses /tmp/licenses \
    && rm -r /tmp/boltage /tmp/collect-python-licenses.py /tmp/licenses
COPY LICENSE THIRD_PARTY_NOTICES.md /usr/share/doc/boltage/
COPY --from=browser /src/LICENSE /src/NOTICE.txt /src/LICENSES.txt /neo4j-browser-source.tar.gz \
    /usr/share/doc/boltage/neo4j-browser/
COPY --from=browser /src/dist /opt/boltage/browser
COPY container/boltage-start.sh /usr/local/bin/boltage-start.sh

# uid and gid 999, the same as the postgres user that runs boltage in the full image,
# so mounted certificates need the same permissions in both. /var/lib/boltage holds
# the self-signed certificate, when there is one.
RUN groupadd --system --gid 999 boltage \
    && useradd --system --uid 999 --gid boltage --no-create-home --home-dir /nonexistent \
        --shell /usr/sbin/nologin boltage \
    && install -d -o boltage -g boltage -m 0700 /var/lib/boltage
USER boltage

ENV BOLTAGE_BROWSER_DIR=/opt/boltage/browser \
    BOLTAGE_HTTP_PORT=7474 \
    BOLTAGE_BOLT_PORT=7687

# 7474: neo4j-browser (HTTP), 7687: Bolt
EXPOSE 7474 7687

CMD ["/usr/local/bin/boltage-start.sh"]


FROM ${AGE_IMAGE} AS full

ARG AGE_SOURCE_REF
ARG PGADMIN_VERSION

RUN apt-get update \
    && apt-get install -y --no-install-recommends python3 python3-psycopg python3-venv \
    && rm -rf /var/lib/apt/lists/*

RUN python3 -m venv /opt/pgadmin \
    && /opt/pgadmin/bin/pip install --no-cache-dir "pgadmin4==${PGADMIN_VERSION}" gunicorn \
    && ln -s "$(/opt/pgadmin/bin/python -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])')/pgadmin4" \
        /opt/pgadmin/app \
    && mkdir -p /var/lib/pgadmin \
    && chown postgres:postgres /var/lib/pgadmin

# License notices: see THIRD_PARTY_NOTICES.md. neo4j-browser is GPL-3.0, so its
# complete source is shipped next to the license.
COPY container/collect-python-licenses.py /tmp/
COPY container/licenses/ /tmp/licenses/
RUN /opt/pgadmin/bin/python /tmp/collect-python-licenses.py \
        /usr/share/doc/boltage/pgadmin-python-licenses /tmp/licenses

# boltage itself, using Debian's psycopg and the other dependencies from PyPI.
COPY --from=sdist /boltage /tmp/boltage
RUN python3 -m venv --system-site-packages /opt/boltage/venv \
    && /opt/boltage/venv/bin/pip install --no-cache-dir "/tmp/boltage[browser]" \
    && /opt/boltage/venv/bin/python /tmp/collect-python-licenses.py \
        /usr/share/doc/boltage/boltage-python-licenses /tmp/licenses \
    && rm -r /tmp/boltage /tmp/collect-python-licenses.py /tmp/licenses
COPY LICENSE THIRD_PARTY_NOTICES.md /usr/share/doc/boltage/
COPY --from=browser /src/LICENSE /src/NOTICE.txt /src/LICENSES.txt /neo4j-browser-source.tar.gz \
    /usr/share/doc/boltage/neo4j-browser/
ADD https://raw.githubusercontent.com/apache/age/${AGE_SOURCE_REF}/LICENSE \
    https://raw.githubusercontent.com/apache/age/${AGE_SOURCE_REF}/NOTICE \
    /usr/share/doc/boltage/apache-age/

COPY --from=browser /src/dist /opt/boltage/browser
COPY container/initdb/ /docker-entrypoint-initdb.d/
COPY container/pgadmin/config_distro.py /opt/boltage/pgadmin/config_distro.py
COPY container/boltage-entrypoint.sh container/boltage-start.sh /usr/local/bin/
RUN install -d -o postgres -g postgres -m 0700 /var/lib/boltage

ENV BOLTAGE_DEFAULT_GRAPH=neo4j \
    BOLTAGE_BROWSER_DIR=/opt/boltage/browser \
    BOLTAGE_HTTP_PORT=7474 \
    BOLTAGE_BOLT_PORT=7687 \
    BOLTAGE_PG_HOST=127.0.0.1 \
    BOLTAGE_PG_PORT=5432 \
    BOLTAGE_PGADMIN=true \
    BOLTAGE_PGADMIN_PORT=5050 \
    CONFIG_DISTRO_FILE_PATH=/opt/boltage/pgadmin/config_distro.py

# 7474: neo4j-browser (HTTP), 7687: Bolt, 5050: pgAdmin, 5432: PostgreSQL
EXPOSE 7474 7687 5050 5432

ENTRYPOINT ["/usr/local/bin/boltage-entrypoint.sh"]
CMD ["postgres", "-c", "shared_preload_libraries=age"]
