diff --git a/Dockerfile b/Dockerfile index 4ed4782cd..5790ae52c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,20 +16,31 @@ SHELL ["/bin/bash", "-c"] ARG GRADLE_BUILD_ARGS="-PdisableSigning=true" # Stage 1a: Install dependencies -# Install necessary tools -COPY .sdkmanrc . +# Install necessary tools, then drop root. The base image ships a +# pre-created "ubuntu" user (uid 1000, the same one the runner stage +# below renames to "engine") — reuse it so Gradle doesn't run as root, +# which ignores POSIX permission bits and breaks tests that depend on +# them (e.g. Log4jMigrationsTest's read-only-file assertion). RUN apt-get update\ && apt-get install -y zip curl\ - && curl -s "https://get.sdkman.io?ci=true" | bash \ - && source "$HOME/.sdkman/bin/sdkman-init.sh" && sdk env install \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* \ + && chown ubuntu:ubuntu /app +USER ubuntu + +COPY --chown=ubuntu:ubuntu .sdkmanrc . +RUN curl -s "https://get.sdkman.io?ci=true" | bash \ + && source "$HOME/.sdkman/bin/sdkman-init.sh" && sdk env install # Stage 1b: Build the application # Copy the entire source tree (excluding .dockerignore files), and build # (file encoding is pinned to UTF-8 in gradle.properties) -COPY . . -RUN --mount=type=cache,target=/root/.gradle/caches,sharing=locked \ - --mount=type=cache,target=/root/.gradle/wrapper,sharing=locked \ +COPY --chown=ubuntu:ubuntu . . +# The cache mounts below own their own target dirs (uid/gid), but not the +# ~/.gradle parent itself — Gradle also writes ~/.gradle/native (extracted +# native-platform lib) outside either mount, so create the parent up front. +RUN mkdir -p /home/ubuntu/.gradle +RUN --mount=type=cache,target=/home/ubuntu/.gradle/caches,sharing=locked,uid=1000,gid=1000 \ + --mount=type=cache,target=/home/ubuntu/.gradle/wrapper,sharing=locked,uid=1000,gid=1000 \ source "$HOME/.sdkman/bin/sdkman-init.sh" \ && ./gradlew --no-daemon build ${GRADLE_BUILD_ARGS}