Skip to content

fix(security): floor litellm/wandb/lxml past known CVEs; relax stale click cap - #1507

Open
nicgupta-nvidia wants to merge 13 commits into
mainfrom
fix/security-dependency-floors
Open

fix(security): floor litellm/wandb/lxml past known CVEs; relax stale click cap#1507
nicgupta-nvidia wants to merge 13 commits into
mainfrom
fix/security-dependency-floors

Conversation

@nicgupta-nvidia

@nicgupta-nvidia nicgupta-nvidia commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

What

Remediates all 17 High findings from the July 30 Trivy scan of:

nvcr.io/0953339617667984/nemo-skills:4fbf5d54

Component Scanned version Remediation Trivy High findings
GitPython 3.1.51 GitPython>=3.1.55 6
datamodel-code-generator 0.25.7 >=0.64.0; BFCL runtime pin also moved to ==0.64.0 8
W&B wandb-core Go stdlib Go 1.26.4 rebuild with Go 1.26.5 1
W&B wandb-core gRPC 1.81.1 1.82.1 1
W&B wandb-core x/text 0.38.0 0.40.0 1
Total 17

July 30 nSpect reconciliation

The nSpect scan of the same exact image reports:

  • Policy stop: 15 High / 0 Critical
  • Detailed export: 16 High / 0 Critical
  • Difference: CVE-2026-39822 (Go stdlib) appears in the detailed export but not in Gate Actions.

All 16 detailed nSpect High advisories are covered by this PR:

  • 8 datamodel-code-generator advisories
  • 6 GitPython advisories
  • 1 W&B core gRPC advisory
  • 1 W&B core Go stdlib advisory

nSpect also reports a non-CVE global-policy warning for .git metadata under /root/.cache/uv/sdists-v9. Commit 8817cf64 removes the build-only uv cache from the final image.

Why W&B needs a patched core

wandb==0.28.1 is the latest W&B release, but its published core still uses Go 1.26.4, gRPC 1.82.0, and x/text 0.38.0. A normal package bump therefore does not clear the final three Trivy findings.

The Dockerfile now:

  1. pins W&B's dependency-only commit e1184091520c9b44aa1096fdb27b2f4bf52f26d7;
  2. builds wandb-core in a golang:1.26.5 builder stage using W&B's upstream build tags and vendored modules;
  3. rejects the build unless go version -m reports Go 1.26.5, gRPC 1.82.1, and x/text 0.40.0;
  4. copies only the verified executable into the Ubuntu runtime image; and
  5. runs the patched core's help path and verifies its embedded commit SHA during the image build.

wandb is pinned to 0.28.1 so its Python package remains a deterministic protocol pair with the patched core.

Advisory coverage

Existing PR scope retained

  • litellm[caching]==1.84.10 for GHSA-4xpc-pv4p-pm3w
  • lxml>=6.1.0 for GHSA-vfmq-68hx-4jfw
  • click cap removal and typer>=0.16 compatibility floor
  • uv override documentation and dependency regression tests

The branch has also been merged with current main.

Validation

Completed locally:

  • tests/test_requirements_versions.py: 26 passed
  • isolated GitPython 3.1.55 and datamodel-code-generator 0.64.0 functional tests: 2 passed
  • isolated W&B 0.28.1 offline init/log/finish smoke test: passed
  • Ruff 0.12.9 lint and format checks: passed
  • git diff --check: passed

Completed in GitHub Actions before the final cache-cleanup commit:

  • Linux NeMo-Skills image build: passed
  • patched wandb-core Go/module assertions and embedded commit-SHA smoke check: passed
  • final image resolved GitPython==3.1.57, datamodel-code-generator==0.71.0, and wandb==0.28.1
  • full CPU test suite: passed
  • pre-commit, copyright, and DCO: passed

The latest commit must complete the same required checks. A fresh published-image nSpect and Trivy scan is still required before release.

Security regression tests

  • static guards prevent lowering the GitPython and datamodel-code-generator floors;
  • BFCL cannot silently reinstall datamodel-code-generator 0.25.7;
  • W&B must remain pinned to the Python version paired with the patched core;
  • the Dockerfile must retain the immutable W&B commit, fixed Go builder, module checks, binary replacement, and runtime smoke check;
  • the final image must remove uv's build-only Git cache;
  • functional tests exercise GitPython repository initialization, datamodel-code-generator import/version, W&B offline logging, NeMo-Skills' W&B call contract, LiteLLM integration, CLI rendering, and lxml parsing.

