Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/wheel-constraints/nemo-platform-plugin.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Partial dependency constraints for the CI wheel install-smoke-test.
# Pins the DIRECT external deps of the built nemo-platform-plugin wheel to vetted versions for
# reproducibility; deep transitives resolve normally (so they stay py3.14-compatible and
# cannot self-conflict). litellm is capped <1.92 — its 1.92.0 native build has no py3.14 wheel.
# Regenerate with: script/compile-wheel-constraints.sh <dir-with-built-wheels>
#
anthropic==0.116.0
anyio==4.14.2
distro==1.9.0
docker==7.2.0
fastapi==0.139.0
fsspec==2026.6.0
httpx==0.28.1
jsonschema==4.26.0
lark==1.3.1
litellm<1.92 # 1.92.0 native build has no py3.14 wheel
ngcsdk==4.20.1
nvidia-ml-py==13.610.43
openai==2.45.0
prompt-toolkit==3.0.52
psutil==7.2.2
pydantic-settings==2.14.2
pydantic==2.13.4
pyyaml==6.0.3
requests==2.34.2
rich==15.0.0
sniffio==1.3.1
typer==0.25.1
typing-extensions==4.16.0
98 changes: 98 additions & 0 deletions .github/wheel-constraints/nemo-platform-services.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Partial dependency constraints for the CI wheel install-smoke-test.
# Pins the DIRECT external deps of the built nemo-platform[services] wheel to vetted versions for
# reproducibility; deep transitives resolve normally (so they stay py3.14-compatible and
# cannot self-conflict). litellm is capped <1.92 — its 1.92.0 native build has no py3.14 wheel.
# Regenerate with: script/compile-wheel-constraints.sh <dir-with-built-wheels>
#
aioboto3==15.5.0
aiofiles==25.1.0
aiohttp==3.14.1
aiosqlite==0.22.1
alembic==1.18.5
anthropic==0.116.0
anyio==4.14.2
asyncpg==0.31.0
base58==2.1.1
boto3==1.40.61
botocore==1.40.61
clickhouse-connect==0.15.1
cloudpickle==3.1.2
data-designer==0.6.1
datasets==4.3.0
distro==1.9.0
docker==7.2.0
duckdb==1.5.4
fastapi==0.139.0
fastmcp==3.4.4
fsspec==2025.9.0
greenlet==3.5.3
gunicorn==26.0.0
httpx==0.28.1
huggingface-hub==1.23.0
hvac==2.4.0
jinja2==3.1.6
jsonpath-ng==1.8.0
jsonschema==4.26.0
kubernetes==36.0.2
langchain-aws==1.1.0
langchain-community==0.3.31
langchain-core==1.4.9
langchain-nvidia-ai-endpoints==1.4.3
langchain-openai==1.3.5
langchain==1.3.13
lark==1.3.1
litellm<1.92 # 1.92.0 native build has no py3.14 wheel
nemo-anonymizer==0.2.1
nemo-safe-synthesizer==0.1.2
nemoguardrails==0.23.0
ngcsdk==4.20.1
nvidia-ml-py==13.610.43
nvidia-nat-config-optimizer==1.8.0
nvidia-nat-core==1.8.0
nvidia-nat-langchain==1.8.0
openai==2.45.0
opentelemetry-distro==0.64b0
opentelemetry-exporter-otlp-proto-grpc==1.43.0
opentelemetry-exporter-otlp-proto-http==1.43.0
opentelemetry-exporter-otlp==1.43.0
opentelemetry-exporter-prometheus==0.64b0
opentelemetry-instrumentation-fastapi==0.64b0
opentelemetry-instrumentation-httpx==0.64b0
opentelemetry-instrumentation-requests==0.64b0
opentelemetry-instrumentation-sqlalchemy==0.64b0
opentelemetry-instrumentation-system-metrics==0.64b0
opentelemetry-processor-baggage==0.64b0
opentelemetry-proto==1.43.0
opentelemetry-sdk==1.43.0
pandas==2.3.3
prometheus-client==0.25.0
prometheus-fastapi-instrumentator==8.0.2
prompt-toolkit==3.0.52
psutil==7.2.2
psycopg2-binary==2.9.12
pyarrow==22.0.0
pydantic-settings==2.14.2
pydantic==2.13.4
pyjwt==2.13.0
pyleak==0.2.0
python-multipart==0.0.32
pyyaml==6.0.3
ragas==0.4.3
requests==2.34.2
rich==14.3.4
rouge-score==0.1.2
sacrebleu==2.6.0
sniffio==1.3.1
sqlalchemy==2.0.51
sqlmodel==0.0.39
streaming-form-data==2.1.0
structlog==26.1.0
tenacity==9.1.4
typer==0.25.1
types-aioboto3==15.5.0
typing-extensions==4.16.0
urllib3==2.7.0
uvicorn==0.51.0
wasmtime==46.0.1
xdg-base-dirs==6.0.2
yara-python==4.5.1
17 changes: 15 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1087,9 +1087,18 @@ jobs:
exit 1
fi
WHEEL="${wheels[0]}"
uv tool install --force --python "${PYTHON_VERSION}" "${WHEEL}[services]"
# Supply-chain: partial-pin the wheel's direct external deps to a committed constraints
# file (deep transitives resolve normally, so they stay py3.14-compatible and can't
# self-conflict), and cap the litellm transitive whose 1.92.0 native build has no py3.14
# wheel. Regenerate with script/compile-wheel-constraints.sh.
VENV="${RUNNER_TEMP}/wheelcheck/.venv"
uv venv "${VENV}" --python "${PYTHON_VERSION}"
uv pip install --python "${VENV}/bin/python" \
--constraint "${GITHUB_WORKSPACE}/.github/wheel-constraints/nemo-platform-services.txt" \
"${WHEEL}[services]"
cd "${RUNNER_TEMP}/wheelcheck"
unset PYTHONPATH VIRTUAL_ENV
export PATH="${VENV}/bin:${PATH}"
bash "${GITHUB_WORKSPACE}/script/test-nemo-cli.sh"

