From 4054d1226a063b27b92905b959e68f284303390a Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 1/8] fix: run Flask only in the app image; delete unused Dockerfile.ollama CMD started `ollama serve` inside the Flask image, but that image never shipped an Ollama binary. Compose already runs `ollama/ollama:latest` as a second service, and the leftover command failed or no-oped at startup. Dockerfile.ollama was a wrapper Compose never referenced. --- Dockerfile | 5 +++-- Dockerfile.ollama | 7 ------- 2 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 Dockerfile.ollama diff --git a/Dockerfile b/Dockerfile index d035713..e0f51c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,8 @@ EXPOSE 8080 ENV FLASK_APP=main.py ENV PYTHONUNBUFFERED=1 +# Compose DNS to the separate ollama service (not installed in this image). ENV OLLAMA_HOST=http://ollama:11434 -# Start Ollama in background, wait for it, then start Flask -CMD ollama serve > /tmp/ollama.log 2>&1 & sleep 5 && flask run --host=0.0.0.0 --port=8080 --no-reload +# Flask only. Ollama runs as compose service ollama/ollama:latest. +CMD ["flask", "run", "--host=0.0.0.0", "--port=8080", "--no-reload"] diff --git a/Dockerfile.ollama b/Dockerfile.ollama deleted file mode 100644 index ca0e39e..0000000 --- a/Dockerfile.ollama +++ /dev/null @@ -1,7 +0,0 @@ -FROM ollama/ollama:latest - -EXPOSE 11434 - -ENV OLLAMA_KEEP_ALIVE=-1 - -CMD ["ollama", "serve"] \ No newline at end of file From 7e1548197a35d2567be9e2e899b944a38cc7c306 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 2/8] chore: drop pip download cache and extra apt recommends from images pip keeps wheels under /root/.cache/pip in the same layer (~3 GB here). apt's recommended packages are not needed at runtime. --no-cache-dir and --no-install-recommends keep those files out of what we publish. --- Dockerfile | 6 +++--- deploy/Dockerfile.pwnzzai-workshop | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index e0f51c8..1e0e412 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,14 +2,14 @@ FROM python:3.11-slim WORKDIR /app -RUN apt-get update && apt-get install -y build-essential \ +RUN apt-get update && apt-get install -y --no-install-recommends build-essential \ libzbar0 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* COPY requirements.txt . -RUN python -m pip install --upgrade pip && \ - pip install \ +RUN python -m pip install --upgrade --no-cache-dir pip && \ + pip install --no-cache-dir \ --retries 10 \ --timeout 600 \ -r requirements.txt diff --git a/deploy/Dockerfile.pwnzzai-workshop b/deploy/Dockerfile.pwnzzai-workshop index 4e7f0ff..fa70601 100644 --- a/deploy/Dockerfile.pwnzzai-workshop +++ b/deploy/Dockerfile.pwnzzai-workshop @@ -13,8 +13,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/* COPY requirements.txt . -RUN python -m pip install --upgrade pip && \ - pip install \ +RUN python -m pip install --upgrade --no-cache-dir pip && \ + pip install --no-cache-dir \ --retries 10 \ --timeout 600 \ -r requirements.txt From 0d8ed49c9b0e49c6a3117b19e7d189156de50ef1 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 3/8] chore: install CPU PyTorch before requirements.txt in Dockerfiles sentence-transformers depends on torch. The default PyPI wheel is CUDA plus nvidia-* packages, even though RAG labs only embed on CPU (MiniLM, 384-d). Installing the CPU index first stops the CUDA stack from landing in the image. requirements.txt stays unpinned so host/macOS venvs are unchanged. --- Dockerfile | 10 ++++++---- deploy/Dockerfile.pwnzzai-workshop | 9 +++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1e0e412..48b9f73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,11 +8,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/* COPY requirements.txt . +# CPU torch first so sentence-transformers does not pull the CUDA wheel (~GB of nvidia-*). +# Do not pin torch in requirements.txt: host/macOS venvs stay unchanged. RUN python -m pip install --upgrade --no-cache-dir pip && \ - pip install --no-cache-dir \ - --retries 10 \ - --timeout 600 \ - -r requirements.txt + pip install --no-cache-dir --retries 10 --timeout 600 \ + torch --index-url https://download.pytorch.org/whl/cpu && \ + pip install --no-cache-dir --retries 10 --timeout 600 \ + -r requirements.txt COPY . . diff --git a/deploy/Dockerfile.pwnzzai-workshop b/deploy/Dockerfile.pwnzzai-workshop index fa70601..e26417a 100644 --- a/deploy/Dockerfile.pwnzzai-workshop +++ b/deploy/Dockerfile.pwnzzai-workshop @@ -13,11 +13,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/* COPY requirements.txt . +# CPU torch first so sentence-transformers does not pull the CUDA wheel (~GB of nvidia-*). RUN python -m pip install --upgrade --no-cache-dir pip && \ - pip install --no-cache-dir \ - --retries 10 \ - --timeout 600 \ - -r requirements.txt + pip install --no-cache-dir --retries 10 --timeout 600 \ + torch --index-url https://download.pytorch.org/whl/cpu && \ + pip install --no-cache-dir --retries 10 --timeout 600 \ + -r requirements.txt COPY . . From 9aa69434653ac177c4752fc353380d99af8dc61c Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 4/8] chore: drop build-essential from app images; keep libzbar0 Current Python deps install from wheels, so gcc was only adding ~300 MB to the final image. libzbar0 stays: it is the runtime library for pyzbar (QR labs). No multi-stage build; the compiler is simply not installed. --- Dockerfile | 3 ++- deploy/Dockerfile.pwnzzai-workshop | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 48b9f73..2ce8d67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,8 @@ FROM python:3.11-slim WORKDIR /app -RUN apt-get update && apt-get install -y --no-install-recommends build-essential \ +# libzbar0: runtime for pyzbar (QR labs). Wheels cover numpy/sklearn/Pillow/faiss; no compiler. +RUN apt-get update && apt-get install -y --no-install-recommends \ libzbar0 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/deploy/Dockerfile.pwnzzai-workshop b/deploy/Dockerfile.pwnzzai-workshop index e26417a..22a59b0 100644 --- a/deploy/Dockerfile.pwnzzai-workshop +++ b/deploy/Dockerfile.pwnzzai-workshop @@ -7,7 +7,8 @@ FROM python:3.11-slim WORKDIR /app -RUN apt-get update && apt-get install -y --no-install-recommends build-essential \ +# libzbar0: runtime for pyzbar (QR labs). Wheels cover numpy/sklearn/Pillow/faiss; no compiler. +RUN apt-get update && apt-get install -y --no-install-recommends \ libzbar0 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* From 8184eb0da75cf2ddef9311cfcffb7c9b89dc5a10 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 5/8] chore: stop copying tests, docs, and CI into the app image COPY . . was shipping tests/, docs/, deploy/, scripts/, and .github/ into the published image. .dockerignore excludes them. make test-docker bind-mounts tests/ so image pytest still runs without baking that tree in. --- .dockerignore | 7 +++++++ Makefile | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.dockerignore b/.dockerignore index 490419b..e06b2a9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -56,6 +56,13 @@ docker-compose.yml # Documentation *.md +# Not needed at runtime (make test-docker bind-mounts tests/ + pytest.ini) +tests/ +docs/ +deploy/ +scripts/ +.github/ + # Testing .pytest_cache/ .coverage diff --git a/Makefile b/Makefile index 83bf75c..13a0167 100644 --- a/Makefile +++ b/Makefile @@ -136,13 +136,21 @@ test-docker-build: ## Build $(TEST_IMAGE) from Dockerfile for test runs docker build -t "$(TEST_IMAGE)" . .PHONY: test-docker -test-docker: test-docker-build ## Run pytest -v inside $(TEST_IMAGE) (installs requirements-test in container) - docker run --rm -t "$(TEST_IMAGE)" \ +test-docker: test-docker-build ## Run pytest -v inside $(TEST_IMAGE) (bind-mounts tests; image excludes tests/) + docker run --rm -t \ + -v "$(CURDIR)/tests:/app/tests:ro" \ + -v "$(CURDIR)/pytest.ini:/app/pytest.ini:ro" \ + -v "$(CURDIR)/requirements-test.txt:/app/requirements-test.txt:ro" \ + "$(TEST_IMAGE)" \ sh -lc 'python -m pip install -q -r requirements-test.txt && pytest -v' .PHONY: test-docker-cov -test-docker-cov: test-docker-build ## pytest with coverage inside container - docker run --rm -t "$(TEST_IMAGE)" \ +test-docker-cov: test-docker-build ## pytest with coverage inside container (bind-mounts tests) + docker run --rm -t \ + -v "$(CURDIR)/tests:/app/tests:ro" \ + -v "$(CURDIR)/pytest.ini:/app/pytest.ini:ro" \ + -v "$(CURDIR)/requirements-test.txt:/app/requirements-test.txt:ro" \ + "$(TEST_IMAGE)" \ sh -lc 'python -m pip install -q -r requirements-test.txt && pytest --cov=application --cov-report=term-missing -v' # ============================================================================= From 1c63f497afd339fbbaba2a65b3dec4053aaa00ac Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 6/8] ci: cache Docker layers in GitHub Actions with Buildx Hosted runners start empty, so every GHCR push rebuilt every layer from scratch. Buildx plus type=gha reuses layers across runs. Tags stay ghcr.io/owasp/pwnzzai:latest and the full git sha. --- .github/workflows/ci-docker.yml | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 74cd5ca..26e01d1 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -47,6 +47,9 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: @@ -54,14 +57,21 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build Docker image - run: | - docker build \ - -t ghcr.io/owasp/pwnzzai:latest \ - -t ghcr.io/owasp/pwnzzai:${{ github.sha }} \ - . + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/owasp/pwnzzai + tags: | + type=raw,value=latest + type=raw,value=${{ github.sha }} - - name: Push Docker image - run: | - docker push ghcr.io/owasp/pwnzzai:latest - docker push ghcr.io/owasp/pwnzzai:${{ github.sha }} + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max From c4464607fdeddcc9b0c4feb812850826a04dee3d Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 7/8] ci: run pytest once and skip Docker work on docs-only changes ci-docker.yml ran a second pytest (3.11, weaker install) on every push, while test.yml already runs the full suite (3.12 + requirements-test.txt). Reuse that workflow, cache pip, cancel overlapping runs, and ignore docs/** / *.md so documentation PRs do not rebuild or push images. --- .github/workflows/ci-docker.yml | 36 ++++++++++----------------------- .github/workflows/test.yml | 27 +++++++++++++++++-------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 26e01d1..d7f9abe 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -3,39 +3,25 @@ name: CI + Docker Build & Push on: push: branches: [ main ] - pull_request: - branches: [ main ] + paths-ignore: + - 'docs/**' + - 'mkdocs.yml' + - '**/*.md' workflow_dispatch: permissions: contents: read packages: write +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libzbar0 - - - name: Install Python dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest - - - name: Run tests - run: pytest -v + uses: ./.github/workflows/test.yml + permissions: + contents: read docker-build: needs: test diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc0cb6d..5f74d4b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,11 +1,21 @@ name: Run Tests -on: - push: - branches: [main] +on: pull_request: branches: [main] + paths-ignore: + - 'docs/**' + - 'mkdocs.yml' + - '**/*.md' + workflow_dispatch: + workflow_call: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: + contents: read jobs: test: @@ -17,8 +27,12 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 - with: + with: python-version: '3.12' + cache: pip + cache-dependency-path: | + requirements.txt + requirements-test.txt - name: Install System Dependencies run: | @@ -30,9 +44,6 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt pip install -r requirements-test.txt - - name: Run Tests - run: pytest -v - - + run: pytest -v From 7e7c95b6c34faa839934406fe5c5d3b316a3429f Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 21 Aug 2026 22:39:14 -0700 Subject: [PATCH 8/8] ci: align lint.yml action versions and skip rules with test.yml lint still used older checkout/setup-python while test and docker jobs did not. Bump to checkout@v4 and setup-python@v5, and apply the same docs-only paths-ignore and concurrency so lint does not run twice or on markdown-only changes. --- .github/workflows/lint.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c2a3c57..7d0c7c7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -2,20 +2,32 @@ name: Lint on: pull_request: + paths-ignore: + - 'docs/**' + - 'mkdocs.yml' + - '**/*.md' push: branches: [ main ] + paths-ignore: + - 'docs/**' + - 'mkdocs.yml' + - '**/*.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.11' - run: pip install ruff - - run: ruff check . \ No newline at end of file + - run: ruff check .