Notes

  • nltk (GHSA-p4gq-832x-fm9v) remains outside this PR because the advisory has no patched release.
  • GPU tests remain opt-in and are not required for these dependency and container-build changes.

July 31 follow-up: msgpack and setuptools

A fresh Trivy 0.71.2 multi-architecture scan of the NVFlow release-baseline image found two additional distinct High findings on both platforms:

nvcr.io/0953339617667984/nemo-skills:dev-f23ae32d

OCI index: sha256:11e67bb94e941329681cb4b600ba03440c3344df05becc8de9974126fcd16414

Advisory Package Scanned version Fixed floor amd64 arm64
GHSA-6v7p-g79w-8964 msgpack 1.1.2 >=1.2.1 1 High 1 High
CVE-2025-47273 setuptools 70.3.0 >=78.1.1 1 High 1 High
Total 2 High 2 High

These are four architecture-aware rows but two unique advisory/package findings.

Commit 672a6d80 adds durable upstream enforcement:

  • resolver-wide uv overrides keep the complete environment at msgpack>=1.2.1 and setuptools>=78.1.1;
  • the root, Core, and Tools build backends require setuptools>=78.1.1;
  • the NeMo-Skills image installs a safe setuptools floor before dependency resolution and rejects the final image unless both fixed floors are present; and
  • static and functional regression tests prevent either vulnerable floor from being reintroduced.

The current lock already resolves msgpack==1.2.1 and setuptools==83.0.0; the explicit floors make those safe choices policy rather than incidental resolver output.

July 31 validation

  • tests/test_requirements_versions.py: 32 passed
  • isolated runtime resolution: msgpack==1.2.1, setuptools==83.0.0
  • uv lock --check: passed (294 packages)
  • Ruff lint/format and all configured pre-commit hooks on changed files: passed
  • git diff --check: passed

A rebuilt multi-architecture image and fresh Trivy/nSpect scan are still required to verify the published-image result.

…click cap

- litellm[caching] 1.83.14 -> 1.84.10: GHSA-4xpc-pv4p-pm3w (Critical) —
  1.83.x leaks the API key to an arbitrary attacker-controlled Host header;
  fixed in 1.84.0. Minimal exact-pin jump; resolves with the existing
  httpx[http2]>=0.28.1 override (litellm 1.84.10 needs httpx>=0.28.0).
- wandb -> >=0.27.1: the bundled wandb-core Go binary in older wheels ships
  golang.org/x/crypto 0.50.0 + Go 1.26.2 stdlib with 7 Critical / 13 High
  CVEs (incl. GHSA-x527-x647-q7gg et al.); 0.27.1 is the first release
  embedding patched x/crypto 0.52.0 (verified on both arches).
- click < 8.2.0 cap removed + typer >= 0.16: the cap guarded against the
  typer/click-8.2 make_metavar break (ai-dynamo/dynamo#1039, closed
  2025-06-26, fixed in typer >=0.16); wandb>=0.27.1 requires click>=8.2,
  and requires-python >=3.10 satisfies click 8.2's floor.
- lxml -> >=6.1.0 (stem extra): GHSA-vfmq-68hx-4jfw (High).

Validation: uv pip compile of core+pipeline (py3.10, with the pyproject
overrides) resolves cleanly — litellm 1.84.10 / wandb 0.28.0 / click 8.4.2 /
typer 0.26.8 / httpx 0.28.1; stem extra resolves with lxml 6.1.1. Runtime
smoke on the resolved set: litellm/wandb import clean; typer --help
rendering (the exact make_metavar crash path) passes under click 8.4.

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Dependency requirements now include security floors and compatibility pins, BFCL uses the updated code generator version, Nemo Skills builds and installs a pinned W&B core binary, and regression plus functional tests validate the updated dependency behavior.

Changes

Dependency security and compatibility updates

Layer / File(s) Summary
Dependency constraints and BFCL pin
core/requirements.txt, requirements/stem.txt, requirements/common-tests.txt, nemo_skills/inference/eval/bfcl.py
Adds security minimums for GitPython, datamodel-code-generator, and lxml; constrains MCP and W&B versions; adds Python 3.10 TOML support; and updates the BFCL code generator pin.
Patched W&B core image integration
dockerfiles/Dockerfile.nemo-skills
Builds wandb-core from a pinned commit, verifies Go dependency versions, installs dependencies through the project configuration, and replaces the bundled binary.
Requirement and Docker regression coverage
tests/test_requirements_versions.py
Validates dependency floors and pins, BFCL compatibility, W&B core build metadata, pipeline compatibility assertions, stem requirements, and PEP 508 parsing.
Functional dependency compatibility tests
tests/test_dependency_functional.py
Adds GitPython and datamodel-code-generator checks while retaining functional coverage for litellm, CLI behavior, W&B offline operation, and lxml parsing.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: gwarmstrong

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR's primary security dependency updates and the removal of the stale Click version cap.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/security-dependency-floors

