# Build the complete service set from the backend repository. Runtime images
# keep their real package/version metadata; security review measures their
# actual installed binaries, never a renamed package or a general allowlist.
# Build-only stage: the reviewed 1.3.2 backport recipe requires the exact
# 1.3.2-r0 distribution build inputs it was reviewed against, so it stays on
# the previous immutable base. Nothing from this base's packages ships.
FROM python:3.13.16-alpine3.24@sha256:1ac543fc677b1e24cfb220f2e9f2c73d6d9f1d5e718c2bbe5801cae34732f899 AS zlib-builder
RUN apk add --no-cache build-base linux-headers clang compiler-rt llvm22
COPY ops/runtime_zlib /build/zlib-recipe
RUN python /build/zlib-recipe/build.py

FROM alpine:3.24.4@sha256:f59abe656b692d901e184be3445e084786602108599d2a51d229c0f5a48c71bf AS certificates
RUN apk add --no-cache ca-certificates-bundle \
    && mkdir -p /runtime/tmp /runtime/data /runtime/config \
    && chmod 1777 /runtime/tmp \
    && chown 1000:1000 /runtime/data /runtime/config

# Alpine's bash intentionally leaves /bin/sh to BusyBox. This local package
# owns only a symlink to the signed distribution bash; it provides the honest
# /bin/sh dependency when removing BusyBox. No third-party unsigned package is
# downloaded: installation of this generated package is network-disabled.
FROM alpine:3.24.4@sha256:f59abe656b692d901e184be3445e084786602108599d2a51d229c0f5a48c71bf AS shell-provider
RUN mkdir -p /provider/bin && ln -s bash /provider/bin/sh \
    && apk mkpkg --info name:genzly-binsh --info version:1.0.0-r0 --info arch:noarch \
       --info license:MIT --info depends:bash --info provides:/bin/sh --info replaces:busybox-binsh \
       --files /provider --output /genzly-binsh.apk

# Neither static service needs a shell, package manager, or C shared library.
FROM chrislusf/seaweedfs:4.53@sha256:ccad23e18639c8b98cee17e7100b95830a06077b56d8e5b006d6dcf8ec5e94a0 AS weed-upstream
FROM scratch AS storage
LABEL org.genzly.component="service:storage"
COPY --from=certificates /runtime/ /
COPY --from=weed-upstream /usr/bin/weed /usr/bin/weed
COPY --from=certificates /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
USER 1000:1000
ENTRYPOINT ["/usr/bin/weed"]

FROM livekit/livekit-server:v1.13.11@sha256:25cd902de7cacbd5f1f779f6a6ac1eae20ba8f56b0935934ce6b0ab80d1e3d20 AS livekit-upstream
FROM scratch AS livekit
LABEL org.genzly.component="service:livekit"
COPY --from=certificates /runtime/ /
COPY --from=livekit-upstream /livekit-server /livekit-server
COPY --from=certificates /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
USER 1000:1000
ENTRYPOINT ["/livekit-server"]

FROM golang:1.27.4-alpine3.24@sha256:0a5f7fe796599ff487605987432e7619ae45beeb2fba4c2ce0b907879932aebf AS caddy-builder
WORKDIR /build
ENV CGO_ENABLED=0 GOTOOLCHAIN=local
COPY ops/services/caddy/go.mod ops/services/caddy/go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY ops/services/caddy/main.go ops/services/caddy/prepare.sh ./
RUN --mount=type=cache,target=/go/pkg/mod sh ./prepare.sh
RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build go build -mod=readonly -modfile=/tmp/genzly-caddy-build/go.mod -trimpath -buildvcs=false -o /caddy .

FROM scratch AS caddy
LABEL org.genzly.component="service:caddy"
COPY --from=certificates /runtime/ /
ENV XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data
COPY --from=caddy-builder /caddy /usr/bin/caddy
COPY --from=certificates /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
COPY ops/services/caddy /opt/genzly-services/caddy
COPY --from=caddy-builder /tmp/genzly-caddy-module/modules/caddyhttp/celmatcher.go /opt/genzly-services/caddy/celmatcher.go
ENTRYPOINT ["/usr/bin/caddy"]
CMD ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

