mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-02-01 20:10:35 +01:00
# Description of Changes This pull request introduces several improvements focused on security and reliability in both the Docker build process and the backend API. The most significant changes are the use of digest-pinned Docker base images to ensure reproducible builds, safer handling of user-provided filenames in error messages, and a switch to more reliable dependency installation in CI workflows. **Docker image security and reproducibility:** * All Dockerfiles now use digest-pinned base images (e.g., `node:20-alpine@sha256:...`, `gradle:8.14-jdk21@sha256:...`, `alpine:3.22.1@sha256:...`, `nginx:alpine@sha256:...`) to guarantee build consistency and protect against upstream image changes. [[1]](diffhunk://#diff-f8faae0938488156cf26e9322ffdf755deaa8770a7ac8c524dd6126c19548888L5-R5) [[2]](diffhunk://#diff-f8faae0938488156cf26e9322ffdf755deaa8770a7ac8c524dd6126c19548888L18-R18) [[3]](diffhunk://#diff-f8faae0938488156cf26e9322ffdf755deaa8770a7ac8c524dd6126c19548888L38-R38) [[4]](diffhunk://#diff-2f5cd3ad965c86a7a5b4af6e0513ad294e0426644d9f5b5358dfb16a2ef995a7L5-R5) [[5]](diffhunk://#diff-2f5cd3ad965c86a7a5b4af6e0513ad294e0426644d9f5b5358dfb16a2ef995a7L18-R18) [[6]](diffhunk://#diff-2f5cd3ad965c86a7a5b4af6e0513ad294e0426644d9f5b5358dfb16a2ef995a7L37-R37) [[7]](diffhunk://#diff-e9edf3a05475d0721a0e65be1ba0eeb162ae972891b0f6d7e1285687efab1de0L9-R9) [[8]](diffhunk://#diff-fa0700cfd7d90d832649eb1d0503904564bb3b28c48972be7d9f17e4ce32a3dcL9-R9) [[9]](diffhunk://#diff-2e766aaf0c87e7b8a62d2a2986f6999c38cc35f677479e31b77d1b427c7aeef7L5-R5) [[10]](diffhunk://#diff-1726db0cbef194c9be3cba9825c0794802b154e15e4c892c1544d0aace03e037L5-R5) [[11]](diffhunk://#diff-c1b6dd504a16fc68cd064baf9cf07d9dd31da56eb55de69601844ab03a5ae319L5-R5) [[12]](diffhunk://#diff-2fc7fcfcfdbb617dd8fbb6b1a2ea5709f9018d618d13942cb33d3e0ed127df16L5-R5) [[13]](diffhunk://#diff-2fc7fcfcfdbb617dd8fbb6b1a2ea5709f9018d618d13942cb33d3e0ed127df16L39-R39) [[14]](diffhunk://#diff-759e94102d21fe6f9bde8ddb0b4f95b5d5cd214b0355ea0419d3ea6c09e8ffbfL2-R2) [[15]](diffhunk://#diff-759e94102d21fe6f9bde8ddb0b4f95b5d5cd214b0355ea0419d3ea6c09e8ffbfL19-R19) **Backend API security:** * In `ConvertEmlToPDF.java`, error messages now escape user-provided filenames using `HtmlUtils.htmlEscape`, preventing potential XSS vulnerabilities when displaying error messages that include filenames. [[1]](diffhunk://#diff-45d22a96bae3e8a746b7fb2c39e25c80aee0bf733b528a3517db8fdd2a3d25cdR13) [[2]](diffhunk://#diff-45d22a96bae3e8a746b7fb2c39e25c80aee0bf733b528a3517db8fdd2a3d25cdR156-R170) **CI/CD reliability:** * All GitHub Actions workflows (`multiOSReleases.yml`, `releaseArtifacts.yml`, `tauri-build.yml`) now use `npm ci` instead of `npm install` for frontend dependency installation, ensuring clean, reproducible installs that match the lockfile. [[1]](diffhunk://#diff-895b214ee023c8c26048a2a3b946cfb1ebc4f26fbc8a9c2fa54b77c12e763b6bL271-R271) [[2]](diffhunk://#diff-699ff98fe113446c403eb07daf16dd1966c2a047ab0b9f7e38fd695d079f7dddL177-R177) [[3]](diffhunk://#diff-b34ab107dd4bc92075b2e89b6f16e4a2813e267ca7c2afebdb1931a0a3900d5aL177-R177) --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details.
193 lines
8.5 KiB
Docker
193 lines
8.5 KiB
Docker
# ==============================================================================
|
||
# Multi-stage Dockerfile for Stirling-PDF – image with everything included
|
||
# Includes: LibreOffice, Calibre, Tesseract, OCRmyPDF, unoserver, WeasyPrint, etc.
|
||
# ==============================================================================
|
||
|
||
# ========================================
|
||
# STAGE 1: Build stage - Alpine with Gradle
|
||
# ========================================
|
||
FROM gradle:8.14-jdk21@sha256:051d9a116793bdc5175a3f97a545718b750489eee85a7da20913c8a53f722a72 AS build
|
||
|
||
COPY build.gradle .
|
||
COPY settings.gradle .
|
||
COPY gradlew .
|
||
COPY gradle gradle/
|
||
COPY app/core/build.gradle core/.
|
||
COPY app/common/build.gradle common/.
|
||
COPY app/proprietary/build.gradle proprietary/.
|
||
RUN ./gradlew build -x spotlessApply -x spotlessCheck -x test -x sonarqube || return 0
|
||
|
||
# Set the working directory
|
||
WORKDIR /app
|
||
|
||
# Copy the entire project to the working directory
|
||
COPY . .
|
||
|
||
# Build the application (server-only JAR - no UI, includes security features controlled at runtime)
|
||
RUN DISABLE_ADDITIONAL_FEATURES=false \
|
||
STIRLING_PDF_DESKTOP_UI=false \
|
||
./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube
|
||
|
||
# ========================================
|
||
# STAGE 2: Runtime image based on Debian stable-slim
|
||
# Contains Java runtime + LibreOffice + Calibre + all PDF tools
|
||
# ========================================
|
||
FROM debian:stable-slim@sha256:7cb087f19bcc175b96fbe4c2aef42ed00733a659581a80f6ebccfd8fe3185a3d
|
||
|
||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||
ENV DEBIAN_FRONTEND=noninteractive
|
||
|
||
ENV TESS_BASE_PATH=/usr/share/tesseract-ocr/5/tessdata
|
||
|
||
# Install core runtime dependencies + tools required by Stirling-PDF features
|
||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||
ca-certificates tzdata tini bash fontconfig \
|
||
openjdk-21-jre-headless \
|
||
ffmpeg poppler-utils ocrmypdf \
|
||
libreoffice-nogui libreoffice-java-common \
|
||
python3 python3-venv python3-uno \
|
||
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
|
||
tesseract-ocr-por tesseract-ocr-chi-sim \
|
||
libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 \
|
||
gosu unpaper \
|
||
# AWT headless support (required for some Java graphics operations)
|
||
libfreetype6 libfontconfig1 libx11-6 libxt6 libxext6 libxrender1 libxtst6 libxi6 \
|
||
libxinerama1 libxkbcommon0 libxkbfile1 libsm6 libice6 \
|
||
# Qt WebEngine dependencies for Calibre
|
||
libegl1 libopengl0 libgl1 libxdamage1 libxfixes3 libxshmfence1 libdrm2 libgbm1 \
|
||
libxkbcommon-x11-0 libxrandr2 libxcomposite1 libnss3 libx11-xcb1 \
|
||
libxcb-cursor0 libdbus-1-3 libglib2.0-0 \
|
||
# Virtual framebuffer (required for headless LibreOffice)
|
||
xvfb x11-utils coreutils \
|
||
# Temporary packages only needed for Calibre installer
|
||
xz-utils gpgv curl xdg-utils \
|
||
\
|
||
# Install Calibre from official installer script
|
||
&& curl -fsSL https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin \
|
||
\
|
||
# Clean up installer-only packages
|
||
&& apt-get purge -y xz-utils gpgv xdg-utils \
|
||
&& apt-get autoremove -y \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
# Make ebook-convert available in PATH
|
||
RUN ln -sf /opt/calibre/ebook-convert /usr/bin/ebook-convert \
|
||
&& /opt/calibre/ebook-convert --version
|
||
|
||
# ==============================================================================
|
||
# Create non-root user (stirlingpdfuser) with configurable UID/GID
|
||
# ==============================================================================
|
||
ARG PUID=1000
|
||
ARG PGID=1000
|
||
|
||
RUN set -eux; \
|
||
# Create group if it doesn't exist
|
||
if ! getent group stirlingpdfgroup >/dev/null 2>&1; then \
|
||
if getent group "${PGID}" >/dev/null 2>&1; then \
|
||
groupadd -o -g "${PGID}" stirlingpdfgroup; \
|
||
else \
|
||
groupadd -g "${PGID}" stirlingpdfgroup; \
|
||
fi; \
|
||
fi; \
|
||
# Create user if it doesn't exist, avoid UID conflicts
|
||
if ! id -u stirlingpdfuser >/dev/null 2>&1; then \
|
||
if getent passwd | awk -F: -v id="${PUID}" '$3==id{found=1} END{exit !found}'; then \
|
||
echo "UID ${PUID} already in use – creating stirlingpdfuser with automatic UID"; \
|
||
useradd -m -g stirlingpdfgroup -d /home/stirlingpdfuser -s /bin/bash stirlingpdfuser; \
|
||
else \
|
||
useradd -m -u "${PUID}" -g stirlingpdfgroup -d /home/stirlingpdfuser -s /bin/bash stirlingpdfuser; \
|
||
fi; \
|
||
fi
|
||
|
||
# Compatibility alias for older entrypoint scripts expecting su-exec
|
||
RUN ln -sf /usr/sbin/gosu /usr/local/bin/su-exec
|
||
|
||
# Copy application files from build stage
|
||
COPY --from=build --chown=stirlingpdfuser:stirlingpdfgroup /app/app/core/build/libs/*.jar /app.jar
|
||
COPY --from=build --chown=stirlingpdfuser:stirlingpdfgroup /app/build/libs/restart-helper.jar /restart-helper.jar
|
||
COPY scripts/ /scripts/
|
||
COPY app/core/src/main/resources/static/fonts/*.ttf /usr/share/fonts/truetype/
|
||
|
||
# Optional version tag (can be passed at build time)
|
||
ARG VERSION_TAG
|
||
|
||
LABEL org.opencontainers.image.title="Stirling-PDF Backend"
|
||
LABEL org.opencontainers.image.description="Backend service for Stirling-PDF - Java Spring Boot with PDF processing capabilities"
|
||
LABEL org.opencontainers.image.source="https://github.com/Stirling-Tools/Stirling-PDF"
|
||
LABEL org.opencontainers.image.licenses="MIT"
|
||
LABEL org.opencontainers.image.vendor="Stirling-Tools"
|
||
LABEL org.opencontainers.image.url="https://www.stirlingpdf.com"
|
||
LABEL org.opencontainers.image.documentation="https://docs.stirlingpdf.com"
|
||
LABEL maintainer="Stirling-Tools"
|
||
LABEL org.opencontainers.image.authors="Stirling-Tools"
|
||
LABEL org.opencontainers.image.version="${VERSION_TAG}"
|
||
LABEL org.opencontainers.image.keywords="PDF, manipulation, backend, API, Spring Boot"
|
||
|
||
# ==============================================================================
|
||
# Runtime environment variables
|
||
# ==============================================================================
|
||
ENV VERSION_TAG=$VERSION_TAG \
|
||
DISABLE_ADDITIONAL_FEATURES=true \
|
||
JAVA_BASE_OPTS="-XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/configs/heap_dumps \
|
||
-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 \
|
||
-XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 \
|
||
-XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70 \
|
||
-Djava.awt.headless=true" \
|
||
JAVA_CUSTOM_OPTS="" \
|
||
HOME=/home/stirlingpdfuser \
|
||
PUID=${PUID} \
|
||
PGID=${PGID} \
|
||
UMASK=022 \
|
||
UNO_PATH=/usr/lib/libreoffice/program \
|
||
STIRLING_TEMPFILES_DIRECTORY=/tmp/stirling-pdf \
|
||
TMPDIR=/tmp/stirling-pdf \
|
||
TEMP=/tmp/stirling-pdf \
|
||
TMP=/tmp/stirling-pdf
|
||
|
||
# ==============================================================================
|
||
# Python virtual environment for additional Python tools (WeasyPrint, OpenCV, etc.)
|
||
# ==============================================================================
|
||
RUN python3 -m venv /opt/venv --system-site-packages \
|
||
&& /opt/venv/bin/pip install --no-cache-dir weasyprint pdf2image opencv-python-headless \
|
||
&& /opt/venv/bin/python -c "import cv2; print('OpenCV version:', cv2.__version__)"
|
||
|
||
# Separate venv for unoserver (keeps it isolated)
|
||
RUN python3 -m venv /opt/unoserver-venv --system-site-packages \
|
||
&& /opt/unoserver-venv/bin/pip install --no-cache-dir unoserver
|
||
|
||
# Make unoserver tools available in main venv PATH
|
||
RUN ln -sf /opt/unoserver-venv/bin/unoconvert /opt/venv/bin/unoconvert \
|
||
&& ln -sf /opt/unoserver-venv/bin/unoserver /opt/venv/bin/unoserver
|
||
|
||
# Extend PATH to include both virtual environments
|
||
ENV PATH="/opt/venv/bin:/opt/unoserver-venv/bin:${PATH}"
|
||
|
||
# ==============================================================================
|
||
# Final permissions, directories and font cache
|
||
# ==============================================================================
|
||
RUN set -eux; \
|
||
chmod +x /scripts/*; \
|
||
mkdir -p /configs /configs/heap_dumps /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf; \
|
||
chown -R stirlingpdfuser:stirlingpdfgroup \
|
||
/home/stirlingpdfuser /configs /logs /customFiles /pipeline /tmp/stirling-pdf \
|
||
/app.jar /restart-helper.jar /usr/share/fonts/truetype /scripts; \
|
||
chmod -R 755 /tmp/stirling-pdf
|
||
|
||
# Rebuild font cache
|
||
RUN fc-cache -f -v
|
||
|
||
# Force Qt/WebEngine to run headlessly (required for Calibre in Docker)
|
||
ENV QT_QPA_PLATFORM=offscreen \
|
||
QTWEBENGINE_CHROMIUM_FLAGS="--disable-gpu --disable-dev-shm-usage"
|
||
|
||
# Expose web UI port
|
||
EXPOSE 8080/tcp
|
||
|
||
STOPSIGNAL SIGTERM
|
||
|
||
# Use tini as init (handles signals and zombies correctly)
|
||
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
||
|
||
# CMD is empty – actual start command is defined in init.sh
|
||
CMD []
|