Comment @coderabbitai help to get the list of available commands.

@nicgupta-nvidia nicgupta-nvidia self-assigned this Jul 9, 2026
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Note

Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

2 similar comments
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Note

Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Note

Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ Unit tests committed locally. Commit: 07acd2ccc5aed23517851655d7112cfb704e9b7b

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ Unit tests committed locally. Commit: e441a66eb09f718a0d49194cedc6abf56d9763e7

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ Created PR with unit tests: #1508

CodeRabbit's test generation ran twice and committed two near-duplicate
suites (test_dependency_pins.py + test_requirements_versions.py) covering
the same pins. Keep the more robust one (operator-keyed specifier parsing
instead of next(iter(specifier)), which is order-fragile on multi-spec
requirements) and graft the three tests unique to the deleted file:
pyproject stale-comment guards, pipeline-lines-parseable, and the
wandb/typer click-comment consistency check.

Also:
- fix the copyright year (2026, not 2025)
- add tomli (python_version < 3.11) to common-tests.txt so the pyproject
  override tests actually RUN on the CI's Python 3.10 instead of
  silently skipping (tomllib is stdlib only from 3.11)
- add the missing trailing newline that failed the pre-commit
  end-of-file-fixer hook on the generated files

17 tests pass on Python 3.10 with the CI's -m 'not gpu' selection;
pre-commit (pinned ruff) clean.

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_requirements_versions.py (1)

95-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract a shared helper for specifier-floor extraction.

The {spec.operator: spec.version for spec in req.specifier} pattern is repeated across four test methods. A small helper reduces duplication and keeps the assertions consistent if the extraction logic ever needs to change (e.g., handling multiple specifiers of the same operator).

♻️ Proposed helper
+def _get_specifier(req: Requirement, operator: str) -> Version:
+    """Return the parsed Version for the given specifier operator, asserting it's present."""
+    specs = {spec.operator: spec.version for spec in req.specifier}
+    assert operator in specs, f"expected a '{operator}' specifier for {req.name}, got {req.specifier}"
+    return Version(specs[operator])
+
+
 class TestCoreRequirements:
     ...
     def test_litellm_pin_fixes_ghsa_4xpc_pv4p_pm3w(self):
         req, comment = _find_requirement(CORE_REQUIREMENTS, "litellm")
         assert "caching" in req.extras, "litellm[caching] extra must be preserved"
-
-        # Must be pinned to an exact version (== specifier) so the resolver is deterministic.
-        specs = {spec.operator: spec.version for spec in req.specifier}
-        assert "==" in specs, f"expected an exact pin for litellm, got specifier {req.specifier}"
-
-        pinned_version = Version(specs["=="])
+        pinned_version = _get_specifier(req, "==")

Also applies to: 113-114, 156-157, 178-179

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_requirements_versions.py` around lines 95 - 96, The specifier
extraction logic is duplicated across multiple test methods in the requirements
version tests, so add a shared helper for turning a requirement’s specifiers
into a usable mapping or floor value. Update the affected assertions in the test
class that currently build specs from req.specifier so they call this helper
instead, keeping the exact-pin checks unchanged while centralizing the
extraction behavior in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_requirements_versions.py`:
- Around line 95-96: The specifier extraction logic is duplicated across
multiple test methods in the requirements version tests, so add a shared helper
for turning a requirement’s specifiers into a usable mapping or floor value.
Update the affected assertions in the test class that currently build specs from
req.specifier so they call this helper instead, keeping the exact-pin checks
unchanged while centralizing the extraction behavior in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0ea160ee-449e-4976-b41b-78cdb3607f1a

📥 Commits

Reviewing files that changed from the base of the PR and between 49cd94e and 01bd214.

📒 Files selected for processing (2)
  • requirements/common-tests.txt
  • tests/test_requirements_versions.py

…ed deps

