Skip to content

Commit f70af73

Browse files
fix(docker): purge uv wheel cache after opencv swap [security] (#570)
## Summary Follow-up to #569 (v0.1.4). That PR replaced the PyPI `opencv-python` wheel with an ffmpeg-free build, but image scanners were still flagging the 14 ffmpeg CVEs against v0.1.4. Root cause is scanner scope, not a broken replacement. ## Root cause `uv pip uninstall` only drops a package from `site-packages`. The extracted wheel archive stays in the uv cache. Inspecting the pushed v0.1.4 image: - ✅ `cv2.__version__` reports `4.12.0` (our replacement wheel) - ✅ `site-packages/cv2/` has no `.libs/` directory - ❌ `/home/notebook-user/.cache/uv/archive-v0/<hash>/opencv_python.libs/` still contains the full extracted old wheel: - `libavcodec-*.so.59.37.100` - `libavformat-*.so.59.27.100` - `libavutil-*.so.57.28.100` - plus `libavfilter`, `libavdevice`, `libswscale`, `libswresample` SO-version suffixes (avcodec 59.37 / avformat 59.27 / avutil 57.28) are ffmpeg 5.1.x — matching the CVE set the upstream PR called out. Scanners walk the whole filesystem and flag these even though nothing links against them at runtime. `UV_LINK_MODE=copy` (set globally in this Dockerfile) compounds it — the cache keeps its own copy independent of `site-packages`. ## Fix Add `uv cache clean` to the end of the opencv replacement `RUN` to wipe the cache (including the old opencv wheel archive) from the final image layer. Single minimal change — scoped to the opencv-fix RUN, not a broader image-slimming pass. Safe because `UV_LINK_MODE=copy` means the live venv copies files out of cache — wiping the cache doesn't affect the installed packages. ## False positives ignored (not fixed here) Two other `libav*` filenames in the image that are **not** ffmpeg and don't trigger these CVEs: - `/usr/lib/libreoffice/program/libavmedia{gst,lo}.so` — LibreOffice's \"avmedia\" framework shim - `pillow.libs/libavif-*.so.16` — AV1 image codec ## Version / Changelog - Bumps service version `0.1.4` → `0.1.5` - `CHANGELOG.md` entry under `0.1.5` → Security - No `uv lock` changes ## Test plan - [ ] `make docker-build` succeeds on `amd64` and `arm64` - [ ] In the rebuilt image, `find / -name \"libavcodec*\" -o -name \"libavformat*\" -o -name \"libswscale*\"` returns nothing under `/home/notebook-user/.cache/uv/` and nothing under `site-packages/cv2/.libs/` - [ ] `cv2.__version__` still reports `4.12.0.88` and `import cv2; cv2.imdecode(...)` smoke check works - [ ] Container scan of the rebuilt image no longer flags the 14 ffmpeg CVEs 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: a single Docker build-step cleanup (`uv cache clean`) plus version/changelog bumps; main risk is unintended impact on Docker layer caching or build time, not runtime behavior. > > **Overview** > Removes leftover ffmpeg `.so` files from the built image by adding `uv cache clean` after uninstalling/reinstalling OpenCV wheels in the Dockerfile, preventing scanners from flagging CVEs from cached wheel contents. > > Bumps the service version to `0.1.5` and adds a matching `CHANGELOG.md` security entry describing the cache purge. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f73143d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 03b57e0 commit f70af73

3 files changed

Lines changed: 16 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.1.5
2+
3+
### Security
4+
5+
- **Purge uv wheel cache after opencv swap**: The 0.1.4 Dockerfile uninstalled the PyPI `opencv-python` wheel and installed the ffmpeg-free replacement, but the original wheel's extracted contents (including `libavcodec.so.59.*` and friends) remained in `~/.cache/uv/archive-v0/…/opencv_python.libs/`. Image scanners still flagged the 14 ffmpeg CVEs because they walk the whole filesystem. Added `uv cache clean` at the end of the opencv replacement `RUN` so the vulnerable libs are evicted from the final image layer.
6+
17
## 0.1.4
28

39
### Security

Dockerfile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,15 @@ RUN ARCH=$(uname -m) && \
113113
uv pip uninstall "$pkg" 2>/dev/null || true; \
114114
done && \
115115
uv pip install --no-deps /tmp/"${WHEEL}" && \
116-
rm /tmp/"${WHEEL}"
116+
rm /tmp/"${WHEEL}" && \
117+
# `uv pip uninstall` only drops the package from site-packages; the wheel
118+
# cache under ~/.cache/uv still holds the extracted opencv-python archive
119+
# (including its bundled `.libs/libavcodec.so.59.*` + friends). Scanners
120+
# see those files and still flag the 14 ffmpeg CVEs even though nothing
121+
# links against them at runtime. Wipe the cache so the image layer no
122+
# longer contains the vulnerable libs. Safe because UV_LINK_MODE=copy
123+
# ensures installed files are independent copies, not cache hardlinks.
124+
uv cache clean
117125

118126
COPY --chown=${NB_USER}:${NB_USER} CHANGELOG.md CHANGELOG.md
119127
COPY --chown=${NB_USER}:${NB_USER} logger_config.yaml logger_config.yaml
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.1.4" # pragma: no cover
1+
__version__ = "0.1.5" # pragma: no cover

0 commit comments

Comments
 (0)