From f578a082d7c185c0c5238f48bf417ef3915cf0d1 Mon Sep 17 00:00:00 2001 From: Lucas Tonon Date: Sat, 18 Jul 2026 23:42:23 -0300 Subject: [PATCH 1/2] ci: add advisory dependency and container image vulnerability scanning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI's only security step was bandit (Python SAST) — no dependency scanning and no image scanning, despite requirements.txt already carrying a manual note pinning litellm to dodge a CVE that a scanner would enforce automatically. Adds three new jobs, all advisory (continue-on-error: true on the scan step) so pre-existing advisories don't break CI: - backend-vuln-scan: pip-audit against backend/requirements.txt - frontend-vuln-scan: npm audit against the frontend lockfile - image-scan: builds trainable-backend/trainable-frontend locally (not pushed) and scans them with Trivy (CRITICAL/HIGH) Each can be flipped to blocking later by dropping continue-on-error once its current advisories are triaged. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4 --- .github/workflows/ci.yml | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09cc77c..affa022 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,6 +84,84 @@ jobs: - run: bandit -r . -x ./tests --severity-level medium -f json -o bandit-report.json || true - run: bandit -r . -x ./tests --severity-level high + backend-vuln-scan: + name: Backend Dependency Vulnerability Scan (advisory) + runs-on: ubuntu-latest + defaults: + run: + working-directory: backend + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: pip + - run: pip install -r requirements.txt pip-audit + # Advisory only: known advisories (e.g. transitive starlette/mcp/ + # python-multipart CVEs) already exist in the dependency tree today, + # and shouldn't block CI. Flip this to blocking (drop + # continue-on-error) once those are triaged and cleared. + - name: pip-audit + run: pip-audit + continue-on-error: true + + frontend-vuln-scan: + name: Frontend Dependency Vulnerability Scan (advisory) + runs-on: ubuntu-latest + defaults: + run: + working-directory: frontend + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + cache-dependency-path: frontend/package-lock.json + - run: npm ci + # Advisory only: known advisories (next/glob/prismjs/postcss/js-yaml) + # already exist in the dependency tree today, and shouldn't block CI. + # Flip this to blocking (drop continue-on-error) once those are + # triaged and cleared. + - name: npm audit + run: npm audit + continue-on-error: true + + image-scan: + name: Container Image Vulnerability Scan (advisory) + runs-on: ubuntu-latest + strategy: + matrix: + include: + - image: trainable-backend + context: ./backend + - image: trainable-frontend + context: ./frontend + target: runner + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Build ${{ matrix.image }} image (local only, not pushed) + uses: docker/build-push-action@v5 + with: + context: ${{ matrix.context }} + target: ${{ matrix.target || '' }} + push: false + load: true + tags: ${{ matrix.image }}:ci-scan + # Advisory only: base-image and OS-package advisories aren't triaged + # yet and shouldn't block CI. Flip to blocking (drop + # continue-on-error, or set exit-code back to 1 without the wrapper) + # once they are. + - name: Trivy scan + uses: aquasecurity/trivy-action@0.36.0 + continue-on-error: true + with: + image-ref: ${{ matrix.image }}:ci-scan + format: table + severity: "CRITICAL,HIGH" + exit-code: "1" + frontend-lint: name: Frontend Lint & Typecheck runs-on: ubuntu-latest From 4a0ca9bc468fb79eed76e6fb63ae344b43bab6ac Mon Sep 17 00:00:00 2001 From: Lucas Tonon Date: Mon, 20 Jul 2026 10:04:00 -0300 Subject: [PATCH 2/2] fix(review): address Greptile findings on #156 - pip-audit job: scan under Python 3.13 to match backend/Dockerfile (python:3.13-slim), so audited dependency resolution mirrors what ships in production. - Trivy action: pin to immutable commit SHA ed142fd0673e97e23eac54620cfb913e5ce36c25 (v0.36.0). This also fixes a broken ref: the previous `@0.36.0` tag does not exist upstream (trivy-action tags are v-prefixed), so the image-scan job would have failed to resolve the action. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4 --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index affa022..5f9c076 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,9 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: "3.11" + # Match backend/Dockerfile (python:3.13-slim) so the audited + # dependency resolution mirrors what actually ships. + python-version: "3.13" cache: pip - run: pip install -r requirements.txt pip-audit # Advisory only: known advisories (e.g. transitive starlette/mcp/ @@ -154,7 +156,7 @@ jobs: # continue-on-error, or set exit-code back to 1 without the wrapper) # once they are. - name: Trivy scan - uses: aquasecurity/trivy-action@0.36.0 + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 continue-on-error: true with: image-ref: ${{ matrix.image }}:ci-scan