# The initializer and PostgreSQL need standard filesystem tools. Use GNU
# tools/bash instead of retaining BusyBox's unrelated HTTP client applet.
FROM alpine:3.24.4@sha256:f59abe656b692d901e184be3445e084786602108599d2a51d229c0f5a48c71bf AS init
LABEL org.genzly.component="service:init"
COPY --from=shell-provider /genzly-binsh.apk /tmp/genzly-binsh.apk
RUN apk add --no-cache bash coreutils alpine-baselayout-data \
    && apk add --no-network --allow-untrusted /tmp/genzly-binsh.apk \
    && rm -f /usr/bin/wget \
    && apk del apk-tools alpine-baselayout busybox-binsh busybox ssl_client \
    && rm /tmp/genzly-binsh.apk
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
CMD ["/bin/sh"]

FROM postgres:17.11-alpine3.24@sha256:3540c0362c809df084ffac0ae69fe794515f9de92692f02178bcdce0ef0302ac AS postgres
LABEL org.genzly.component="service:postgres"
COPY --from=shell-provider /genzly-binsh.apk /tmp/genzly-binsh.apk
# CVE-2026-4738: require Alpine's signed upstream zlib 1.4 (verified below by
# the reviewed upstream_fixed runtime state, not the 1.3.2 backport).
# The 11 Nov 2026 grype DB also reports fixed Alpine packages for krb5-libs and
# libxslt (CVE-2026-112314 family and CVE-2026-125350 / CVE-2026-87636 / CVE-2026-9947 / CVE-2025-10911).
RUN apk add --no-cache zlib=1.4-r0 krb5-libs=1.22.3-r0 libxslt=1.1.43-r4 bash coreutils findutils grep sed su-exec ca-certificates-bundle alpine-baselayout-data \
    && apk add --no-network --allow-untrusted /tmp/genzly-binsh.apk \
    && test "$(grep -c 'exec gosu postgres' /usr/local/bin/docker-entrypoint.sh)" = 1 \
    && sed -i 's/exec gosu postgres/exec su-exec postgres/' /usr/local/bin/docker-entrypoint.sh \
    && rm /usr/local/bin/gosu && rm -f /usr/bin/wget \
    && apk del apk-tools alpine-baselayout busybox-binsh busybox ssl_client \
    && rm /tmp/genzly-binsh.apk
COPY --from=zlib-builder /opt/genzly-zlib /opt/genzly-zlib
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
RUN ["/opt/genzly-zlib/regression", "1.4"]

FROM valkey/valkey:8.1@sha256:d2e18f3410b6f616de1417f570fa55261af2898b9c5b2cfb6781ce2373ea43d1 AS redis
LABEL org.genzly.component="service:redis"
RUN apk upgrade --no-cache && apk add --no-cache alpine-baselayout-data ca-certificates-bundle \
    && rm -f /usr/bin/wget \
    && apk del ca-certificates apk-tools alpine-baselayout busybox-binsh busybox ssl_client
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
USER 999:1000
ENTRYPOINT []
CMD ["/usr/local/bin/valkey-server", "/config/valkey.conf"]

FROM nginx:1.30.6-alpine3.24@sha256:583b7f2fce1cdb8da5ad5c39ebd3c33b98b87d493190e548bdee1fa8c619c311 AS nginx
LABEL org.genzly.component="service:nginx"
COPY --from=shell-provider /genzly-binsh.apk /tmp/genzly-binsh.apk
# CVE-2026-103111: require the signed distribution's fixed PCRE2 release.
# Installing only additional packages does not upgrade this base dependency.
RUN apk add --no-cache pcre2=10.49-r0 zlib=1.4-r0 bash ca-certificates-bundle alpine-baselayout-data \
    && apk add --no-network --allow-untrusted /tmp/genzly-binsh.apk \
    && rm -f /usr/bin/wget \
    && apk del nginx-module-acme nginx-module-geoip nginx-module-image-filter nginx-module-njs nginx-module-xslt \
       curl gettext-envsubst ca-certificates apk-tools alpine-baselayout busybox-binsh busybox ssl_client \
    && /bin/bash -c 'test ! -e /bin/busybox; test ! -e /usr/bin/wget'
