0f3671f42d
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 23s
CI / integration (pull_request) Successful in 18s
CI / ui (pull_request) Successful in 45s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m5s
Replace the dictionary hot-reload with an online update flow in the GM console (/_gm/dictionary): the operator uploads scrabble-dawg-vX.Y.Z.tar.gz, previews the per-variant words added/removed against the active dictionary, and confirms to install + activate it. Versions are immutable; in-progress games keep their pinned version while new games use the new one. - engine: DiffWords (enumerate both DAWGs, decode only the differences), OpenFinder, Registry.Finder, DictFiles; OpenWithVersions skips the .staging area. - dictadmin: hardened release-archive validation + extraction (path-traversal, symlink, oversize, entry-count rejection) and staging -> install (atomic rename). - game: active dictionary version persisted in the dictionary_state singleton (single source of truth, restored on boot), concurrency-safe accessor. - storage: BACKEND_DICT_DIR is a named volume seeded from the image (nonroot-owned), so uploaded versions persist across redeploys; the build's DICT_VERSION labels the seed and equals the resident tag (BACKEND_DICT_VERSION). - docs: ARCHITECTURE §5, FUNCTIONAL (+ru), backend README, TESTING, PRERELEASE. Tests: engine + dictadmin unit; integration upload->preview->install->activate-> restart->pin->immutability->CSRF.
54 lines
2.7 KiB
Docker
54 lines
2.7 KiB
Docker
# Multi-stage build for the backend service. Mirrors platform/telegram/Dockerfile:
|
|
# a golang-alpine builder yields a static binary shipped on distroless nonroot.
|
|
#
|
|
# The dictionary DAWGs are baked in from the scrabble-dictionary release artifact
|
|
# — the same set the Go CI downloads — and BACKEND_DICT_DIR points the
|
|
# binary at them. The published solver module is fetched directly from Gitea
|
|
# (GOPRIVATE), so the build stage needs git and network.
|
|
#
|
|
# Build from the repository root so go.work, go.work.sum, pkg/ and backend/ are all
|
|
# in the Docker context:
|
|
# docker build -f backend/Dockerfile -t scrabble-backend .
|
|
|
|
# --- dictionary artifact -----------------------------------------------------
|
|
FROM alpine:3.20 AS dawg
|
|
ARG DICT_VERSION=v1.0.0
|
|
RUN apk add --no-cache curl tar
|
|
RUN mkdir -p /dawg \
|
|
&& curl -fsSL -o /tmp/dawg.tar.gz \
|
|
"https://gitea.iliadenisov.ru/developer/scrabble-dictionary/releases/download/${DICT_VERSION}/scrabble-dawg-${DICT_VERSION}.tar.gz" \
|
|
&& tar xzf /tmp/dawg.tar.gz -C /dawg
|
|
|
|
# --- build -------------------------------------------------------------------
|
|
FROM golang:1.26.3-alpine AS build
|
|
WORKDIR /src
|
|
# git: the published solver module is fetched from Gitea directly (GOPRIVATE).
|
|
RUN apk add --no-cache git
|
|
ENV GOPRIVATE=gitea.iliadenisov.ru/*
|
|
|
|
COPY go.work go.work.sum ./
|
|
COPY pkg ./pkg
|
|
COPY backend ./backend
|
|
|
|
# Reduce the workspace to what the backend needs: backend + pkg. loadtest and the
|
|
# gateway replace it requires are not in this context, so drop both.
|
|
RUN go work edit -dropuse=./gateway -dropuse=./platform/telegram -dropuse=./loadtest -dropreplace=scrabble/gateway@v0.0.0
|
|
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -o /out/backend ./backend/cmd/backend
|
|
|
|
# --- runtime -----------------------------------------------------------------
|
|
FROM gcr.io/distroless/static-debian12:nonroot
|
|
# Re-declare the build arg in this stage so it labels the seed dictionary. One
|
|
# DICT_VERSION drives both the artifact the dawg stage downloads and the version
|
|
# label the binary pins, so the resident version equals the release tag.
|
|
ARG DICT_VERSION=v1.0.0
|
|
COPY --from=build /out/backend /usr/local/bin/backend
|
|
# Own the seed dictionary as the nonroot runtime user (UID 65532): a named volume
|
|
# mounted at /opt/dawg inherits this ownership on first use, so the admin console
|
|
# can write new version subdirectories at runtime. The volume preserves uploaded
|
|
# versions across deploys and, once seeded, is not re-seeded — so after bootstrap
|
|
# every dictionary change goes through the console, not a rebuild (ARCHITECTURE.md §5).
|
|
COPY --from=dawg --chown=65532:65532 /dawg /opt/dawg
|
|
ENV BACKEND_DICT_DIR=/opt/dawg
|
|
ENV BACKEND_DICT_VERSION=${DICT_VERSION}
|
|
ENTRYPOINT ["/usr/local/bin/backend"]
|