- name: Install + test nemo-platform-plugin
Expand All @@ -1106,9 +1115,13 @@ jobs:
exit 1
fi
WHEEL="${wheels[0]}"
# Supply-chain: partial-pin direct external deps via a committed constraints file
# (see the nemo-platform CLI step above).
cd "${RUNNER_TEMP}/wheelcheck"
uv venv .venv --python "${PYTHON_VERSION}"
uv pip install --python .venv/bin/python "${WHEEL}"
uv pip install --python .venv/bin/python \
--constraint "${GITHUB_WORKSPACE}/.github/wheel-constraints/nemo-platform-plugin.txt" \
"${WHEEL}"
unset PYTHONPATH VIRTUAL_ENV
# Import the package + a couple of representative submodules
# (cli, commands). These are the surfaces a plugin author would
Expand Down
79 changes: 79 additions & 0 deletions script/compile-wheel-constraints.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Regenerate the partial dependency constraints used by CI's wheel install-smoke-test
# (.github/wheel-constraints/*.txt).
#
# Why partial (constraints, not a full lock): the smoke test installs the freshly
# built nemo-platform / nemo-platform-plugin wheels. Without any pin it resolves
# the whole tree fresh from PyPI (non-reproducible, supply-chain risk). A FULL
# lock does not work here — the vendored-SDK wheel needs newer deps than
# uv.lock, and pinning the entire tree also pins packages that lack py3.14
# wheels, breaking the py3.14 matrix. So we pin only each wheel's DIRECT external
# deps (the versions we've vetted) and let deep transitives resolve normally, so
# they stay py3.14-compatible and cannot self-conflict.
#
# litellm is capped <1.92 (a transitive): litellm 1.92.0 ships a native/PyO3
# build with no py3.14 wheel. Drop the cap once litellm ships a 3.14 wheel.
#
# Usage:
# script/compile-wheel-constraints.sh <dir-with-both-wheels>
#
# Wheels come from `uv build --package nemo-platform[-plugin]` (nemo-platform
# needs the Studio/node toolchain) or a CI "<pkg>-wheel-py3.11" artifact
# (`gh run download <run-id> -n nemo-platform-wheel-py3.11 -D <dir>`).
set -euo pipefail

