From 4b36c4dd901e3d2aea1d869ee7ebbd160ea2c2e9 Mon Sep 17 00:00:00 2001 From: Filipe Pina Date: Thu, 11 Sep 2025 17:27:00 +0100 Subject: [PATCH 1/5] drop wheels from layers --- Dockerfile.django-alpine | 9 ++++++++- Dockerfile.django-debian | 11 +++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Dockerfile.django-alpine b/Dockerfile.django-alpine index 939662de865..f1ff1e36242 100644 --- a/Dockerfile.django-alpine +++ b/Dockerfile.django-alpine @@ -1,3 +1,10 @@ +# TESTS +# alpine build - 1m55 - 732MB +# debian build - 1m42 - 960MB + +# DROP WHEELS +# debian build - 866MB + # code: language=Dockerfile @@ -58,7 +65,7 @@ RUN \ COPY --from=build /tmp/wheels /tmp/wheels COPY requirements.txt ./ RUN export PYCURL_SSL_LIBRARY=openssl && \ - pip3 install \ + pip3 install \ --no-cache-dir \ --no-index \ --find-links=/tmp/wheels \ diff --git a/Dockerfile.django-debian b/Dockerfile.django-debian index da5b4b3a22a..1b4c9773e12 100644 --- a/Dockerfile.django-debian +++ b/Dockerfile.django-debian @@ -58,10 +58,13 @@ RUN \ apt-get clean && \ rm -rf /var/lib/apt/lists && \ true -COPY --from=build /tmp/wheels /tmp/wheels -COPY requirements.txt ./ -RUN export PYCURL_SSL_LIBRARY=openssl && \ - pip3 install \ +# COPY --from=build /tmp/wheels /tmp/wheels +# COPY requirements.txt ./ +RUN \ + --mount=from=build,src=/tmp/wheels,target=/tmp/wheels \ + --mount=from=build,src=/app/requirements.txt,target=/app/requirements.txt \ + export PYCURL_SSL_LIBRARY=openssl && \ + pip3 install \ --no-cache-dir \ --no-index \ --find-links=/tmp/wheels \ From 52299d764404d17624a4e226a52672ddc82d1f2e Mon Sep 17 00:00:00 2001 From: Filipe Pina Date: Thu, 11 Sep 2025 17:38:43 +0100 Subject: [PATCH 2/5] drop unittests, integration tests and *-dev packages from main stage --- Dockerfile.django-alpine | 6 +++--- Dockerfile.django-debian | 19 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Dockerfile.django-alpine b/Dockerfile.django-alpine index f1ff1e36242..5cb54a58db0 100644 --- a/Dockerfile.django-alpine +++ b/Dockerfile.django-alpine @@ -2,9 +2,9 @@ # alpine build - 1m55 - 732MB # debian build - 1m42 - 960MB -# DROP WHEELS -# debian build - 866MB - +# DEBIAN +# drop wheels - 866MB +# drop unittests, integration tests and *-dev packages from main stage - 1m40 - 842MB # code: language=Dockerfile diff --git a/Dockerfile.django-debian b/Dockerfile.django-debian index 1b4c9773e12..8896cf05a21 100644 --- a/Dockerfile.django-debian +++ b/Dockerfile.django-debian @@ -28,7 +28,8 @@ RUN \ COPY requirements.txt ./ # CPUCOUNT=1 is needed, otherwise the wheel for uwsgi won't always be build succesfully # https://github.com/unbit/uwsgi/issues/1318#issuecomment-542238096 -RUN CPUCOUNT=1 pip3 wheel --wheel-dir=/tmp/wheels -r ./requirements.txt +RUN export PYCURL_SSL_LIBRARY=openssl && \ + CPUCOUNT=1 pip3 wheel --wheel-dir=/tmp/wheels -r ./requirements.txt FROM base AS django WORKDIR /app @@ -49,21 +50,17 @@ RUN \ xmlsec1 \ git \ uuid-runtime \ - libpq-dev \ # only required for the dbshell (used by the initializer job) postgresql-client \ - # libcurl4-openssl-dev is required for installing pycurl python package + # libcurl4-openssl-dev is required for installing pycurl python package as there is no libcurl4-openssl package libcurl4-openssl-dev \ && \ apt-get clean && \ rm -rf /var/lib/apt/lists && \ true -# COPY --from=build /tmp/wheels /tmp/wheels -# COPY requirements.txt ./ RUN \ --mount=from=build,src=/tmp/wheels,target=/tmp/wheels \ --mount=from=build,src=/app/requirements.txt,target=/app/requirements.txt \ - export PYCURL_SSL_LIBRARY=openssl && \ pip3 install \ --no-cache-dir \ --no-index \ @@ -78,20 +75,17 @@ COPY \ docker/entrypoint-first-boot.sh \ docker/entrypoint-uwsgi.sh \ docker/entrypoint-uwsgi-dev.sh \ - docker/entrypoint-unit-tests.sh \ - docker/entrypoint-unit-tests-devDocker.sh \ docker/wait-for-it.sh \ docker/secret-file-loader.sh \ docker/reach_database.sh \ docker/certs/* \ / -COPY wsgi.py manage.py docker/unit-tests.sh ./ +COPY wsgi.py manage.py ./ COPY dojo/ ./dojo/ # Add extra fixtures to docker image which are loaded by the initializer COPY docker/extra_fixtures/* /app/dojo/fixtures/ -COPY tests/ ./tests/ RUN \ # Remove placeholder copied from docker/certs rm -f /readme.txt && \ @@ -143,4 +137,9 @@ ENV \ ENTRYPOINT ["/entrypoint-uwsgi.sh"] FROM django AS django-unittests +COPY \ + docker/entrypoint-unit-tests.sh \ + docker/entrypoint-unit-tests-devDocker.sh \ + / +COPY docker/unit-tests.sh ./ COPY unittests/ ./unittests/ From 4e51356ead4e48ad8a0166cc7b8943db291c16ac Mon Sep 17 00:00:00 2001 From: Filipe Pina Date: Thu, 11 Sep 2025 18:02:25 +0100 Subject: [PATCH 3/5] split requirements - reduce attack surface --- Dockerfile.django-alpine | 3 ++- requirements-dev.txt | 7 +++++++ requirements.txt | 7 ------- 3 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 requirements-dev.txt diff --git a/Dockerfile.django-alpine b/Dockerfile.django-alpine index 5cb54a58db0..95fc60eaa06 100644 --- a/Dockerfile.django-alpine +++ b/Dockerfile.django-alpine @@ -3,8 +3,9 @@ # debian build - 1m42 - 960MB # DEBIAN -# drop wheels - 866MB +# drop wheels - 1m42 - 866MB # drop unittests, integration tests and *-dev packages from main stage - 1m40 - 842MB +# take dev requirements out of main stage - 1m40 - 836MB ==> reduce attack surface, not just size # code: language=Dockerfile diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000000..cc0c210da68 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,7 @@ +django-debug-toolbar==6.0.0 +django-debug-toolbar-request-history==0.1.4 +vcrpy==7.0.0 +vcrpy-unittest==0.1.7 +django-test-migrations==1.4.0 +parameterized==0.9.0 +watchdog==6.0.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index cf3258fb8da..b7669409ac0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -51,16 +51,11 @@ packageurl-python==0.17.5 django-crum==0.7.9 JSON-log-formatter==1.1.1 django-split-settings==1.3.2 -django-debug-toolbar==6.0.0 -django-debug-toolbar-request-history==0.1.4 -vcrpy==7.0.0 -vcrpy-unittest==0.1.7 django-tagulous==2.1.1 PyJWT==2.10.1 cvss==3.6 django-fieldsignals==0.7.0 hyperlink==21.0.0 -django-test-migrations==1.4.0 djangosaml2==1.11.1 drf-spectacular==0.28.0 drf-spectacular-sidecar==2025.8.1 @@ -74,5 +69,3 @@ vulners==2.3.7 fontawesomefree==6.6.0 PyYAML==6.0.2 pyopenssl==25.1.0 -parameterized==0.9.0 -watchdog==6.0.0 # only needed for development, but would require some docker refactoring if we want to exclude it for production images \ No newline at end of file From bca4cdd0b5857bb05c83d538744df2b2331a0c52 Mon Sep 17 00:00:00 2001 From: Filipe Pina Date: Fri, 12 Sep 2025 10:41:31 +0100 Subject: [PATCH 4/5] same to alpine image --- Dockerfile.django-alpine | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/Dockerfile.django-alpine b/Dockerfile.django-alpine index 95fc60eaa06..849fc9a9c8d 100644 --- a/Dockerfile.django-alpine +++ b/Dockerfile.django-alpine @@ -1,11 +1,3 @@ -# TESTS -# alpine build - 1m55 - 732MB -# debian build - 1m42 - 960MB - -# DEBIAN -# drop wheels - 1m42 - 866MB -# drop unittests, integration tests and *-dev packages from main stage - 1m40 - 842MB -# take dev requirements out of main stage - 1m40 - 836MB ==> reduce attack surface, not just size # code: language=Dockerfile @@ -37,7 +29,8 @@ RUN \ COPY requirements.txt ./ # CPUCOUNT=1 is needed, otherwise the wheel for uwsgi won't always be build succesfully # https://github.com/unbit/uwsgi/issues/1318#issuecomment-542238096 -RUN CPUCOUNT=1 pip3 wheel --wheel-dir=/tmp/wheels -r ./requirements.txt +RUN export PYCURL_SSL_LIBRARY=openssl && \ + CPUCOUNT=1 pip3 wheel --wheel-dir=/tmp/wheels -r ./requirements.txt FROM base AS django WORKDIR /app @@ -63,9 +56,9 @@ RUN \ && \ rm -rf /var/cache/apk/* && \ true -COPY --from=build /tmp/wheels /tmp/wheels -COPY requirements.txt ./ -RUN export PYCURL_SSL_LIBRARY=openssl && \ +RUN \ + --mount=from=build,src=/tmp/wheels,target=/tmp/wheels \ + --mount=from=build,src=/app/requirements.txt,target=/app/requirements.txt \ pip3 install \ --no-cache-dir \ --no-index \ @@ -80,20 +73,17 @@ COPY \ docker/entrypoint-first-boot.sh \ docker/entrypoint-uwsgi.sh \ docker/entrypoint-uwsgi-dev.sh \ - docker/entrypoint-unit-tests.sh \ - docker/entrypoint-unit-tests-devDocker.sh \ docker/wait-for-it.sh \ docker/secret-file-loader.sh \ docker/reach_database.sh \ docker/certs/* \ / -COPY wsgi.py manage.py docker/unit-tests.sh ./ +COPY wsgi.py manage.py ./ COPY dojo/ ./dojo/ # Add extra fixtures to docker image which are loaded by the initializer COPY docker/extra_fixtures/* /app/dojo/fixtures/ -COPY tests/ ./tests/ RUN \ # Remove placeholder copied from docker/certs rm -f /readme.txt && \ @@ -145,4 +135,9 @@ ENV \ ENTRYPOINT ["/entrypoint-uwsgi.sh"] FROM django AS django-unittests +COPY \ + docker/entrypoint-unit-tests.sh \ + docker/entrypoint-unit-tests-devDocker.sh \ + / +COPY docker/unit-tests.sh ./ COPY unittests/ ./unittests/ From 5f4c40bd6ba60ed8603a7eabfdbc3c6bf6740a21 Mon Sep 17 00:00:00 2001 From: Filipe Pina Date: Fri, 12 Sep 2025 11:04:19 +0100 Subject: [PATCH 5/5] update dockerfile and compose.dev after requirements.txt split --- Dockerfile.django-alpine | 10 ++++++++++ Dockerfile.django-debian | 10 ++++++++++ docker-compose.override.dev.yml | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/Dockerfile.django-alpine b/Dockerfile.django-alpine index 849fc9a9c8d..b4f08cd2b6b 100644 --- a/Dockerfile.django-alpine +++ b/Dockerfile.django-alpine @@ -141,3 +141,13 @@ COPY \ / COPY docker/unit-tests.sh ./ COPY unittests/ ./unittests/ + +USER root +RUN \ + --mount=src=requirements-dev.txt,target=/tmp/requirements-dev.txt \ + pip3 install \ + --no-cache-dir \ + -r /tmp/requirements-dev.txt + +ARG uid=1001 +USER ${uid} \ No newline at end of file diff --git a/Dockerfile.django-debian b/Dockerfile.django-debian index 8896cf05a21..772f13e7aa9 100644 --- a/Dockerfile.django-debian +++ b/Dockerfile.django-debian @@ -143,3 +143,13 @@ COPY \ / COPY docker/unit-tests.sh ./ COPY unittests/ ./unittests/ + +USER root +RUN \ + --mount=src=requirements-dev.txt,target=/tmp/requirements-dev.txt \ + pip3 install \ + --no-cache-dir \ + -r /tmp/requirements-dev.txt + +ARG uid=1001 +USER ${uid} \ No newline at end of file diff --git a/docker-compose.override.dev.yml b/docker-compose.override.dev.yml index 8dfa5a9e19b..f48fe0f811f 100644 --- a/docker-compose.override.dev.yml +++ b/docker-compose.override.dev.yml @@ -1,6 +1,10 @@ --- services: uwsgi: + build: + context: ./ + dockerfile: "Dockerfile.django-${DEFECT_DOJO_OS:-debian}" + target: django-unittests entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST:-postgres}:${DD_DATABASE_PORT:-5432}', '-t', '30', '--', '/entrypoint-uwsgi-dev.sh'] volumes: - '.:/app:z'