From 08fa7a7b4dc7e41397a5318df3d9d22a76a36313 Mon Sep 17 00:00:00 2001 From: Renn F Date: Wed, 21 Oct 2026 03:06:00 +0200 Subject: [PATCH 1/2] fix(docker): run the test image as a non-root user --- Dockerfile | 29 +++++++++++++++-------------- compose.yml | 2 ++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0da9e10..0e2ff58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,33 @@ ARG PYTHON_VERSION=3.10 FROM python:${PYTHON_VERSION}-slim -RUN apt-get update && apt-get install -y \ - libsodium23 \ - wget \ - build-essential \ - libffi-dev \ - curl +COPY --from=ghcr.io/astral-sh/uv:0.13.4 /uv /uvx /bin/ + +RUN useradd --create-home --uid 10001 app \ + && mkdir /app \ + && chown app:app /app WORKDIR /app -ENV PIP_NO_CACHE_DIR=false \ - PIP_DISABLE_PIP_VERSION_CHECK=on \ +ENV PIP_DISABLE_PIP_VERSION_CHECK=on \ PIP_DEFAULT_TIMEOUT=10 \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 -# Install uv -RUN pip install uv +USER 10001 -COPY pyproject.toml uv.lock* README.md /app/ +COPY --chown=app:app pyproject.toml uv.lock* README.md /app/ RUN uv sync --extra dev --frozen ENV PATH="/app/.venv/bin:$PATH" -COPY flaskapi_guard/ /app/flaskapi_guard/ -COPY tests/ /app/tests/ -COPY examples/ /app/examples/ +COPY --chown=app:app flaskapi_guard/ /app/flaskapi_guard/ +COPY --chown=app:app tests/ /app/tests/ +COPY --chown=app:app examples/ /app/examples/ RUN mkdir -p /app/data/ipinfo + +# Probes the app service on port 8000. Any HTTP answer counts as alive; a refused connection or a timeout fails. +HEALTHCHECK --interval=10s --timeout=5s --start-period=20s --retries=3 \ + CMD ["python", "-c", "import urllib.request, urllib.error\ntry:\n urllib.request.urlopen('http://127.0.0.1:8000/', timeout=3)\nexcept urllib.error.HTTPError:\n pass"] diff --git a/compose.yml b/compose.yml index cc66e6e..42b8bd9 100644 --- a/compose.yml +++ b/compose.yml @@ -26,6 +26,8 @@ services: PYTHON_VERSION: ${PYTHON_VERSION:-3.10} image: flaskapi-guard-py${PYTHON_VERSION:-3.10} command: pytest -v --cov=. + healthcheck: + disable: true environment: - REDIS_URL=redis://redis:6379 - REDIS_PREFIX=${REDIS_PREFIX:-"test:flaskapi_guard:"} From 883278bf81b19ec1f25f8295edd3c6088b0faef1 Mon Sep 17 00:00:00 2001 From: Renn F Date: Wed, 21 Oct 2026 03:47:09 +0200 Subject: [PATCH 2/2] fix(docker): run the example and smoke images as a non-root user --- .github/workflows/docksec.yml | 2 ++ examples/advanced_app/Dockerfile | 8 ++++++-- examples/simple_app/Dockerfile | 16 ++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docksec.yml b/.github/workflows/docksec.yml index 36de464..1b71db1 100644 --- a/.github/workflows/docksec.yml +++ b/.github/workflows/docksec.yml @@ -5,10 +5,12 @@ on: branches: [master] paths: - 'Dockerfile' + - '**/Dockerfile' - '.github/workflows/docksec.yml' pull_request: paths: - 'Dockerfile' + - '**/Dockerfile' - '.github/workflows/docksec.yml' schedule: - cron: '0 6 * * 1' diff --git a/examples/advanced_app/Dockerfile b/examples/advanced_app/Dockerfile index cfb059b..b16e51d 100644 --- a/examples/advanced_app/Dockerfile +++ b/examples/advanced_app/Dockerfile @@ -18,7 +18,7 @@ RUN uv venv .venv && \ FROM python:3.12-slim RUN groupadd --system guard && \ - useradd --system --gid guard --create-home guard + useradd --system --uid 10001 --gid guard --create-home guard WORKDIR /app @@ -31,8 +31,12 @@ ENV PATH="/app/.venv/bin:$PATH" \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 -USER guard +USER 10001 EXPOSE 8000 +# Same probe as the compose services: /health must answer 2xx. +HEALTHCHECK --interval=10s --timeout=5s --start-period=20s --retries=3 \ + CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)"] + CMD ["gunicorn", "-c", "gunicorn.conf.py", "app.main:app"] diff --git a/examples/simple_app/Dockerfile b/examples/simple_app/Dockerfile index f9a1770..3b89977 100644 --- a/examples/simple_app/Dockerfile +++ b/examples/simple_app/Dockerfile @@ -1,18 +1,22 @@ FROM python:3.10-slim -RUN apt-get update && apt-get install -y \ - libsodium23 \ - build-essential \ - libffi-dev \ - && rm -rf /var/lib/apt/lists/* +RUN useradd --create-home --uid 10001 app \ + && mkdir /app \ + && chown app:app /app WORKDIR /app COPY requirements.txt /app/ RUN pip install --no-cache-dir -r requirements.txt -COPY . /app/ +USER 10001 + +COPY --chown=app:app . /app/ EXPOSE 8000 +# Probes port 8000. Any HTTP answer counts as alive; a refused connection or a timeout fails. +HEALTHCHECK --interval=10s --timeout=5s --start-period=20s --retries=3 \ + CMD ["python", "-c", "import urllib.request, urllib.error\ntry:\n urllib.request.urlopen('http://127.0.0.1:8000/', timeout=3)\nexcept urllib.error.HTTPError:\n pass"] + CMD ["gunicorn", "main:app", "--bind", "0.0.0.0:8000", "--reload"]