diff --git a/roles/web-app-chess/config/main.yml b/roles/web-app-chess/config/main.yml index 72641cdb..05314fcf 100644 --- a/roles/web-app-chess/config/main.yml +++ b/roles/web-app-chess/config/main.yml @@ -21,7 +21,9 @@ features: server: csp: whitelist: {} - flags: {} + flags: + script-src-elem: + unsafe-inline: true domains: canonical: - "chess.{{ PRIMARY_DOMAIN }}" diff --git a/roles/web-app-chess/files/Dockerfile b/roles/web-app-chess/files/Dockerfile new file mode 100644 index 00000000..bf02d2f6 --- /dev/null +++ b/roles/web-app-chess/files/Dockerfile @@ -0,0 +1,69 @@ +# Multi-stage build for castling.club + +# Allow a dynamic base image version in both stages +ARG CHESS_VERSION + +# -------- Stage 1: build -------- +FROM node:${CHESS_VERSION} AS build + +# Build-time inputs +ARG CHESS_REPO_URL +ARG CHESS_REPO_REF + +RUN apt-get update && apt-get install -y --no-install-recommends \ + git ca-certificates openssl dumb-init python3 build-essential \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /src +RUN git clone --depth 1 --branch "${CHESS_REPO_REF}" "${CHESS_REPO_URL}" ./ + +# Prepare Yarn 4 as root (safe during build stage) +RUN corepack enable && corepack prepare yarn@4.9.1 --activate && yarn -v +RUN yarn install --immutable --inline-builds +RUN yarn build + +# -------- Stage 2: runtime -------- +FROM node:${CHESS_VERSION} + +# Runtime inputs (formerly Jinja variables) +ARG CHESS_ENTRYPOINT_REL +ARG CHESS_ENTRYPOINT_INT +ARG CHESS_APP_DATA_DIR +ARG CONTAINER_PORT + +WORKDIR /app + +# Minimal runtime deps + curl for healthcheck +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash openssl dumb-init postgresql-client ca-certificates curl \ + && rm -rf /var/lib/apt/lists/* + +# Copy built app +COPY --from=build /src /app + +# Install entrypoint +COPY ${CHESS_ENTRYPOINT_REL} ${CHESS_ENTRYPOINT_INT} +RUN chmod +x ${CHESS_ENTRYPOINT_INT} + +# Fix: enable Corepack/Yarn as root so shims land in /usr/local/bin +RUN corepack enable && corepack prepare yarn@4.9.1 --activate && yarn -v + +# Create writable dirs and set ownership +RUN mkdir -p ${CHESS_APP_DATA_DIR} /app/.yarn/cache /home/node \ + && chown -R node:node /app /home/node + +# Use project-local Yarn cache +ENV YARN_ENABLE_GLOBAL_CACHE=false \ + YARN_CACHE_FOLDER=/app/.yarn/cache \ + HOME=/home/node + +# Drop privileges +USER node + +# Expose the runtime port (build-time constant) +EXPOSE ${CONTAINER_PORT} + +ENTRYPOINT ["dumb-init", "--"] +# Use a shell so the value can be expanded reliably +ENV CHESS_ENTRYPOINT_INT=${CHESS_ENTRYPOINT_INT} +CMD ["sh","-lc","exec \"$CHESS_ENTRYPOINT_INT\""] diff --git a/roles/web-app-chess/templates/Dockerfile.j2 b/roles/web-app-chess/templates/Dockerfile.j2 deleted file mode 100644 index b0c13921..00000000 --- a/roles/web-app-chess/templates/Dockerfile.j2 +++ /dev/null @@ -1,52 +0,0 @@ -# Multi-stage build for castling.club -# Stage 1: build -FROM node:{{ CHESS_VERSION }} AS build - -ARG CHESS_REPO_URL={{ CHESS_REPO_URL }} -ARG CHESS_REPO_REF={{ CHESS_REPO_REF }} - -RUN apt-get update && apt-get install -y --no-install-recommends \ - git ca-certificates openssl dumb-init python3 build-essential \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /src -RUN git clone --depth 1 --branch "${CHESS_REPO_REF}" "${CHESS_REPO_URL}" ./ - -# Use Yarn 4 for the build -RUN corepack enable && corepack prepare yarn@4.9.1 --activate && yarn -v -RUN yarn install --immutable --inline-builds -RUN yarn build - -# Stage 2: runtime -FROM node:{{ CHESS_VERSION }} - -WORKDIR /app - -# Minimal runtime packages + dumb-init (+ curl for healthcheck) -RUN apt-get update && apt-get install -y --no-install-recommends \ - bash openssl dumb-init postgresql-client ca-certificates curl \ - && rm -rf /var/lib/apt/lists/* - -# Copy built app from builder -COPY --from=build /src /app - -# Entrypoint script (root so chmod works in /usr/local/bin) -COPY {{ CHESS_ENTRYPOINT_REL }} {{ CHESS_ENTRYPOINT_INT }} -RUN chmod +x {{ CHESS_ENTRYPOINT_INT }} - -# Create data dir for signing keys and Yarn cache; fix ownership -RUN mkdir -p {{ CHESS_APP_DATA_DIR }} /app/.yarn/cache /home/node \ - && chown -R node:node /app /home/node - -# Use project-local yarn cache (avoid /root/.yarn) -ENV YARN_ENABLE_GLOBAL_CACHE=false -ENV YARN_CACHE_FOLDER=/app/.yarn/cache - -# Switch to non-root and prep yarn 4 -USER node -ENV HOME=/home/node -RUN corepack enable && corepack prepare yarn@4.9.1 --activate && yarn -v - -EXPOSE {{ container_port }} -ENTRYPOINT ["dumb-init", "--"] -CMD ["{{ CHESS_ENTRYPOINT_INT }}"] diff --git a/roles/web-app-chess/templates/docker-compose.yml.j2 b/roles/web-app-chess/templates/docker-compose.yml.j2 index 3649e7f6..59412d4e 100644 --- a/roles/web-app-chess/templates/docker-compose.yml.j2 +++ b/roles/web-app-chess/templates/docker-compose.yml.j2 @@ -4,8 +4,13 @@ context: . dockerfile: Dockerfile args: + CHESS_VERSION: "{{ CHESS_VERSION }}" CHESS_REPO_URL: "{{ CHESS_REPO_URL }}" CHESS_REPO_REF: "{{ CHESS_REPO_REF }}" + CHESS_ENTRYPOINT_REL: "{{ CHESS_ENTRYPOINT_REL }}" + CHESS_ENTRYPOINT_INT: "{{ CHESS_ENTRYPOINT_INT }}" + CHESS_APP_DATA_DIR: "{{ CHESS_APP_DATA_DIR }}" + CONTAINER_PORT: "{{ container_port | string }}" image: "{{ CHESS_CUSTOM_IMAGE }}" container_name: "{{ CHESS_CONTAINER }}" hostname: "{{ CHESS_HOSTNAME }}"