test_requirements_versions.py only asserts the pins statically. Add functional
coverage that drives litellm 1.84.10, typer/click, and wandb through NeMo-Skills'
own code paths (CPU-only, hermetic — no sandbox, no live endpoint, no API keys)
so a resolve to a behavior-divergent version fails CI, not a production run:

  * litellm: OpenAIModel.litellm_kwargs binds api_key to the configured
    base_url/api_base only (GHSA-4xpc-pv4p-pm3w regression), generate_async
    calls litellm.acompletion with those credentials and parses the 1.84
    response, and the imported litellm exception/type surface still exists.
  * typer/click: ns CLI --help + per-command help render Parameter.make_metavar
    (the click 8.2 break typer>=0.16 fixes) and unknown commands are usage errors.
  * wandb: log_random_samples matches the wandb 0.28 init/save/summary/finish
    contract, and a real offline init/finish cycle runs with no account.
  * lxml: importorskip-guarded real parse (optional stem extra).

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
Bring in #1509 (drop deleted vedas pin) so the sandbox image build — and
therefore this PR's CI — is unblocked.

Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
gwarmstrong added a commit that referenced this pull request Jul 28, 2026
Cherry-picked from #1507 (fix/security-dependency-floors), which is the
last configuration in which the full CPU suite passed (725 passed, 0
failed on 2026-07-14).

With click pinned below 8.2 the ns CLI stops accepting underscore-style
option names, so every test that shells out to `ns eval --output_dir=...`
or `ns summarize_results --max_seq_len=...` fails with "Missing option
'--output-dir'" / "No such option: --max_seq_len". The typer floor moves
to 0.16 alongside it because that is the first release compatible with
click 8.2 (fixes the make_metavar break that motivated the original pin).

Only the CLI-relevant pair is taken here. #1507's litellm, wandb and stem
security floors are left to that PR.

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>
gwarmstrong added a commit that referenced this pull request Jul 28, 2026
Dropping the click<8.2 cap alone was not enough: wandb 0.26.1 only
requires click>=8.0.1, so uv still settled on click 8.1.8 and the CPU
suite failed identically (10 failed, 685 passed).

wandb 0.27.1 is the first release requiring click>=8.2.0, which is what
actually moves the resolver. Taken from #1507, the last configuration in
which the full suite passed.

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>
gwarmstrong added a commit that referenced this pull request Jul 28, 2026
This is the actual root cause of the CPU suite failures, and the reason
removing the repo's own `click < 8.2.0` cap changed nothing: litellm
1.83.14 declares an exact `click==8.1.8` dependency, capping the entire
tree below click 8.2 regardless of what this repo asks for.

uv spelled it out when wandb>=0.27.1 was added:

    Because wandb>=0.27.1 depends on click>=8.2.0 and litellm==1.83.14
    depends on click==8.1.8, we can conclude that litellm==1.83.14 and
    wandb>=0.27.1 are incompatible.

litellm 1.84.10 relaxes that to click>=8.0.0,<9.0 (and clears
GHSA-4xpc-pv4p-pm3w). With it, `uv pip install -e .[dev]` resolves to
click 8.4.2 / typer 0.27.0 / wandb 0.28.1.

Taken from #1507 together with the wandb floor and the click cap removal;
the three only work as a set.

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>
…cy-floors

# Conflicts:
#	core/requirements.txt
#	requirements/pipeline.txt
Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
@nicgupta-nvidia
nicgupta-nvidia enabled auto-merge (squash) July 30, 2026 16:34
Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
Signed-off-by: Nick Gupta <nicgupta@nvidia.com>
@nicgupta-nvidia

Copy link
Copy Markdown
Collaborator Author

August 6 High-severity follow-up (commit 75d0c6a):

  • Floors aiohttp>=3.14.3 for CVE-2026-69244.
  • Replaces Ray runtime-env agent’s private aiohttp 3.14.1 copy with the fixed package from the same architecture. Ray 2.56.1 still bundles 3.14.1, so a Ray-only bump is insufficient.
  • Removes uv’s embedded build SBOM from the runtime image. That SBOM describes uv build dependencies (msgpack 1.1.2, setuptools 70.3.0) even though the image actually installs msgpack 1.2.1 and setuptools 83.0.0, causing two false-positive High findings.
  • Scope is High findings only; no Medium or Low remediation is included.

Focused validation: 35 security tests passed, Ruff lint/format passed (excluding one pre-existing C408 on an untouched line), the Ray private import resolved aiohttp 3.14.3, and the SBOM cleanup was exercised. A rebuilt multi-architecture image and fresh Trivy scan remain the final image-level verification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant