From c5affa4f48fbcea9ca50a0000981e7aab19f1c31 Mon Sep 17 00:00:00 2001 From: alovladi007 <83262803+alovladi007@users.noreply.github.com> Date: Thu, 30 Jul 2026 19:44:26 -0400 Subject: [PATCH] =?UTF-8?q?fix(security):=20clear=20the=20v0.1.0=20Trivy?= =?UTF-8?q?=20gate=20=E2=80=94=20CVE=20dependency=20upgrades=20+=20pip-les?= =?UTF-8?q?s=20runtime=20images?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The second CD firing did its job: the Trivy HIGH/CRITICAL gate stopped the release on 11 fixable findings per image. All cleared, the honest way: Dependency upgrades (full suites green on the new set): - python-jose 3.3.0 → 3.5.0 — CRITICAL CVE-2024-33663 (ECDSA algorithm confusion) in OUR JWT LIBRARY. - python-multipart 0.0.6 → 0.0.32 (5 HIGH DoS CVEs — login form parsing runs through this). - fastapi 0.104.1 → 0.141.1 / starlette <0.28 → 1.3.1 (3 HIGH CVEs; starlette is fastapi-pinned so this is the coupled jump), pydantic 2.5.0 → 2.13.4, prometheus-fastapi-instrumentator >=8 (6.x cannot walk starlette 1.x routes — the one break the upgrade caused, caught by the lims suite going 66-red until the bump). - cryptography pinned 48.0.1 (2 HIGHs fixed vs 44.x; 49.0.0's macOS wheel is broken — 48.0.1 imports clean on every platform we build on). - msgpack >=1.2.1, setuptools >=78.1.1 explicit floors. Runtime images (all three backends): - Upgrade pip/setuptools/wheel BEFORE dependency install (stale toolchain carried fixable HIGHs into every image). - Then REMOVE pip from the runtime image entirely: pip 26.2 VENDORS msgpack 1.1.2 + setuptools 70.3.0 (pip/_vendor) with no patched pip release to move to — and runtime containers have no business installing packages anyway. Zero fixable HIGH/CRITICAL findings on the rebuilt image, verified with a --pull --no-cache build + local Trivy using the same flags as the gate. CD workflow: security-events: write on the build job (the SARIF upload failed "Resource not accessible by integration" without it). Tests: the shared tracing fixture now attaches its exporter to whichever tracer provider actually won the single-shot global slot, so the suite holds under any pytest collection order (the instrumentator upgrade surfaced a cross-suite pollution only reachable in combined invocations CI never runs — fixed anyway). Verified live: full compose stack rebuilt on the new set — migrate exit 0, all backends healthy, 4-test smoke green. Suites: analysis 304, pc 440, lims 68, shared 88. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/cd.yml | 3 +++ requirements.txt | 17 +++++++++++++---- services/analysis/Dockerfile | 8 ++++++++ services/analysis/requirements.txt | 21 +++++++++++++++------ services/lims/Dockerfile | 8 ++++++++ services/lims/requirements.txt | 19 ++++++++++++++----- services/process_control/Dockerfile | 8 ++++++++ services/process_control/requirements.txt | 19 ++++++++++++++----- services/shared/tests/test_tracing.py | 8 ++++++++ 9 files changed, 91 insertions(+), 20 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index cc5042ad..9f66c8ef 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -50,6 +50,9 @@ jobs: permissions: contents: read packages: write + # SARIF upload to code scanning (the v0.1.0 run's upload step failed + # with "Resource not accessible by integration" without this). + security-events: write strategy: fail-fast: false matrix: diff --git a/requirements.txt b/requirements.txt index 01f18f70..a9150d91 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,10 +23,10 @@ pyvisa>=1.12.0 pyvisa-py>=0.5.0 # API & Web -fastapi>=0.100.0 +fastapi==0.141.1 uvicorn[standard]>=0.23.0 -python-multipart>=0.0.6 -python-jose[cryptography]>=3.3.0 +python-multipart==0.0.32 +python-jose[cryptography]==3.5.0 # Middleware used by all three services' main.py (rate limiting, session # signing, structured logging). These were pinned only in the per-service # requirements.txt, so a root-only install (and CI's unit job) could not import @@ -39,7 +39,7 @@ structlog>=24.1 # needs both; prometheus_client is imported at module level in # services/shared/observability/metrics.py. prometheus-client>=0.20 -prometheus-fastapi-instrumentator>=7.0 +prometheus-fastapi-instrumentator>=8,<9 # httpx — imported at module level in services/shared/auth/jwt.py (OIDC) and by # Starlette's TestClient. Was only in the per-service reqs. httpx>=0.24,<0.26 @@ -124,3 +124,12 @@ opentelemetry-instrumentation-fastapi>=0.46b0 opentelemetry-instrumentation-sqlalchemy>=0.46b0 opentelemetry-instrumentation-celery>=0.46b0 opentelemetry-instrumentation-redis>=0.46b0 + +# CVE hygiene (v0.1.0 Trivy gate): pinned alongside the jose 3.5 +# upgrade; 44.0.1 carries the CVE-2024-12797 fix and ships working +# wheels on every platform we build for. +cryptography==48.0.1 +msgpack>=1.2.1 +# something in the dependency tree downgrades setuptools below the +# CVE-2025-47273 fix; pin the floor explicitly. +setuptools>=78.1.1 diff --git a/services/analysis/Dockerfile b/services/analysis/Dockerfile index 5772179f..de08656c 100644 --- a/services/analysis/Dockerfile +++ b/services/analysis/Dockerfile @@ -14,7 +14,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* COPY services/analysis/requirements.txt . +# Toolchain first: stale wheel/setuptools (jaraco.context) carried +# fixable HIGH CVEs into every image (v0.1.0 Trivy gate). +RUN pip install --no-cache-dir --upgrade pip setuptools wheel RUN pip install --no-cache-dir -r requirements.txt +# Runtime containers don't need pip — and pip VENDORS msgpack/setuptools +# copies (pip/_vendor) that carry fixable-looking CVEs no pip release has +# patched yet; removing pip both clears the Trivy gate honestly and +# shrinks the attack surface. (Real setuptools stays installed.) +RUN python -m pip uninstall -y pip # services/shared is a sibling package; the analysis service imports from # it via `from services.shared...` and the legacy `from db.base...` style diff --git a/services/analysis/requirements.txt b/services/analysis/requirements.txt index 55327ec3..1b48950c 100644 --- a/services/analysis/requirements.txt +++ b/services/analysis/requirements.txt @@ -12,15 +12,15 @@ # ---------------------------------------------------------------------------- # Web framework # ---------------------------------------------------------------------------- -fastapi==0.104.1 +fastapi==0.141.1 uvicorn[standard]==0.24.0 -python-multipart==0.0.6 -starlette<0.28 +python-multipart==0.0.32 +starlette==1.3.1 # ---------------------------------------------------------------------------- # Validation / config # ---------------------------------------------------------------------------- -pydantic==2.5.0 +pydantic==2.13.4 python-dotenv==1.0.0 pyyaml>=6.0 @@ -35,7 +35,7 @@ alembic>=1.13.0 # ---------------------------------------------------------------------------- # Auth # ---------------------------------------------------------------------------- -python-jose[cryptography]==3.3.0 +python-jose[cryptography]==3.5.0 passlib[bcrypt]==1.7.4 # OIDC + session middleware (Phase 4.1) @@ -53,7 +53,7 @@ prometheus-client>=0.20 # fastapi==0.104.1 / starlette<0.28 pins below (a fresh `pip install` — i.e. the # Docker build — fails with ResolutionImpossible). 6.1.0 exposes the same # Instrumentator API and resolves cleanly with starlette 0.27. -prometheus-fastapi-instrumentator>=6.1,<7 +prometheus-fastapi-instrumentator>=8,<9 # ---------------------------------------------------------------------------- # Numerical & scientific @@ -117,3 +117,12 @@ opentelemetry-sdk>=1.25.0 opentelemetry-exporter-otlp>=1.25.0 opentelemetry-instrumentation-fastapi>=0.46b0 opentelemetry-instrumentation-sqlalchemy>=0.46b0 + +# CVE hygiene (v0.1.0 Trivy gate): pinned alongside the jose 3.5 +# upgrade; 44.0.1 carries the CVE-2024-12797 fix and ships working +# wheels on every platform we build for. +cryptography==48.0.1 +msgpack>=1.2.1 +# something in the dependency tree downgrades setuptools below the +# CVE-2025-47273 fix; pin the floor explicitly. +setuptools>=78.1.1 diff --git a/services/lims/Dockerfile b/services/lims/Dockerfile index 78db1419..434e2431 100644 --- a/services/lims/Dockerfile +++ b/services/lims/Dockerfile @@ -13,7 +13,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* COPY services/lims/requirements.txt . +# Toolchain first: stale wheel/setuptools (jaraco.context) carried +# fixable HIGH CVEs into every image (v0.1.0 Trivy gate). +RUN pip install --no-cache-dir --upgrade pip setuptools wheel RUN pip install --no-cache-dir -r requirements.txt +# Runtime containers don't need pip — and pip VENDORS msgpack/setuptools +# copies (pip/_vendor) that carry fixable-looking CVEs no pip release has +# patched yet; removing pip both clears the Trivy gate honestly and +# shrinks the attack surface. (Real setuptools stays installed.) +RUN python -m pip uninstall -y pip COPY services/shared /app/services/shared COPY services/lims/app /app/app diff --git a/services/lims/requirements.txt b/services/lims/requirements.txt index 3bb964b5..46a8ef7f 100644 --- a/services/lims/requirements.txt +++ b/services/lims/requirements.txt @@ -2,12 +2,12 @@ # Reconciled in Session 1.5 from a static import audit of services/lims/app/. # Web framework -fastapi==0.104.1 +fastapi==0.141.1 uvicorn[standard]==0.24.0 -python-multipart==0.0.6 +python-multipart==0.0.32 # Validation / config -pydantic==2.5.0 +pydantic==2.13.4 python-dotenv==1.0.0 # Database @@ -15,7 +15,7 @@ sqlalchemy==2.0.23 psycopg[binary]==3.1.13 # Auth -python-jose[cryptography]==3.3.0 +python-jose[cryptography]==3.5.0 passlib[bcrypt]==1.7.4 # OIDC + session middleware (Phase 4.1) @@ -33,7 +33,7 @@ prometheus-client>=0.20 # fastapi==0.104.1 / starlette<0.28 pins (a fresh `pip install` — the Docker # build — fails with ResolutionImpossible). 6.1.0 exposes the same Instrumentator # API and resolves cleanly with starlette 0.27. -prometheus-fastapi-instrumentator>=6.1,<7 +prometheus-fastapi-instrumentator>=8,<9 # Reporting / labels jinja2>=3.1 @@ -51,3 +51,12 @@ opentelemetry-sdk>=1.25.0 opentelemetry-exporter-otlp>=1.25.0 opentelemetry-instrumentation-fastapi>=0.46b0 opentelemetry-instrumentation-sqlalchemy>=0.46b0 + +# CVE hygiene (v0.1.0 Trivy gate): pinned alongside the jose 3.5 +# upgrade; 44.0.1 carries the CVE-2024-12797 fix and ships working +# wheels on every platform we build for. +cryptography==48.0.1 +msgpack>=1.2.1 +# something in the dependency tree downgrades setuptools below the +# CVE-2025-47273 fix; pin the floor explicitly. +setuptools>=78.1.1 diff --git a/services/process_control/Dockerfile b/services/process_control/Dockerfile index c82bae03..a92b1891 100644 --- a/services/process_control/Dockerfile +++ b/services/process_control/Dockerfile @@ -14,7 +14,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* COPY services/process_control/requirements.txt . +# Toolchain first: stale wheel/setuptools (jaraco.context) carried +# fixable HIGH CVEs into every image (v0.1.0 Trivy gate). +RUN pip install --no-cache-dir --upgrade pip setuptools wheel RUN pip install --no-cache-dir -r requirements.txt +# Runtime containers don't need pip — and pip VENDORS msgpack/setuptools +# copies (pip/_vendor) that carry fixable-looking CVEs no pip release has +# patched yet; removing pip both clears the Trivy gate honestly and +# shrinks the attack surface. (Real setuptools stays installed.) +RUN python -m pip uninstall -y pip COPY services/shared /app/services/shared COPY services/process_control/app /app/app diff --git a/services/process_control/requirements.txt b/services/process_control/requirements.txt index d65627f4..181fc15f 100644 --- a/services/process_control/requirements.txt +++ b/services/process_control/requirements.txt @@ -4,13 +4,13 @@ # added auth, async-jobs, and OPC-UA packages discovered by the audit. # FastAPI and web framework -fastapi==0.104.1 +fastapi==0.141.1 uvicorn[standard]==0.24.0 -python-multipart==0.0.6 +python-multipart==0.0.32 websockets==12.0 # Validation / config -pydantic==2.5.0 +pydantic==2.13.4 python-dotenv==1.0.0 # Database @@ -20,7 +20,7 @@ alembic==1.12.1 psycopg[binary]==3.1.13 # Auth -python-jose[cryptography]==3.3.0 +python-jose[cryptography]==3.5.0 passlib[bcrypt]==1.7.4 # Phase 4.2 — middleware (request-ID, rate limiting, structlog) @@ -35,7 +35,7 @@ prometheus-client>=0.20 # fastapi==0.104.1 / starlette<0.28 pins (a fresh `pip install` — the Docker # build — fails with ResolutionImpossible). 6.1.0 exposes the same Instrumentator # API and resolves cleanly with starlette 0.27. -prometheus-fastapi-instrumentator>=6.1,<7 +prometheus-fastapi-instrumentator>=8,<9 # Async / background jobs celery>=5.3,<6.0 @@ -75,3 +75,12 @@ opentelemetry-sdk>=1.25.0 opentelemetry-exporter-otlp>=1.25.0 opentelemetry-instrumentation-fastapi>=0.46b0 opentelemetry-instrumentation-sqlalchemy>=0.46b0 + +# CVE hygiene (v0.1.0 Trivy gate): pinned alongside the jose 3.5 +# upgrade; 44.0.1 carries the CVE-2024-12797 fix and ships working +# wheels on every platform we build for. +cryptography==48.0.1 +msgpack>=1.2.1 +# something in the dependency tree downgrades setuptools below the +# CVE-2025-47273 fix; pin the floor explicitly. +setuptools>=78.1.1 diff --git a/services/shared/tests/test_tracing.py b/services/shared/tests/test_tracing.py index 0ccd6a5e..32d0ecc6 100644 --- a/services/shared/tests/test_tracing.py +++ b/services/shared/tests/test_tracing.py @@ -46,6 +46,14 @@ def in_memory_exporter(): # provider — but if pytest gives us a fresh process, this is the # installation point. trace.set_tracer_provider(provider) + # set_tracer_provider is single-shot per process: when another suite + # (e.g. lims importing its app) already installed a provider, the call + # above no-ops and spans would flow to THAT provider — attach our + # exporter to whichever provider actually won, so the assertions hold + # regardless of test-collection order. + active = trace.get_tracer_provider() + if active is not provider and hasattr(active, "add_span_processor"): + active.add_span_processor(SimpleSpanProcessor(exporter)) return exporter