WHEEL_DIR="${1:?usage: script/compile-wheel-constraints.sh <dir-with-built-wheels>}"
OUT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/.github/wheel-constraints"
LITELLM_CAP='litellm<1.92 # 1.92.0 native build has no py3.14 wheel'

# Pin each of a wheel's direct external deps to the version that resolves for it
# (with litellm capped), then append the litellm cap.
emit_constraints() {
local wheel="$1" spec="$2" label="$3" out="$4" venv meta
venv="$(mktemp -d)"
meta="$(mktemp -d)"
uv venv "${venv}" --python 3.11 --quiet
# Resolve+install once with the cap so we snapshot consistent, py3.14-safe versions.
printf '%s\n' "${LITELLM_CAP%% *}" >"${meta}/cap.txt"
uv pip install --python "${venv}/bin/python" --constraint "${meta}/cap.txt" "${spec}" >/dev/null
# Direct external deps = the wheel's own Requires-Dist, minus self-referential extras.
python3 - "$wheel" >"${meta}/names.txt" <<'PY'
import sys, zipfile, re
names=set()
with zipfile.ZipFile(sys.argv[1]) as z:
md=next(n for n in z.namelist() if n.endswith(".dist-info/METADATA"))
for line in z.read(md).decode().splitlines():
if line.startswith("Requires-Dist:"):
dep=line.split(":",1)[1].strip()
name=re.split(r"[<>=!~;\[ ]", dep, 1)[0].strip()
if name and not name.startswith("nemo-platform"):
names.add(name)
print("\n".join(sorted(names)))
PY
{
printf '# Partial dependency constraints for the CI wheel install-smoke-test.\n'
printf '# Pins the DIRECT external deps of the built %s wheel to vetted versions for\n' "${label}"
printf '# reproducibility; deep transitives resolve normally (so they stay py3.14-compatible and\n'
printf '# cannot self-conflict). litellm is capped <1.92 — its 1.92.0 native build has no py3.14 wheel.\n'
printf '# Regenerate with: script/compile-wheel-constraints.sh <dir-with-built-wheels>\n#\n'
while read -r name; do
[[ -n "${name}" ]] || continue
ver="$("${venv}/bin/python" -c "import importlib.metadata as m; print(m.version('${name}'))" 2>/dev/null || true)
[[ -n "${ver}" ]] && printf '%s==%s\n' "${name}" "${ver}"
done <"${meta}/names.txt" | sort
printf '%s\n' "${LITELLM_CAP}"
} >"${out}"
rm -rf "${venv}" "${meta}"
echo "wrote ${out} ($(grep -cE '^[a-z0-9].*(==|<[0-9])' "${out}") pins)"
}

np_wheel="$(find "${WHEEL_DIR}" -name 'nemo_platform-*.whl' | head -1)"
pl_wheel="$(find "${WHEEL_DIR}" -name 'nemo_platform_plugin-*.whl' | head -1)"
[[ -n "${np_wheel}" ]] || { echo "no nemo_platform-*.whl in ${WHEEL_DIR}" >&2; exit 1; }
[[ -n "${pl_wheel}" ]] || { echo "no nemo_platform_plugin-*.whl in ${WHEEL_DIR}" >&2; exit 1; }

emit_constraints "${np_wheel}" "${np_wheel}[services]" "nemo-platform[services]" "${OUT_DIR}/nemo-platform-services.txt"
emit_constraints "${pl_wheel}" "${pl_wheel}" "nemo-platform-plugin" "${OUT_DIR}/nemo-platform-plugin.txt"