From c51fb61027acd6f59269ac3b621c0c63013cbf3e Mon Sep 17 00:00:00 2001 From: atti92 Date: Thu, 20 Nov 2025 19:25:57 +0100 Subject: [PATCH 1/7] Make sure the dev docker image is not using root user --- Dockerfile.dev | 8 ++++++++ docker-compose.yml | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/Dockerfile.dev b/Dockerfile.dev index b426785c..1b03fe73 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,6 +1,11 @@ # Development Dockerfile for hot reload and debugging FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS development +ARG APP_USER=appuser +ARG APP_GROUP=appgrp +ARG UID=1000 +ARG GID=1000 + # Install development dependencies RUN apt-get update \ && apt-get install -y --no-install-recommends \ @@ -35,6 +40,9 @@ COPY . . # Create directories RUN mkdir -p /app/reports /app/config +# Switch to non-root user +USER ${APP_USER}:${APP_GROUP} + # Set executable path ENV PATH="/app/.venv/bin:$PATH" diff --git a/docker-compose.yml b/docker-compose.yml index 29718f8a..0ad36ec5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -57,6 +57,11 @@ services: context: . dockerfile: Dockerfile.dev target: development + args: + APP_USER: appuser + APP_GROUP: appgrp + UID: 1000 + GID: 1000 environment: - PYTHONUNBUFFERED=1 - TZ=UTC From 234cc162500578238df3f7f938c6476795fcd7e0 Mon Sep 17 00:00:00 2001 From: atti92 Date: Thu, 20 Nov 2025 19:53:11 +0100 Subject: [PATCH 2/7] Make sure docker files are run with the current host user ids. --- Dockerfile.dev | 14 ++++++++++---- docker-compose.yml | 8 ++++---- scripts/build.sh | 4 ++++ scripts/common.sh | 4 ++++ scripts/run.sh | 12 ++++++++++-- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index 1b03fe73..8aa17b3e 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -18,6 +18,10 @@ RUN apt-get update \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +# Create non-root user and group +RUN groupadd -g "${GID}" "${APP_GROUP}" \ + && useradd -u "${UID}" -g "${APP_GROUP}" -s /bin/sh -m "${APP_USER}" + # Set working directory WORKDIR /app @@ -28,17 +32,19 @@ ENV PYTHONUNBUFFERED=1 ENV PYTHONPATH=/app/src # Copy dependency files -COPY LICENSE README.md pyproject.toml uv.lock ./ +COPY --chown=${APP_USER}:${APP_GROUP} LICENSE README.md pyproject.toml uv.lock ./ # Install all dependencies including dev dependencies RUN --mount=type=cache,target=/root/.cache/uv \ - uv sync --frozen + uv sync --frozen \ + && chown -R ${APP_USER}:${APP_GROUP} .venv # Copy source code -COPY . . +COPY --chown=${APP_USER}:${APP_GROUP} . . # Create directories -RUN mkdir -p /app/reports /app/config +RUN mkdir -p /app/reports /app/config \ + && chown -R ${APP_USER}:${APP_GROUP} /app/reports /app/config # Switch to non-root user USER ${APP_USER}:${APP_GROUP} diff --git a/docker-compose.yml b/docker-compose.yml index 0ad36ec5..27ae745e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,8 +11,8 @@ services: UV_LINK_MODE: copy APP_USER: appuser APP_GROUP: appgrp - UID: 1000 - GID: 1000 + UID: ${HOST_UID:-1000} + GID: ${HOST_GID:-1000} # Environment variables environment: - PYTHONUNBUFFERED=1 @@ -60,8 +60,8 @@ services: args: APP_USER: appuser APP_GROUP: appgrp - UID: 1000 - GID: 1000 + UID: ${HOST_UID:-1000} + GID: ${HOST_GID:-1000} environment: - PYTHONUNBUFFERED=1 - TZ=UTC diff --git a/scripts/build.sh b/scripts/build.sh index 38aea2b4..11e1b13c 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -58,6 +58,8 @@ build_production() { --target production \ --build-arg UV_COMPILE_BYTECODE=1 \ --build-arg UV_LINK_MODE=copy \ + --build-arg UID="${HOST_UID}" \ + --build-arg GID="${HOST_GID}" \ "${build_args[@]}" \ -t "${NAMESPACE}/${IMAGE}" \ -t "${NAMESPACE}/${IMAGE_LATEST}" \ @@ -87,6 +89,8 @@ build_development() { -f Dockerfile.dev \ --target development \ --build-arg UV_COMPILE_BYTECODE=0 \ + --build-arg UID="${HOST_UID}" \ + --build-arg GID="${HOST_GID}" \ "${build_args[@]}" \ -t "${NAMESPACE}/${IMAGE_DEV}" \ . diff --git a/scripts/common.sh b/scripts/common.sh index 3e9841ce..85d8c5bb 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -10,6 +10,10 @@ readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly NC='\033[0m' # No Color +# Current user +HOST_UID=$(id -u) +HOST_GID=$(id -g) + # Logging functions log_info() { echo -e "${BLUE}[INFO]${NC} $1" >&2 diff --git a/scripts/run.sh b/scripts/run.sh index 62c32224..c2806ec7 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -13,6 +13,8 @@ source "$SCRIPT_DIR/common.sh" readonly COMPOSE_FILE="docker-compose.yml" readonly SERVICE_NAME="verification-tool" readonly DEV_SERVICE_NAME="verification-dev" +readonly HOST_UID="$(id -u)" +readonly HOST_GID="$(id -g)" # Check if Docker and Docker Compose are available # Note: check_dependencies is now sourced from common.sh @@ -89,7 +91,10 @@ run_production() { compose_opts+=("--verbose") fi - docker compose "${compose_opts[@]}" --file "${COMPOSE_FILE}" run --rm "${SERVICE_NAME}" "$@" + docker compose "${compose_opts[@]}" --file "${COMPOSE_FILE}" run --rm \ + --user "${HOST_UID}:${HOST_GID}" \ + -e HOST_UID="${HOST_UID}" -e HOST_GID="${HOST_GID}" \ + "${SERVICE_NAME}" "$@" } # Run in development mode @@ -112,7 +117,10 @@ run_development() { compose_opts+=("--verbose") fi - docker compose "${compose_opts[@]}" --profile dev run --rm "${DEV_SERVICE_NAME}" "$@" + docker compose "${compose_opts[@]}" --profile dev run --rm \ + --user "${HOST_UID}:${HOST_GID}" \ + -e HOST_UID="${HOST_UID}" -e HOST_GID="${HOST_GID}" \ + "${DEV_SERVICE_NAME}" "$@" } # Cleanup function for run script From 4f066756b946999a01a4153c75e3d122ab52072b Mon Sep 17 00:00:00 2001 From: atti92 Date: Thu, 20 Nov 2025 20:02:21 +0100 Subject: [PATCH 3/7] Fix mac build arguments and GID clash --- Dockerfile | 10 +++++----- Dockerfile.dev | 14 +++++++------- scripts/build.sh | 4 ++-- scripts/run.sh | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Dockerfile b/Dockerfile index f2629d56..0871aa7f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -65,21 +65,21 @@ ENV TZ=UTC ENV PATH="/app/.venv/bin:$PATH" # Create non-root user and group for enhanced security -RUN groupadd -g "${GID}" "${APP_GROUP}" \ - && useradd -u "${UID}" -g "${APP_GROUP}" -s /bin/sh -m "${APP_USER}" +RUN (getent group "${GID}" || groupadd -g "${GID}" "${APP_GROUP}") \ + && useradd -u "${UID}" -g "${GID}" -s /bin/sh -m "${APP_USER}" # Copy application artifacts from builder stage -COPY --chown=${APP_USER}:${APP_GROUP} --from=builder /app /app +COPY --chown=${UID}:${GID} --from=builder /app /app # Set working directory WORKDIR /app # Create necessary directories with proper permissions RUN mkdir -p /app/config /app/reports \ - && chown -R ${APP_USER}:${APP_GROUP} /app/config /app/reports + && chown -R ${UID}:${GID} /app/config /app/reports # Switch to non-root user -USER ${APP_USER}:${APP_GROUP} +USER ${UID}:${GID} # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ diff --git a/Dockerfile.dev b/Dockerfile.dev index 8aa17b3e..dc0b5149 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -19,8 +19,8 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* # Create non-root user and group -RUN groupadd -g "${GID}" "${APP_GROUP}" \ - && useradd -u "${UID}" -g "${APP_GROUP}" -s /bin/sh -m "${APP_USER}" +RUN (getent group "${GID}" || groupadd -g "${GID}" "${APP_GROUP}") \ + && useradd -u "${UID}" -g "${GID}" -s /bin/sh -m "${APP_USER}" # Set working directory WORKDIR /app @@ -32,22 +32,22 @@ ENV PYTHONUNBUFFERED=1 ENV PYTHONPATH=/app/src # Copy dependency files -COPY --chown=${APP_USER}:${APP_GROUP} LICENSE README.md pyproject.toml uv.lock ./ +COPY --chown=${UID}:${GID} LICENSE README.md pyproject.toml uv.lock ./ # Install all dependencies including dev dependencies RUN --mount=type=cache,target=/root/.cache/uv \ uv sync --frozen \ - && chown -R ${APP_USER}:${APP_GROUP} .venv + && chown -R ${UID}:${GID} .venv # Copy source code -COPY --chown=${APP_USER}:${APP_GROUP} . . +COPY --chown=${UID}:${GID} . . # Create directories RUN mkdir -p /app/reports /app/config \ - && chown -R ${APP_USER}:${APP_GROUP} /app/reports /app/config + && chown -R ${UID}:${GID} /app/reports /app/config # Switch to non-root user -USER ${APP_USER}:${APP_GROUP} +USER ${UID}:${GID} # Set executable path ENV PATH="/app/.venv/bin:$PATH" diff --git a/scripts/build.sh b/scripts/build.sh index 11e1b13c..fcafd20a 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -60,7 +60,7 @@ build_production() { --build-arg UV_LINK_MODE=copy \ --build-arg UID="${HOST_UID}" \ --build-arg GID="${HOST_GID}" \ - "${build_args[@]}" \ + ${build_args[@]+"${build_args[@]}"} \ -t "${NAMESPACE}/${IMAGE}" \ -t "${NAMESPACE}/${IMAGE_LATEST}" \ . @@ -91,7 +91,7 @@ build_development() { --build-arg UV_COMPILE_BYTECODE=0 \ --build-arg UID="${HOST_UID}" \ --build-arg GID="${HOST_GID}" \ - "${build_args[@]}" \ + ${build_args[@]+"${build_args[@]}"} \ -t "${NAMESPACE}/${IMAGE_DEV}" \ . diff --git a/scripts/run.sh b/scripts/run.sh index c2806ec7..233b12fd 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -82,7 +82,7 @@ run_production() { if [[ "${BUILD_FIRST}" == "true" ]]; then log_info "Building production image first..." - ./scripts/build.sh "${build_opts[@]}" production + ./scripts/build.sh ${build_opts[@]+"${build_opts[@]}"} production fi local compose_opts=() @@ -91,7 +91,7 @@ run_production() { compose_opts+=("--verbose") fi - docker compose "${compose_opts[@]}" --file "${COMPOSE_FILE}" run --rm \ + docker compose ${compose_opts[@]+"${compose_opts[@]}"} --file "${COMPOSE_FILE}" run --rm \ --user "${HOST_UID}:${HOST_GID}" \ -e HOST_UID="${HOST_UID}" -e HOST_GID="${HOST_GID}" \ "${SERVICE_NAME}" "$@" @@ -109,7 +109,7 @@ run_development() { if [[ "${BUILD_FIRST}" == "true" ]]; then log_info "Building development image first..." - ./scripts/build.sh "${build_opts[@]}" development + ./scripts/build.sh ${build_opts[@]+"${build_opts[@]}"} development fi local compose_opts=() @@ -117,7 +117,7 @@ run_development() { compose_opts+=("--verbose") fi - docker compose "${compose_opts[@]}" --profile dev run --rm \ + docker compose ${compose_opts[@]+"${compose_opts[@]}"} --profile dev run --rm \ --user "${HOST_UID}:${HOST_GID}" \ -e HOST_UID="${HOST_UID}" -e HOST_GID="${HOST_GID}" \ "${DEV_SERVICE_NAME}" "$@" From a19a160696957a71c8b1bdd016bbd5ecf19c68c4 Mon Sep 17 00:00:00 2001 From: atti92 Date: Thu, 20 Nov 2025 20:03:06 +0100 Subject: [PATCH 4/7] Make sure -- separator is consumed properly. --- scripts/run.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/run.sh b/scripts/run.sh index 233b12fd..4e6b36c7 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -172,6 +172,11 @@ main() { esac done + # Consume the separator if present + if [[ "${1:-}" == "--" ]]; then + shift + fi + log_info "Starting OpenUTM Verification Tool..." check_dependencies check_files From 4f388cf134a0bd1b89ef26f6afb5e9be6d95ccf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20K=C3=B3bor?= Date: Thu, 20 Nov 2025 20:06:24 +0100 Subject: [PATCH 5/7] Update scripts/common.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/common.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/common.sh b/scripts/common.sh index 85d8c5bb..4dc8bfb1 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -11,8 +11,8 @@ readonly BLUE='\033[0;34m' readonly NC='\033[0m' # No Color # Current user -HOST_UID=$(id -u) -HOST_GID=$(id -g) +readonly HOST_UID=$(id -u) +readonly HOST_GID=$(id -g) # Logging functions log_info() { From a429831e6dbf2348209de28b5449752dd12af427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20K=C3=B3bor?= Date: Thu, 20 Nov 2025 20:06:41 +0100 Subject: [PATCH 6/7] Update scripts/run.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/run.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/run.sh b/scripts/run.sh index 4e6b36c7..a65cae2c 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -13,8 +13,6 @@ source "$SCRIPT_DIR/common.sh" readonly COMPOSE_FILE="docker-compose.yml" readonly SERVICE_NAME="verification-tool" readonly DEV_SERVICE_NAME="verification-dev" -readonly HOST_UID="$(id -u)" -readonly HOST_GID="$(id -g)" # Check if Docker and Docker Compose are available # Note: check_dependencies is now sourced from common.sh From 61b11fe08a6590da7799c28efdf5c57e92c306e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20K=C3=B3bor?= Date: Thu, 20 Nov 2025 20:08:43 +0100 Subject: [PATCH 7/7] Update Dockerfile.dev Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Dockerfile.dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index dc0b5149..f4bcc048 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -35,7 +35,7 @@ ENV PYTHONPATH=/app/src COPY --chown=${UID}:${GID} LICENSE README.md pyproject.toml uv.lock ./ # Install all dependencies including dev dependencies -RUN --mount=type=cache,target=/root/.cache/uv \ +RUN --mount=type=cache,target=/home/${APP_USER}/.cache/uv,uid=${UID},gid=${GID} \ uv sync --frozen \ && chown -R ${UID}:${GID} .venv