From c42460ce2f0d77e96c7286049a945e58b4508f0f Mon Sep 17 00:00:00 2001 From: Sam Stepanyan Date: Sat, 9 Aug 2025 16:30:45 +0100 Subject: [PATCH] Dockerfile change to multi-stage with 'nettacker' as entrypoint + related CI/CD changes (#1115) * Update Dockerfile multi-stage Dockerfile * Update ci_cd.yml modifications to support Dockerfile entrypoint changes * Update Dockerfile added --no-deps --no-cache-dir * Update Dockerfile added OCI Label and remove the whl file after installation following the CodeRabbit review * Update Dockerfile moved OCI label as copy-pasted in the wrong place * Update Dockerfile as per suggestion Co-authored-by: Arkadii Yakovets <2201626+arkid15r@users.noreply.github.com> Signed-off-by: Sam Stepanyan --------- Signed-off-by: Sam Stepanyan Co-authored-by: Arkadii Yakovets <2201626+arkid15r@users.noreply.github.com> --- .github/workflows/ci_cd.yml | 31 ++++++++++-------------- Dockerfile | 47 ++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 9bd9e989..6071d1cb 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -161,46 +161,42 @@ jobs: - name: Test help menu run: | - docker run -e github_ci=true --rm nettacker \ - poetry run python nettacker.py --help + docker run -e github_ci=true --rm nettacker --help - name: Test help menu in Persian run: | - docker run -e github_ci=true --rm nettacker \ - poetry run python nettacker.py --help -L fa + docker run -e github_ci=true --rm nettacker --help -L fa - name: Show all modules run: | - docker run -e github_ci=true --rm nettacker \ - poetry run python nettacker.py --show-all-modules + docker run -e github_ci=true --rm nettacker --show-all-modules - name: Show all profiles run: | - docker run -e github_ci=true --rm nettacker \ - poetry run python nettacker.py --show-all-profiles + docker run -e github_ci=true --rm nettacker --show-all-profiles - name: Test all modules command + check if it's finish successfully + csv run: | - docker run -e github_ci=true --rm -i nettacker \ - poetry run python nettacker.py -i 127.0.0.1 -u user1,user2 -p pass1,pass2 -m all -g 21,25,80,443 \ + docker run -e github_ci=true --rm -i --add-host=host.docker.internal:host-gateway nettacker \ + -i host.docker.internal -u user1,user2 -p pass1,pass2 -m all -g 21,25,80,443 \ -t 1000 -T 3 -o out.csv - name: Test all modules command + check if it's finish successfully + csv run: | - docker run -e github_ci=true --rm -i nettacker \ - poetry run python nettacker.py -i 127.0.0.1 -u user1,user2 -p pass1,pass2 -m all -g 21,25,80,443 \ + docker run -e github_ci=true --rm -i --add-host=host.docker.internal:host-gateway nettacker \ + -i host.docker.internal -u user1,user2 -p pass1,pass2 -m all -g 21,25,80,443 \ -t 1000 -T 3 -o out.csv --skip-service-discovery - name: Test all modules command + check if it's finish successfully + with graph + Persian run: | - docker run -e github_ci=true --rm -i nettacker \ - poetry run python nettacker.py -i 127.0.0.1 -L fa -u user1,user2 -p pass1,pass2 --profile all \ + docker run -e github_ci=true --rm -i --add-host=host.docker.internal:host-gateway nettacker \ + -i host.docker.internal -L fa -u user1,user2 -p pass1,pass2 --profile all \ -g 21,25,80,443 -t 1000 -T 3 --graph d3_tree_v2_graph -v - name: Test all modules command + check if it's finish successfully + with graph + Persian run: | - docker run -e github_ci=true --rm -i nettacker \ - poetry run python nettacker.py -i 127.0.0.1 -L fa -u user1,user2 -p pass1,pass2 --profile all \ + docker run -e github_ci=true --rm -i --add-host=host.docker.internal:host-gateway nettacker \ + -i host.docker.internal -L fa -u user1,user2 -p pass1,pass2 --profile all \ -g 21,25,80,443 -t 1000 -T 3 --graph d3_tree_v2_graph -v --skip-service-discovery test-docker-image-build: @@ -243,9 +239,6 @@ jobs: - name: Build Nettacker image run: docker build . -t nettacker - - name: Run pip install - run: docker run nettacker pip install . - publish-nettacker-dev-to-docker-registry: name: Publish nettacker:dev Docker image if: | diff --git a/Dockerfile b/Dockerfile index 4d5732c9..a7fd97c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,10 @@ -FROM python:3.11.13-slim - +### Multi-stage Dockerfile +# Define the base image only once as a build argument +ARG PYTHON_IMAGE=python:3.11.13-slim + +### Build stage +FROM ${PYTHON_IMAGE} AS builder +### Install OS dependencies and poetry package manager RUN apt-get update && \ apt-get install -y gcc libssl-dev && \ apt-get clean && \ @@ -8,11 +13,41 @@ RUN apt-get update && \ WORKDIR /usr/src/owaspnettacker +# Copy dependency files first to maximize Docker cache usage for installing dependencies +COPY poetry.lock pyproject.toml ./ + +# Install dependencies +RUN poetry config virtualenvs.in-project true && \ + poetry install --no-cache --no-root --without dev --without test + +# Now copy the rest of the required source code COPY nettacker nettacker -COPY nettacker.py poetry.lock pyproject.toml README.md ./ +COPY nettacker.py README.md ./ -RUN poetry install --no-cache --no-root --without dev --without test +# Build the project only after all code is present +RUN poetry build +### Runtime stage - start from a clean Python image +FROM ${PYTHON_IMAGE} AS runtime +WORKDIR /usr/src/owaspnettacker + +# OCI Labels (attach to final image) +LABEL org.opencontainers.image.title="OWASP Nettacker" \ + org.opencontainers.image.description="Automated Penetration Testing Framework" \ + org.opencontainers.image.url="https://owasp.org/nettacker" \ + org.opencontainers.image.source="https://github.com/OWASP/Nettacker" \ + org.opencontainers.image.licenses="Apache-2.0" + +### Bring from 'builder' just the virtualenv and the packaged Nettacker as a wheel +COPY --from=builder /usr/src/owaspnettacker/.venv ./.venv +COPY --from=builder /usr/src/owaspnettacker/dist/*.whl . + +ENV PATH=/usr/src/owaspnettacker/.venv/bin:$PATH +### Use pip inside the venv to install just the nettacker wheel saving 50%+ space +RUN pip install --no-deps --no-cache-dir nettacker-*.whl && \ + rm -f nettacker-*.whl + +### We now have Nettacker installed in the virtualenv with 'nettacker' command which is the new entrypoint ENV docker_env=true - -CMD [ "poetry", "run", "python", "./nettacker.py" ] +ENTRYPOINT [ "nettacker" ] +CMD ["--help"]