# check=skip=FromPlatformFlagConstDisallowed # ^ The --platform=linux/amd64 pins below are DELIBERATE (Exoscale SKS # nodes are amd64). BuildKit lints a constant --platform as a smell; # here it is the fix. Silenced so a real warning is not lost in noise. # Bikoret Shoresh Engine โ€” Haskell root activation engine # Construction spec ยง1.1: GHC 9.6.4, Cabal 3.10 # Communicates with vav_pipeline via Erlang Port (stdin/stdout) # # PLATFORM PIN: see Dockerfile.vav_pipeline for the rationale. # Exoscale SKS = amd64; arm64 images cannot exec on the cluster. # === BUILD STAGE === FROM --platform=linux/amd64 haskell:9.6.4-slim AS build # haskell:9.6.4-slim is Debian Buster (EOL) โ€” use archive repos RUN sed -i 's|deb.debian.org/debian|archive.debian.org/debian|g' /etc/apt/sources.list && \ sed -i 's|deb.debian.org/debian-security|archive.debian.org/debian-security|g' /etc/apt/sources.list && \ sed -i '/buster-updates/d' /etc/apt/sources.list && \ apt-get update && apt-get install -y zlib1g-dev && rm -rf /var/lib/apt/lists/* WORKDIR /app # Copy cabal files first for dependency caching COPY shoresh-engine/shoresh-engine.cabal ./ COPY shoresh-engine/cabal.project.freeze ./ RUN cabal update && cabal build --only-dependencies # Copy source and build COPY shoresh-engine/ ./ RUN cabal build && \ cp $(cabal list-bin shoresh-engine) /usr/local/bin/shoresh-engine # === RUNTIME STAGE === FROM --platform=linux/amd64 ubuntu:jammy-20240125 RUN apt-get update && \ apt-get install -y --no-install-recommends \ libgmp10 zlib1g locales && \ rm -rf /var/lib/apt/lists/* && \ sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen # === UTF-8 IS LOAD-BEARING HERE === # This engine's entire job is Hebrew roots. GHC picks stdout's encoding # from the locale at startup; ubuntu:jammy with no locale set gives the # POSIX/C locale, i.e. ASCII, and the FIRST non-ASCII byte the engine # tries to write kills it: # Shoresh Engine ...: : commitBuffer: invalid argument # (cannot encode character '\8212') # It died on the em-dash in its own banner, before reading one root. # vav_pipeline's runtime stage has always set these three; this stage # did not, and shoresh-engine is the one component that CANNOT run # without them. Matches Dockerfile.vav_pipeline so both halves of the # Erlang Port speak the same encoding. ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 RUN useradd --create-home --shell /bin/bash bikoret USER bikoret WORKDIR /home/bikoret COPY --from=build /usr/local/bin/shoresh-engine ./shoresh-engine # L1 Torah filesystem โ€” baked into the image # L1 is read-only in fact, not only in name. Until 2026-10-04 the scroll # was copied in owned by the service user with its write bits on: the # process that reads Torah could also have rewritten it, and only the # SHA-256 check would have noticed afterwards. Owned by root, no write # bit for anyone; the service user can read and traverse, nothing more. USER root COPY --chown=root:root l1/ /mnt/torah/ RUN chmod -R a-w,a+rX /mnt/torah USER bikoret # L1 mount point ENV L1_MOUNT_POINT=/mnt/torah # The engine is invoked as an Erlang Port by vav_pipeline # In K8s, it runs as a sidecar or is called via the Port protocol CMD ["./shoresh-engine"]