From 90fc571eb45020297f5b0f82b6b642ba8e2fbee5 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 09:46:36 -0400 Subject: [PATCH 01/10] Use hashes for each later + set USER --- docker/Dockerfile | 113 +++++++++++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 36 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index c420ca4c0..b30c70767 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -11,26 +11,32 @@ # - dev-slim: Slim image with development dependencies # - dev-full: Full image with emulator stage and development dependencies -# Versions: + +# ARGUMENT DECLARATIONS ARG ALPINE_VERSION=3.22 -ARG NGINX_VERSION=1.29.0 -ARG NODE_VERSION=20.19 +ARG ALPINE_HASH=4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1 + ARG PYTHON_VERSION=3.13 +ARG PYTHON_ALPINE_HASH=9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844 -# Alias stages: -FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} AS python-alias +FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION}@sha256:${PYTHON_ALPINE_HASH} AS python-alias + +ARG NODE_VERSION=20.19 +ARG NODE_ALPINE_HASH=eabac870db94f7342d6c33560d6613f188bbcf4bbe1f4eb47d5e2a08e1a37722 -FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS frontend-build +# FROTNEND BUILD +FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}@sha256:${NODE_ALPINE_HASH} AS frontend-build WORKDIR /front COPY ./frontend/package*.json ./ -RUN npm ci +RUN npm ci --only=production --ignore-scripts --no-audit --no-fund COPY ./frontend ./ RUN npm run build +# BACKEND PYTHON BUILD FROM python-alias AS backend-build # git is needed to install streaming-form-data fork @@ -43,14 +49,18 @@ RUN apk add --no-cache \ mariadb-connector-c-dev \ musl-dev -COPY --from=ghcr.io/astral-sh/uv:0.7.19 /uv /uvx /bin/ + +ARG UV_VERSION=0.7.19 +ARG UV_HASH=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d + +# https://github.com/astral-sh/uv/pkgs/container/uv/452595714 +COPY --from=ghcr.io/astral-sh/uv:${UV_VERSION}-python${PYTHON_VERSION}-alpine@sha256:${UV_HASH} /uv /uvx /bin/ WORKDIR /src COPY ./pyproject.toml ./uv.lock /src/ RUN uv sync --locked --no-cache - FROM backend-build AS backend-dev-build # linux-headers is needed to install psutil @@ -60,48 +70,63 @@ RUN apk add --no-cache \ RUN uv sync --locked --no-cache --all-extras -FROM alpine:${ALPINE_VERSION} AS rahasher-build - +# CUSTOM RAHASHER FOR RETROACHIEVEMENTS +FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_HASH} AS rahasher-build RUN apk add --no-cache \ g++ \ - git \ linux-headers \ make \ + wget \ zlib-dev ARG RALIBRETRO_VERSION=1.8.1 +ARG RALIBRETRO_HASH=5e97ef4ed01414566befe0b58690b7461fbd04f7120b5c6194f87372c6fa98ed # TODO: Remove `sed` command adding "ctime", when RAHasher can be compiled without it. # TODO: Remove `sed` command adding "unistd.h", when RAHasher can be compiled without it. # Related pull request: https://github.com/madler/zlib/pull/1022 -RUN git clone --recursive --branch "${RALIBRETRO_VERSION}" --depth 1 https://github.com/RetroAchievements/RALibretro.git && \ +RUN wget "https://github.com/RetroAchievements/RALibretro/archive/refs/tags/${RALIBRETRO_VERSION}.zip" && \ + echo "${RALIBRETRO_HASH} ${RALIBRETRO_VERSION}.zip" | sha256sum -c - && \ + unzip -q "${RALIBRETRO_VERSION}.zip" && \ + mv "RALibretro-${RALIBRETRO_VERSION}" RALibretro && \ + rm "${RALIBRETRO_VERSION}.zip" && \ cd ./RALibretro && \ sed -i '22a #include ' ./src/Util.h && \ sed -i '6a #include ' \ - ./src/libchdr/deps/zlib-1.3.1/gzlib.c \ - ./src/libchdr/deps/zlib-1.3.1/gzread.c \ - ./src/libchdr/deps/zlib-1.3.1/gzwrite.c && \ + ./src/libchdr/deps/zlib-1.3.1/gzlib.c \ + ./src/libchdr/deps/zlib-1.3.1/gzread.c \ + ./src/libchdr/deps/zlib-1.3.1/gzwrite.c && \ make HAVE_CHD=1 -f ./Makefile.RAHasher -FROM alpine:${ALPINE_VERSION} AS emulator-stage +# FETCH EMULATORJS AND RUFFLE +FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_HASH} AS emulator-stage RUN apk add --no-cache \ 7zip \ - wget + wget \ + ca-certificates ARG EMULATORJS_VERSION=4.2.3 +ARG EMULATORJS_HASH=07d451bc06fa3ad04ab30d9b94eb63ac34ad0babee52d60357b002bde8f3850b + RUN wget "https://github.com/EmulatorJS/EmulatorJS/releases/download/v${EMULATORJS_VERSION}/${EMULATORJS_VERSION}.7z" && \ + echo "${EMULATORJS_HASH} ${EMULATORJS_VERSION}.7z" | sha256sum -c - && \ 7z x -y "${EMULATORJS_VERSION}.7z" -o/emulatorjs && \ - rm -rf "${EMULATORJS_VERSION}.7z"; + rm -f "${EMULATORJS_VERSION}.7z" ARG RUFFLE_VERSION=nightly-2025-08-14 ARG RUFFLE_FILE=ruffle-nightly-2025_08_14-web-selfhosted.zip -RUN wget "https://github.com/ruffle-rs/ruffle/releases/download/${RUFFLE_VERSION}/${RUFFLE_FILE}" && \ - unzip -o "${RUFFLE_FILE}" -d /ruffle && \ - rm -f "${RUFFLE_FILE}"; +ARG RUFFLE_HASH=178870c5e7dd825a8df35920dfc5328d83e53f3c4d5d95f70b1ea9cd13494151 -FROM alpine:${ALPINE_VERSION} AS nginx-build +RUN wget "https://github.com/ruffle-rs/ruffle/releases/download/${RUFFLE_VERSION}/${RUFFLE_FILE}" && \ + echo "${RUFFLE_HASH} ${RUFFLE_FILE}" | sha256sum -c - && \ + unzip -o "${RUFFLE_FILE}" -d /ruffle && \ + rm -f "${RUFFLE_FILE}" + + +# BUILD NGINX MODULE WITH MOD_ZIP +FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_HASH} AS nginx-build RUN apk add --no-cache \ gcc \ @@ -109,32 +134,38 @@ RUN apk add --no-cache \ libc-dev \ make \ pcre-dev \ + wget \ zlib-dev -ARG NGINX_VERSION +ARG NGINX_VERSION=1.29.1 +ARG NGINX_HASH=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 # The specified commit SHA is the latest commit on the `master` branch at the time of writing. # It includes a fix to correctly calculate CRC-32 checksums when using upstream subrequests. # TODO: Move to a tagged release of `mod_zip`, once a version newer than 1.3.0 is released. -ARG NGINX_MOD_ZIP_SHA=a9f9afa441117831cc712a832c98408b3f0416f6 +ARG NGINX_MOD_ZIP_HASH=a9f9afa441117831cc712a832c98408b3f0416f6 +ARG NGINX_RELEASE_HASH=87726e2e3b021ee9f7f0f709c49308ce275c5e44d2625841f3d9f948385494c5 -# Clone both nginx and `ngx_http_zip_module` repositories, needed to compile the module from source. +# Clone `ngx_http_zip_module` repository and download nginx source, needed to compile the module from source. # This is needed to be able to dinamically load it as a module in the final image. `nginx` Docker # images do not have a simple way to include third-party modules. RUN git clone https://github.com/evanmiller/mod_zip.git && \ cd ./mod_zip && \ - git checkout "${NGINX_MOD_ZIP_SHA}" && \ + git checkout "${NGINX_MOD_ZIP_HASH}" && \ cd ../ && \ - git clone --branch "release-${NGINX_VERSION}" --depth 1 https://github.com/nginx/nginx.git && \ - cd ./nginx && \ + wget "https://github.com/nginx/nginx/releases/download/release-${NGINX_VERSION}/nginx-${NGINX_VERSION}.zip" && \ + echo "${NGINX_RELEASE_HASH} nginx-${NGINX_VERSION}.zip" | sha256sum -c - && \ + unzip -q "nginx-${NGINX_VERSION}.zip" && \ + rm "nginx-${NGINX_VERSION}.zip" && \ + cd "./nginx-${NGINX_VERSION}" && \ ./auto/configure --with-compat --add-dynamic-module=../mod_zip/ && \ make -f ./objs/Makefile modules && \ chmod 644 ./objs/ngx_http_zip_module.so -FROM nginx:${NGINX_VERSION}-alpine${ALPINE_VERSION} AS production-stage +# PRODUCTION STAGE +FROM nginx:${NGINX_VERSION}-alpine${ALPINE_VERSION}-slim@sha256:${NGINX_HASH} AS production-stage ARG WEBSERVER_FOLDER=/var/www/html -# Install required packages and dependencies RUN apk add --no-cache \ bash \ libmagic \ @@ -148,7 +179,6 @@ RUN apk add --no-cache \ # Python version, which could not be the same as the one used in the backend build stage. # TODO: Replace with a bundled installation of Python using `uv`, when it is supported. # Related issue: https://github.com/astral-sh/uv/issues/7865 -ARG PYTHON_VERSION COPY --from=python-alias /usr/lib/* /usr/lib/ COPY --from=python-alias /usr/local/bin/* /usr/local/bin/ COPY --from=python-alias /usr/local/include/python${PYTHON_VERSION} /usr/local/include/python${PYTHON_VERSION} @@ -175,13 +205,15 @@ COPY ./docker/gunicorn/logging.conf /etc/gunicorn/logging.conf # User permissions # - Create default user `romm` (1000) and group `romm` (1000). # - Create base directories and make default user/group the owner. -# - Make nginx configuration files writable by everyone, for `envsubst` to work -# when a custom UID/GID is used. +# - Make nginx configuration files writable by everyone for `envsubst` to work RUN addgroup -g 1000 -S romm && adduser -u 1000 -D -S -G romm romm && \ - mkdir /romm /redis-data && chown romm:romm /romm /redis-data && \ + mkdir /romm /redis-data && \ + chown romm:romm /romm /redis-data && \ + chmod 750 /romm /redis-data && \ chmod -R a+w /etc/nginx/conf.d +# SLIM IMAGE FROM scratch AS slim-image COPY --from=production-stage / / @@ -190,10 +222,18 @@ COPY --from=backend-build /src/.venv /src/.venv ENV PATH="/src/.venv/bin:${PATH}" +# Security: Set security-focused environment variables +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV PYTHONPATH=/backend + +# Use non-root user by default +USER romm + # Declare the supported volumes VOLUME ["/romm/resources", "/romm/library", "/romm/assets", "/romm/config", "/redis-data"] -# Expose ports and start +# Expose non-privileged ports EXPOSE 8080 6379/tcp WORKDIR /romm @@ -201,6 +241,7 @@ ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["/init"] +# FULL IMAGE FROM slim-image AS full-image ARG WEBSERVER_FOLDER=/var/www/html COPY --from=emulator-stage /emulatorjs ${WEBSERVER_FOLDER}/assets/emulatorjs From 92ca3d899cef36d08ecfe1718321c0f6cfcb5bd3 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 09:55:02 -0400 Subject: [PATCH 02/10] pin docker uses to immutable versions --- .github/workflows/build.yml | 18 +++++++++--------- .github/workflows/i18n.yml | 4 ++-- .github/workflows/pytest.yml | 6 +++--- .github/workflows/test-build.yml | 12 ++++++------ .github/workflows/trunk-check.yml | 4 ++-- .github/workflows/typecheck.yml | 4 ++-- .trunk/setup-ci/action.yaml | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e88c39ce9..c3b497f74 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,22 +42,22 @@ jobs: run: echo "Triggered by ${{ github.event_name }}" - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v4.3.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v3.6.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v3.11.1 - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v3.5.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@v3.5.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -65,7 +65,7 @@ jobs: - name: Generate Docker metadata (slim) id: meta-slim - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v5.8.0 with: images: | name=rommapp/romm @@ -85,7 +85,7 @@ jobs: - name: Generate Docker metadata (full) id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v5.8.0 with: images: | name=rommapp/romm @@ -106,7 +106,7 @@ jobs: - name: Build slim image id: build-slim - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v6.18.0 with: file: docker/Dockerfile context: . @@ -118,7 +118,7 @@ jobs: - name: Build full image id: build-full - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v6.18.0 with: file: docker/Dockerfile context: . diff --git a/.github/workflows/i18n.yml b/.github/workflows/i18n.yml index f513c62d0..de0a94b82 100644 --- a/.github/workflows/i18n.yml +++ b/.github/workflows/i18n.yml @@ -13,10 +13,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v4.3.0 - name: Set up Python 3.13 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6.0.0 with: python-version: "3.13" diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 51c857d23..ba998fdde 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -31,7 +31,7 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v4.3.0 - name: Install mariadb connectors run: | @@ -39,7 +39,7 @@ jobs: sudo apt-get install -y libmariadb3 libmariadb-dev - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v6.7.0 - name: Install python run: | @@ -62,7 +62,7 @@ jobs: uv run pytest -vv --maxfail=10 --junitxml=pytest-report.xml --cov --cov-report xml:coverage.xml --cov-config=.coveragerc . - name: Publish test results - uses: EnricoMi/publish-unit-test-result-action/linux@v2 + uses: EnricoMi/publish-unit-test-result-action/linux@sha-3a74b29 if: (!cancelled()) with: files: | diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index f1714fcdc..089585b82 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -26,26 +26,26 @@ jobs: run: echo "Triggered by ${{ github.event_name }}" - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v4.3.0 with: ref: ${{ github.event.inputs.branch }} fetch-depth: 0 - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v3.6.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v3.11.1 - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v3.5.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Generate Docker metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v5.8.0 with: images: | name=rommapp/romm-testing @@ -54,7 +54,7 @@ jobs: - name: Build full image id: build-full - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v6.18.0 with: file: docker/Dockerfile context: . diff --git a/.github/workflows/trunk-check.yml b/.github/workflows/trunk-check.yml index 033b4bea5..e5c4f8dab 100644 --- a/.github/workflows/trunk-check.yml +++ b/.github/workflows/trunk-check.yml @@ -17,6 +17,6 @@ jobs: contents: read # For repo checkout steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v4.3.0 - name: Trunk Check - uses: trunk-io/trunk-action@v1 + uses: trunk-io/trunk-action@v1.2.4 diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 4d6bf4e5b..a9a826ce0 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -20,10 +20,10 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v4.3.0 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5.0.0 with: node-version: "18" diff --git a/.trunk/setup-ci/action.yaml b/.trunk/setup-ci/action.yaml index b0b37da43..0021cf330 100644 --- a/.trunk/setup-ci/action.yaml +++ b/.trunk/setup-ci/action.yaml @@ -5,7 +5,7 @@ runs: using: composite steps: - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@v5.0.0 with: node-version: 18 From d91be2c16a508630853d2e7b79984d53fb831419 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 10:25:19 -0400 Subject: [PATCH 03/10] first attempt to fix build failure --- docker/Dockerfile | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b30c70767..ac85a01fd 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -15,14 +15,17 @@ # ARGUMENT DECLARATIONS ARG ALPINE_VERSION=3.22 ARG ALPINE_HASH=4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1 - ARG PYTHON_VERSION=3.13 ARG PYTHON_ALPINE_HASH=9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844 - -FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION}@sha256:${PYTHON_ALPINE_HASH} AS python-alias - ARG NODE_VERSION=20.19 ARG NODE_ALPINE_HASH=eabac870db94f7342d6c33560d6613f188bbcf4bbe1f4eb47d5e2a08e1a37722 +ARG NGINX_VERSION=1.29.1 +ARG NGINX_HASH=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 +ARG UV_VERSION=0.7.19 +ARG UV_HASH=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d + + +FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION}@sha256:${PYTHON_ALPINE_HASH} AS python-alias # FROTNEND BUILD @@ -36,6 +39,10 @@ COPY ./frontend ./ RUN npm run build +# https://github.com/astral-sh/uv/pkgs/container/uv/452595714 +FROM ghcr.io/astral-sh/uv:${UV_VERSION}-python${PYTHON_VERSION}-alpine@sha256:${UV_HASH} AS uv-stage + + # BACKEND PYTHON BUILD FROM python-alias AS backend-build @@ -49,12 +56,7 @@ RUN apk add --no-cache \ mariadb-connector-c-dev \ musl-dev - -ARG UV_VERSION=0.7.19 -ARG UV_HASH=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d - -# https://github.com/astral-sh/uv/pkgs/container/uv/452595714 -COPY --from=ghcr.io/astral-sh/uv:${UV_VERSION}-python${PYTHON_VERSION}-alpine@sha256:${UV_HASH} /uv /uvx /bin/ +COPY --from=uv-stage /uv /uvx /bin/ WORKDIR /src @@ -137,8 +139,6 @@ RUN apk add --no-cache \ wget \ zlib-dev -ARG NGINX_VERSION=1.29.1 -ARG NGINX_HASH=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 # The specified commit SHA is the latest commit on the `master` branch at the time of writing. # It includes a fix to correctly calculate CRC-32 checksums when using upstream subrequests. # TODO: Move to a tagged release of `mod_zip`, once a version newer than 1.3.0 is released. @@ -179,6 +179,7 @@ RUN apk add --no-cache \ # Python version, which could not be the same as the one used in the backend build stage. # TODO: Replace with a bundled installation of Python using `uv`, when it is supported. # Related issue: https://github.com/astral-sh/uv/issues/7865 +ARG PYTHON_VERSION COPY --from=python-alias /usr/lib/* /usr/lib/ COPY --from=python-alias /usr/local/bin/* /usr/local/bin/ COPY --from=python-alias /usr/local/include/python${PYTHON_VERSION} /usr/local/include/python${PYTHON_VERSION} From 57e488d8b43c971076a1499f02c52dbc940ef190 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 10:39:55 -0400 Subject: [PATCH 04/10] copy from uv image direct --- docker/Dockerfile | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index ac85a01fd..9f6df2afb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -14,22 +14,22 @@ # ARGUMENT DECLARATIONS ARG ALPINE_VERSION=3.22 -ARG ALPINE_HASH=4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1 +ARG ALPINE_SHA256=4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1 ARG PYTHON_VERSION=3.13 -ARG PYTHON_ALPINE_HASH=9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844 +ARG PYTHON_ALPINE_SHA256=9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844 ARG NODE_VERSION=20.19 -ARG NODE_ALPINE_HASH=eabac870db94f7342d6c33560d6613f188bbcf4bbe1f4eb47d5e2a08e1a37722 +ARG NODE_ALPINE_SHA256=eabac870db94f7342d6c33560d6613f188bbcf4bbe1f4eb47d5e2a08e1a37722 ARG NGINX_VERSION=1.29.1 -ARG NGINX_HASH=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 +ARG NGINX_SHA256=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 ARG UV_VERSION=0.7.19 -ARG UV_HASH=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d +ARG UV_SHA256=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d -FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION}@sha256:${PYTHON_ALPINE_HASH} AS python-alias +FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION}@sha256:${PYTHON_ALPINE_SHA256} AS python-alias # FROTNEND BUILD -FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}@sha256:${NODE_ALPINE_HASH} AS frontend-build +FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}@sha256:${NODE_ALPINE_SHA256} AS frontend-build WORKDIR /front COPY ./frontend/package*.json ./ @@ -40,7 +40,7 @@ RUN npm run build # https://github.com/astral-sh/uv/pkgs/container/uv/452595714 -FROM ghcr.io/astral-sh/uv:${UV_VERSION}-python${PYTHON_VERSION}-alpine@sha256:${UV_HASH} AS uv-stage +FROM ghcr.io/astral-sh/uv:${UV_VERSION}-python${PYTHON_VERSION}-alpine@sha256:${UV_SHA256} AS uv-stage # BACKEND PYTHON BUILD @@ -56,7 +56,7 @@ RUN apk add --no-cache \ mariadb-connector-c-dev \ musl-dev -COPY --from=uv-stage /uv /uvx /bin/ +COPY --from=uv-stage /usr/local/bin/uv /usr/local/bin/uvx /bin/ WORKDIR /src @@ -73,7 +73,7 @@ RUN uv sync --locked --no-cache --all-extras # CUSTOM RAHASHER FOR RETROACHIEVEMENTS -FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_HASH} AS rahasher-build +FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_SHA256} AS rahasher-build RUN apk add --no-cache \ g++ \ linux-headers \ @@ -82,13 +82,13 @@ RUN apk add --no-cache \ zlib-dev ARG RALIBRETRO_VERSION=1.8.1 -ARG RALIBRETRO_HASH=5e97ef4ed01414566befe0b58690b7461fbd04f7120b5c6194f87372c6fa98ed +ARG RALIBRETRO_SHA256=5e97ef4ed01414566befe0b58690b7461fbd04f7120b5c6194f87372c6fa98ed # TODO: Remove `sed` command adding "ctime", when RAHasher can be compiled without it. # TODO: Remove `sed` command adding "unistd.h", when RAHasher can be compiled without it. # Related pull request: https://github.com/madler/zlib/pull/1022 RUN wget "https://github.com/RetroAchievements/RALibretro/archive/refs/tags/${RALIBRETRO_VERSION}.zip" && \ - echo "${RALIBRETRO_HASH} ${RALIBRETRO_VERSION}.zip" | sha256sum -c - && \ + echo "${RALIBRETRO_SHA256} ${RALIBRETRO_VERSION}.zip" | sha256sum -c - && \ unzip -q "${RALIBRETRO_VERSION}.zip" && \ mv "RALibretro-${RALIBRETRO_VERSION}" RALibretro && \ rm "${RALIBRETRO_VERSION}.zip" && \ @@ -102,7 +102,7 @@ RUN wget "https://github.com/RetroAchievements/RALibretro/archive/refs/tags/${RA # FETCH EMULATORJS AND RUFFLE -FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_HASH} AS emulator-stage +FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_SHA256} AS emulator-stage RUN apk add --no-cache \ 7zip \ @@ -110,25 +110,25 @@ RUN apk add --no-cache \ ca-certificates ARG EMULATORJS_VERSION=4.2.3 -ARG EMULATORJS_HASH=07d451bc06fa3ad04ab30d9b94eb63ac34ad0babee52d60357b002bde8f3850b +ARG EMULATORJS_SHA256=07d451bc06fa3ad04ab30d9b94eb63ac34ad0babee52d60357b002bde8f3850b RUN wget "https://github.com/EmulatorJS/EmulatorJS/releases/download/v${EMULATORJS_VERSION}/${EMULATORJS_VERSION}.7z" && \ - echo "${EMULATORJS_HASH} ${EMULATORJS_VERSION}.7z" | sha256sum -c - && \ + echo "${EMULATORJS_SHA256} ${EMULATORJS_VERSION}.7z" | sha256sum -c - && \ 7z x -y "${EMULATORJS_VERSION}.7z" -o/emulatorjs && \ rm -f "${EMULATORJS_VERSION}.7z" ARG RUFFLE_VERSION=nightly-2025-08-14 ARG RUFFLE_FILE=ruffle-nightly-2025_08_14-web-selfhosted.zip -ARG RUFFLE_HASH=178870c5e7dd825a8df35920dfc5328d83e53f3c4d5d95f70b1ea9cd13494151 +ARG RUFFLE_SHA256=178870c5e7dd825a8df35920dfc5328d83e53f3c4d5d95f70b1ea9cd13494151 RUN wget "https://github.com/ruffle-rs/ruffle/releases/download/${RUFFLE_VERSION}/${RUFFLE_FILE}" && \ - echo "${RUFFLE_HASH} ${RUFFLE_FILE}" | sha256sum -c - && \ + echo "${RUFFLE_SHA256} ${RUFFLE_FILE}" | sha256sum -c - && \ unzip -o "${RUFFLE_FILE}" -d /ruffle && \ rm -f "${RUFFLE_FILE}" # BUILD NGINX MODULE WITH MOD_ZIP -FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_HASH} AS nginx-build +FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_SHA256} AS nginx-build RUN apk add --no-cache \ gcc \ @@ -142,18 +142,18 @@ RUN apk add --no-cache \ # The specified commit SHA is the latest commit on the `master` branch at the time of writing. # It includes a fix to correctly calculate CRC-32 checksums when using upstream subrequests. # TODO: Move to a tagged release of `mod_zip`, once a version newer than 1.3.0 is released. -ARG NGINX_MOD_ZIP_HASH=a9f9afa441117831cc712a832c98408b3f0416f6 -ARG NGINX_RELEASE_HASH=87726e2e3b021ee9f7f0f709c49308ce275c5e44d2625841f3d9f948385494c5 +ARG NGINX_MOD_ZIP_SHA256=a9f9afa441117831cc712a832c98408b3f0416f6 +ARG NGINX_RELEASE_SHA256=87726e2e3b021ee9f7f0f709c49308ce275c5e44d2625841f3d9f948385494c5 # Clone `ngx_http_zip_module` repository and download nginx source, needed to compile the module from source. # This is needed to be able to dinamically load it as a module in the final image. `nginx` Docker # images do not have a simple way to include third-party modules. RUN git clone https://github.com/evanmiller/mod_zip.git && \ cd ./mod_zip && \ - git checkout "${NGINX_MOD_ZIP_HASH}" && \ + git checkout "${NGINX_MOD_ZIP_SHA256}" && \ cd ../ && \ wget "https://github.com/nginx/nginx/releases/download/release-${NGINX_VERSION}/nginx-${NGINX_VERSION}.zip" && \ - echo "${NGINX_RELEASE_HASH} nginx-${NGINX_VERSION}.zip" | sha256sum -c - && \ + echo "${NGINX_RELEASE_SHA256} nginx-${NGINX_VERSION}.zip" | sha256sum -c - && \ unzip -q "nginx-${NGINX_VERSION}.zip" && \ rm "nginx-${NGINX_VERSION}.zip" && \ cd "./nginx-${NGINX_VERSION}" && \ @@ -163,7 +163,7 @@ RUN git clone https://github.com/evanmiller/mod_zip.git && \ # PRODUCTION STAGE -FROM nginx:${NGINX_VERSION}-alpine${ALPINE_VERSION}-slim@sha256:${NGINX_HASH} AS production-stage +FROM nginx:${NGINX_VERSION}-alpine${ALPINE_VERSION}-slim@sha256:${NGINX_SHA256} AS production-stage ARG WEBSERVER_FOLDER=/var/www/html RUN apk add --no-cache \ From 1a41190fb832be9b3b4cf9ed02947dc484162bbf Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 11:01:51 -0400 Subject: [PATCH 05/10] add NGINX_VERSION to local --- docker/Dockerfile | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 9f6df2afb..61376e4ed 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -19,7 +19,7 @@ ARG PYTHON_VERSION=3.13 ARG PYTHON_ALPINE_SHA256=9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844 ARG NODE_VERSION=20.19 ARG NODE_ALPINE_SHA256=eabac870db94f7342d6c33560d6613f188bbcf4bbe1f4eb47d5e2a08e1a37722 -ARG NGINX_VERSION=1.29.1 +ARG NGINX_VERSION=1.29.0 ARG NGINX_SHA256=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 ARG UV_VERSION=0.7.19 ARG UV_SHA256=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d @@ -136,27 +136,23 @@ RUN apk add --no-cache \ libc-dev \ make \ pcre-dev \ - wget \ zlib-dev +ARG NGINX_VERSION # The specified commit SHA is the latest commit on the `master` branch at the time of writing. # It includes a fix to correctly calculate CRC-32 checksums when using upstream subrequests. # TODO: Move to a tagged release of `mod_zip`, once a version newer than 1.3.0 is released. -ARG NGINX_MOD_ZIP_SHA256=a9f9afa441117831cc712a832c98408b3f0416f6 -ARG NGINX_RELEASE_SHA256=87726e2e3b021ee9f7f0f709c49308ce275c5e44d2625841f3d9f948385494c5 +ARG NGINX_MOD_ZIP_COMMIT=a9f9afa441117831cc712a832c98408b3f0416f6 -# Clone `ngx_http_zip_module` repository and download nginx source, needed to compile the module from source. +# Clone both `nginx` and `ngx_http_zip_module` repositories, needed to compile the module from source. # This is needed to be able to dinamically load it as a module in the final image. `nginx` Docker # images do not have a simple way to include third-party modules. RUN git clone https://github.com/evanmiller/mod_zip.git && \ cd ./mod_zip && \ - git checkout "${NGINX_MOD_ZIP_SHA256}" && \ + git checkout "${NGINX_MOD_ZIP_COMMIT}" && \ cd ../ && \ - wget "https://github.com/nginx/nginx/releases/download/release-${NGINX_VERSION}/nginx-${NGINX_VERSION}.zip" && \ - echo "${NGINX_RELEASE_SHA256} nginx-${NGINX_VERSION}.zip" | sha256sum -c - && \ - unzip -q "nginx-${NGINX_VERSION}.zip" && \ - rm "nginx-${NGINX_VERSION}.zip" && \ - cd "./nginx-${NGINX_VERSION}" && \ + git clone --branch "release-${NGINX_VERSION}" --depth 1 https://github.com/nginx/nginx.git && \ + cd ./nginx && \ ./auto/configure --with-compat --add-dynamic-module=../mod_zip/ && \ make -f ./objs/Makefile modules && \ chmod 644 ./objs/ngx_http_zip_module.so From 536a5dd3dd068fba652a5a60a96b87b67f2c1fe9 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 11:35:22 -0400 Subject: [PATCH 06/10] atempt fix ralibretro --- docker/Dockerfile | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 61376e4ed..b617e186e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -19,7 +19,7 @@ ARG PYTHON_VERSION=3.13 ARG PYTHON_ALPINE_SHA256=9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844 ARG NODE_VERSION=20.19 ARG NODE_ALPINE_SHA256=eabac870db94f7342d6c33560d6613f188bbcf4bbe1f4eb47d5e2a08e1a37722 -ARG NGINX_VERSION=1.29.0 +ARG NGINX_VERSION=1.29.1 ARG NGINX_SHA256=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 ARG UV_VERSION=0.7.19 ARG UV_SHA256=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d @@ -78,26 +78,20 @@ RUN apk add --no-cache \ g++ \ linux-headers \ make \ - wget \ zlib-dev ARG RALIBRETRO_VERSION=1.8.1 -ARG RALIBRETRO_SHA256=5e97ef4ed01414566befe0b58690b7461fbd04f7120b5c6194f87372c6fa98ed # TODO: Remove `sed` command adding "ctime", when RAHasher can be compiled without it. # TODO: Remove `sed` command adding "unistd.h", when RAHasher can be compiled without it. # Related pull request: https://github.com/madler/zlib/pull/1022 -RUN wget "https://github.com/RetroAchievements/RALibretro/archive/refs/tags/${RALIBRETRO_VERSION}.zip" && \ - echo "${RALIBRETRO_SHA256} ${RALIBRETRO_VERSION}.zip" | sha256sum -c - && \ - unzip -q "${RALIBRETRO_VERSION}.zip" && \ - mv "RALibretro-${RALIBRETRO_VERSION}" RALibretro && \ - rm "${RALIBRETRO_VERSION}.zip" && \ +RUN git clone --recursive --branch "${RALIBRETRO_VERSION}" --depth 1 https://github.com/RetroAchievements/RALibretro.git && \ cd ./RALibretro && \ sed -i '22a #include ' ./src/Util.h && \ sed -i '6a #include ' \ - ./src/libchdr/deps/zlib-1.3.1/gzlib.c \ - ./src/libchdr/deps/zlib-1.3.1/gzread.c \ - ./src/libchdr/deps/zlib-1.3.1/gzwrite.c && \ + ./src/libchdr/deps/zlib-1.3.1/gzlib.c \ + ./src/libchdr/deps/zlib-1.3.1/gzread.c \ + ./src/libchdr/deps/zlib-1.3.1/gzwrite.c && \ make HAVE_CHD=1 -f ./Makefile.RAHasher From f1750951cf65af884ee56c41f2581a6b95fe4581 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 11:45:38 -0400 Subject: [PATCH 07/10] install devs deps to build images --- docker/Dockerfile | 3 ++- frontend/package-lock.json | 3 +-- frontend/package.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b617e186e..432569e52 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -33,7 +33,7 @@ FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}@sha256:${NODE_ALPINE_SHA256} A WORKDIR /front COPY ./frontend/package*.json ./ -RUN npm ci --only=production --ignore-scripts --no-audit --no-fund +RUN npm ci --ignore-scripts --no-audit --no-fund COPY ./frontend ./ RUN npm run build @@ -76,6 +76,7 @@ RUN uv sync --locked --no-cache --all-extras FROM alpine:${ALPINE_VERSION}@sha256:${ALPINE_SHA256} AS rahasher-build RUN apk add --no-cache \ g++ \ + git \ linux-headers \ make \ zlib-dev diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c9f2f7855..c832ac893 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,6 +23,7 @@ "qrcode": "^1.5.4", "semver": "^7.6.2", "socket.io-client": "^4.7.5", + "tailwindcss": "^4.0.0", "vanilla-tilt": "^1.8.1", "vue": "^3.4.27", "vue-i18n": "^11.1.10", @@ -44,7 +45,6 @@ "eslint-plugin-vue": "^9.33.0", "globals": "^16.0.0", "openapi-typescript-codegen": "^0.29.0", - "tailwindcss": "^4.0.0", "typescript": "^5.7.3", "typescript-eslint": "^8.42.0", "vite": "^6.3.6", @@ -8374,7 +8374,6 @@ "version": "4.1.12", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", - "dev": true, "license": "MIT" }, "node_modules/tapable": { diff --git a/frontend/package.json b/frontend/package.json index 8e3b2defe..772b1bf15 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,7 +21,7 @@ "type": "module", "scripts": { "dev": "vite --host", - "build": "npm run typecheck && vite build", + "build": "vite build", "preview": "vite preview", "typecheck": "vue-tsc --noEmit", "generate": "openapi --input http://127.0.0.1:3000/openapi.json --output ./src/__generated__ --client axios --useOptions --useUnionTypes --exportServices false --exportSchemas false --exportCore false", @@ -42,6 +42,7 @@ "qrcode": "^1.5.4", "semver": "^7.6.2", "socket.io-client": "^4.7.5", + "tailwindcss": "^4.0.0", "vanilla-tilt": "^1.8.1", "vue": "^3.4.27", "vue-i18n": "^11.1.10", @@ -63,7 +64,6 @@ "eslint-plugin-vue": "^9.33.0", "globals": "^16.0.0", "openapi-typescript-codegen": "^0.29.0", - "tailwindcss": "^4.0.0", "typescript": "^5.7.3", "typescript-eslint": "^8.42.0", "vite": "^6.3.6", From b0c37c193f45152b3e3016cb64ffaa18378f859c Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 14:22:04 -0400 Subject: [PATCH 08/10] drop setting user --- docker/Dockerfile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 432569e52..8283cf537 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -201,7 +201,7 @@ COPY ./docker/gunicorn/logging.conf /etc/gunicorn/logging.conf RUN addgroup -g 1000 -S romm && adduser -u 1000 -D -S -G romm romm && \ mkdir /romm /redis-data && \ chown romm:romm /romm /redis-data && \ - chmod 750 /romm /redis-data && \ + chmod 755 /romm /redis-data && \ chmod -R a+w /etc/nginx/conf.d @@ -219,9 +219,6 @@ ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 ENV PYTHONPATH=/backend -# Use non-root user by default -USER romm - # Declare the supported volumes VOLUME ["/romm/resources", "/romm/library", "/romm/assets", "/romm/config", "/redis-data"] From 873b59c951a680c8f9e9f7b29ebfab0c95675a75 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 15:30:04 -0400 Subject: [PATCH 09/10] use non-slim nginx --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 8283cf537..c0057ff82 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,7 +20,7 @@ ARG PYTHON_ALPINE_SHA256=9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef ARG NODE_VERSION=20.19 ARG NODE_ALPINE_SHA256=eabac870db94f7342d6c33560d6613f188bbcf4bbe1f4eb47d5e2a08e1a37722 ARG NGINX_VERSION=1.29.1 -ARG NGINX_SHA256=94f1c83ea210e0568f87884517b4fe9a39c74b7677e0ad3de72700cfa3da7268 +ARG NGINX_SHA256=42a516af16b852e33b7682d5ef8acbd5d13fe08fecadc7ed98605ba5e3b26ab8 ARG UV_VERSION=0.7.19 ARG UV_SHA256=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d @@ -154,7 +154,7 @@ RUN git clone https://github.com/evanmiller/mod_zip.git && \ # PRODUCTION STAGE -FROM nginx:${NGINX_VERSION}-alpine${ALPINE_VERSION}-slim@sha256:${NGINX_SHA256} AS production-stage +FROM nginx:${NGINX_VERSION}-alpine${ALPINE_VERSION}@sha256:${NGINX_SHA256} AS production-stage ARG WEBSERVER_FOLDER=/var/www/html RUN apk add --no-cache \ From c4d84500099b9b505323da71ae6203d8d550d544 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Thu, 18 Sep 2025 17:01:28 -0400 Subject: [PATCH 10/10] fix typo --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index c0057ff82..86a109a26 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -28,7 +28,7 @@ ARG UV_SHA256=9ce16aa2fe33496c439996865dc121371bb33fd5fb37500007d48e2078686b0d FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION}@sha256:${PYTHON_ALPINE_SHA256} AS python-alias -# FROTNEND BUILD +# FRONTEND BUILD FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}@sha256:${NODE_ALPINE_SHA256} AS frontend-build WORKDIR /front