COPY --from=zlib-builder /opt/genzly-zlib /opt/genzly-zlib
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
RUN ["/opt/genzly-zlib/regression", "1.4"]
USER 101:101
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]

FROM python:3.13.18-alpine3.24@sha256:1e1f6334529d1fb26a2ef619d7cffb30a7c7d7cc1cc7338ebee283a58d1aeaca AS synapse-builder
COPY --from=ghcr.io/astral-sh/uv:0.12.10@sha256:2bb3ebca0a796a155094a27773d290c4b074572e6107f171d88d086682fd2500 /uv /bin/uv
RUN apk add --no-cache build-base libpq-dev
WORKDIR /build
COPY ops/services/synapse/pyproject.toml ops/services/synapse/uv.lock ./
RUN uv export --frozen --no-dev --only-group build --no-emit-project --output-file /build-tools.txt \
    && uv pip install --system --require-hashes --no-deps --requirements /build-tools.txt \
    && uv export --frozen --no-dev --no-emit-project --output-file /runtime.txt \
    && uv pip install --prefix /install --require-hashes --no-deps --no-build-isolation --requirements /runtime.txt

FROM python:3.13.18-alpine3.24@sha256:1e1f6334529d1fb26a2ef619d7cffb30a7c7d7cc1cc7338ebee283a58d1aeaca AS synapse
LABEL org.genzly.component="service:synapse"
RUN apk upgrade --no-cache && apk add --no-cache libpq libstdc++ ca-certificates-bundle alpine-baselayout-data \
    && addgroup -g 991 -S synapse && adduser -D -u 991 -G synapse synapse
COPY --from=synapse-builder /install /usr/local
COPY --from=zlib-builder /opt/genzly-zlib /opt/genzly-zlib
COPY ops/runtime_zlib /app/ops/runtime_zlib
COPY ops/runtime_security /app/ops/runtime_security
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
COPY ops/services/synapse /opt/genzly-services/synapse
WORKDIR /app
RUN ["python", "-m", "ops.runtime_zlib.install"]
RUN ["python", "-m", "ops.runtime_security.install"]
RUN ["python", "-m", "ops.runtime_security.verify"]
RUN rm -f /usr/bin/wget && apk del ca-certificates apk-tools alpine-baselayout busybox-binsh busybox ssl_client
ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1 SYNAPSE_CONFIG_PATH=/config/synapse.yaml
USER 991:991
RUN ["python", "-m", "ops.runtime_zlib.verify"]
ENTRYPOINT ["python", "/opt/genzly-services/synapse/start.py"]

FROM alpine:3.24.4@sha256:f59abe656b692d901e184be3445e084786602108599d2a51d229c0f5a48c71bf AS scanner
LABEL org.genzly.component="service:scanner"
COPY --from=shell-provider /genzly-binsh.apk /tmp/genzly-binsh.apk
RUN apk add --no-cache zlib=1.4-r0 clamav=1.4.6-r0 clamav-daemon=1.4.6-r0 clamav-clamdscan=1.4.6-r0 \
       freshclam=1.4.6-r0 bash coreutils tini ca-certificates-bundle alpine-baselayout-data \
    && apk add --no-network --allow-untrusted /tmp/genzly-binsh.apk \
    && mkdir -p /var/lib/clamav \
    && chown clamav:clamav /var/lib/clamav \
    && rm -f /usr/bin/wget \
    && apk del apk-tools alpine-baselayout busybox-binsh busybox ssl_client \
    && rm /tmp/genzly-binsh.apk
COPY --from=zlib-builder /opt/genzly-zlib /opt/genzly-zlib
COPY ops/services/Dockerfile /opt/genzly-services/Dockerfile
COPY --chmod=0755 ops/services/scanner/init-unprivileged /init-unprivileged
COPY ops/services/scanner/freshclam.conf /etc/clamav/freshclam.conf
COPY ops/clamav/clamd.conf /etc/clamav/clamd.conf
RUN ["/opt/genzly-zlib/regression", "1.4"]
USER clamav
ENTRYPOINT ["/sbin/tini", "-g", "--", "/init-unprivileged"]
HEALTHCHECK --interval=30s --timeout=5s --start-period=180s --retries=3 CMD ["clamdscan", "--ping=1", "--config-file=/etc/clamav/clamd.conf"]
