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
76 changes: 76 additions & 0 deletions .github/workflows/docker-source-smoke.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Docker source smoke

on:
workflow_dispatch:
inputs:
image_tag:
description: Optional image tag. Defaults to the commit SHA.
required: false
type: string
default: ""

permissions:
contents: read

env:
TOOLCHAIN: system
NMP_COLLECT_SOURCES: "1"

jobs:
build-source-images:
name: Build Docker images with sources
runs-on: ubuntu-latest
timeout-minutes: 180
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Free disk space
uses: ./.github/actions/free-disk-space
with:
disable_swap: "true"
remove_go: "true"
remove_haskell: "true"
remove_java: "true"
remove_node: "true"
remove_pypy: "true"
remove_ruby: "true"
remove_swift: "true"
prune_docker: "true"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
with:
name: nmp-builder
driver: docker-container
cleanup: true

- name: Configure bake variables
shell: bash
env:
INPUT_IMAGE_TAG: ${{ inputs.image_tag }}
SOURCE_SHA: ${{ github.sha }}
run: |
set -euo pipefail

image_registry="ghcr.io/${GITHUB_REPOSITORY,,}"
source_sha="${SOURCE_SHA:-$GITHUB_SHA}"
bake_tag="${INPUT_IMAGE_TAG:-$source_sha}"

{
printf 'IMAGE_REGISTRY=%s\n' "$image_registry"
printf 'BASE_REGISTRY=%s\n' "$image_registry"
printf 'CACHE_REGISTRY=%s\n' "$image_registry"
printf 'BAKE_TAG=%s\n' "$bake_tag"
printf 'CI_COMMIT_SHA=%s\n' "$source_sha"
} >> "$GITHUB_ENV"

- name: Print Docker bake graph
shell: bash
run: make docker-print TARGET=docker

- name: Build Docker images with sources
shell: bash
run: make docker-build TARGET=docker
4 changes: 4 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,10 @@ jobs:
cadence: process.env.RELEASE_TYPE,
version: process.env.RELEASE_LABEL,
containers: JSON.parse(process.env.CONTAINER_IDS),
collect_sources: true,
bake_env: {
NMP_COLLECT_SOURCES: "1",
},
},
});

Expand Down
2 changes: 2 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

Licensed under the Apache License, Version 2.0.

NOTICE AND DISCLAIMER: This software automatically retrieves, accesses or interacts with external materials. Those retrieved materials are not distributed with this software and are governed solely by separate terms, conditions and licenses. You are solely responsible for finding, reviewing and complying with all applicable terms, conditions, and licenses, and for verifying the security, integrity and suitability of any retrieved materials for your specific use case. This software is provided "AS IS", without warranty of any kind. The author makes no representations or warranties regarding any retrieved materials, and assumes no liability for any losses, damages, liabilities or legal consequences from your use or inability to use this software or any retrieved materials. Use this software and the retrieved materials at your own risk.

================================================================================
Third-Party / Vendored and Distributed Components
================================================================================
Expand Down
49 changes: 41 additions & 8 deletions docker-bake.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ variable "USE_PREBUILT_BASES" {
default = ""
}

variable "NMP_COLLECT_SOURCES" {
default = "0"
}

variable "NMP_PYTHON_IMAGE" {
default = "python:3.13.14-slim-trixie"
}
Expand Down Expand Up @@ -387,6 +391,9 @@ target "nmp-customizer-tasks" {
causal-conv1d-wheel-src = causal_conv1d_wheel_context()
mamba-ssm-wheel-src = mamba_ssm_wheel_context()
}
args = {
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-customizer-tasks")
cache-from = maybe_registry_cache_from("nmp-customizer-tasks")
tags = sha_and_maybe_latest_tags("nmp-customizer-tasks")
Expand All @@ -404,7 +411,8 @@ target "nmp-customizer-tasks-smoke-test" {
mamba-ssm-wheel-src = mamba_ssm_wheel_context()
}
args = {
SMOKE_MARKER = "smoke_nmp_customizer_tasks"
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
SMOKE_MARKER = "smoke_nmp_customizer_tasks"
}
cache-from = maybe_registry_cache_from("nmp-customizer-tasks")
output = ["type=cacheonly"]
Expand All @@ -428,8 +436,9 @@ target "nmp-rl-base-builder" {
context = "."
dockerfile = "docker/rl/Dockerfile.nmp-rl-base"
args = {
NEMO_RL_REPO = NEMO_RL_REPO
NEMO_RL_REF = NEMO_RL_REF
NEMO_RL_REPO = NEMO_RL_REPO
NEMO_RL_REF = NEMO_RL_REF
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-rl-base")
cache-from = maybe_registry_cache_from("nmp-rl-base")
Expand All @@ -448,6 +457,9 @@ target "nmp-rl-training" {
platform-workspace = "target:rl-platform-workspace"
nmp-rl-base = rl_base_context()
}
args = {
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-rl-training")
cache-from = maybe_registry_cache_from("nmp-rl-training")
tags = sha_and_maybe_latest_tags("nmp-rl-training")
Expand All @@ -465,7 +477,8 @@ target "nmp-rl-training-smoke-test" {
nmp-rl-base = rl_base_context()
}
args = {
SMOKE_MARKER = "smoke_nmp_rl_training"
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
SMOKE_MARKER = "smoke_nmp_rl_training"
}
cache-from = maybe_registry_cache_from("nmp-rl-training")
output = ["type=cacheonly"]
Expand Down Expand Up @@ -615,8 +628,9 @@ target "nmp-api-docker" {
}
args = {
NMP_PLATFORM_VERSION = notequal(BAKE_TAG, "") ? BAKE_TAG : "dev"
NMP_CODE_REVISION = notequal(CI_COMMIT_SHA, "") ? CI_COMMIT_SHA : "dev"
NMP_CODE_REVISION = notequal(CI_COMMIT_SHA, "") ? CI_COMMIT_SHA : "dev"
NMP_API_RUNTIME_BASE = NMP_API_RUNTIME_BASE
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-api")
cache-from = maybe_registry_cache_from("nmp-api")
Expand All @@ -640,6 +654,7 @@ target "nmp-core-docker" {
}
args = {
NMP_CORE_RUNTIME_BASE = NMP_CORE_RUNTIME_BASE
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-core")
cache-from = maybe_registry_cache_from("nmp-core")
Expand All @@ -657,6 +672,9 @@ target "nmp-cpu-tasks-docker" {
nmp-python-base = "target:nmp-python-base"
nmp-workspace = "target:nmp-workspace"
}
args = {
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-cpu-tasks")
cache-from = maybe_registry_cache_from("nmp-cpu-tasks")
tags = sha_and_maybe_latest_tags("nmp-cpu-tasks")
Expand Down Expand Up @@ -715,7 +733,8 @@ target "safe-synthesizer-tasks-docker" {
context = "."
dockerfile = "docker/Dockerfile.safe-synthesizer-tasks"
args = {
CONTAINER_VARIANT = "${SAFE_SYNTHESIZER_CONTAINER_VARIANT}"
CONTAINER_VARIANT = "${SAFE_SYNTHESIZER_CONTAINER_VARIANT}"
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("safe-synthesizer-tasks")
cache-from = maybe_registry_cache_from("safe-synthesizer-tasks")
Expand All @@ -732,7 +751,8 @@ target "safe-synthesizer-tasks-smoke-test" {
context = "."
dockerfile = "docker/Dockerfile.safe-synthesizer-tasks"
args = {
CONTAINER_VARIANT = "${SAFE_SYNTHESIZER_CONTAINER_VARIANT}"
CONTAINER_VARIANT = "${SAFE_SYNTHESIZER_CONTAINER_VARIANT}"
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-from = maybe_registry_cache_from("safe-synthesizer-tasks")
output = ["type=cacheonly"]
Expand Down Expand Up @@ -891,6 +911,9 @@ target "nmp-automodel-base-builder" {
causal-conv1d-wheel-image = causal_conv1d_wheel_context()
mamba-ssm-wheel-image = mamba_ssm_wheel_context()
}
args = {
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
platforms = get_platforms()
}

Expand All @@ -902,6 +925,9 @@ target "nmp-automodel-training-docker" {
platform-workspace = "target:automodel-platform-workspace"
nmp-automodel-base = automodel_base_context()
}
args = {
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-automodel-training")
cache-from = maybe_registry_cache_from("nmp-automodel-training")
tags = sha_and_maybe_latest_tags("nmp-automodel-training")
Expand All @@ -918,7 +944,8 @@ target "nmp-automodel-training-smoke-test" {
nmp-automodel-base = automodel_base_context()
}
args = {
SMOKE_MARKER = "smoke_nmp_automodel_training"
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
SMOKE_MARKER = "smoke_nmp_automodel_training"
}
cache-from = maybe_registry_cache_from("nmp-automodel-training")
output = ["type=cacheonly"]
Expand All @@ -942,6 +969,9 @@ target "nmp-unsloth-training" {
causal-conv1d-wheel-image = causal_conv1d_wheel_context()
mamba-ssm-wheel-image = mamba_ssm_wheel_context()
}
args = {
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("nmp-unsloth-training")
cache-from = maybe_registry_cache_from("nmp-unsloth-training")
tags = sha_and_maybe_latest_tags("nmp-unsloth-training")
Expand Down Expand Up @@ -999,6 +1029,9 @@ target "auditor-tasks-docker" {
root-busybox = "target:root-busybox"
}
dockerfile = "docker/Dockerfile.auditor-tasks"
args = {
NMP_COLLECT_SOURCES = NMP_COLLECT_SOURCES
}
cache-to = maybe_registry_cache_to("auditor-tasks")
cache-from = maybe_registry_cache_from("auditor-tasks")
tags = sha_and_maybe_latest_tags("auditor-tasks")
Expand Down
29 changes: 29 additions & 0 deletions docker/Dockerfile.auditor-tasks
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-reco
&& rm -rf /var/lib/apt/lists/*

COPY --from=ghcr.io/astral-sh/uv:0.9.14 /uv /bin/uv
COPY docker/scripts/collect-python-sdists.py /usr/local/bin/

ENV UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy
Expand Down Expand Up @@ -88,11 +89,31 @@ RUN --mount=type=cache,target=/root/.cache/uv \
"cryptography>=50.0.0,<51" \
"nltk>=3.10.0"

ARG NMP_COLLECT_SOURCES=0
ENV NMP_COLLECT_SOURCES=${NMP_COLLECT_SOURCES}
RUN --mount=type=cache,target=/root/.cache/uv \
uv run --no-project --python /app/.venv/bin/python \
/usr/local/bin/collect-python-sdists.py \
--python /app/.venv/bin/python \
--output /source-distributions/auditor-tasks \
--lock-file /app/uv.lock \
--label app-venv && \
uv run --no-project --python /app/.garak_venv/bin/python \
/usr/local/bin/collect-python-sdists.py \
--python /app/.garak_venv/bin/python \
--output /source-distributions/auditor-tasks \
--lock-file /app/uv.lock \
--label garak-venv

FROM ${AUDITOR_PYTHON_IMAGE} AS base
ARG USERNAME=nvs
ARG USER_UID=1000
ARG USER_GID=1000
WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:0.9.14 /uv /bin/uv
COPY docker/scripts/collect-apt-sources.sh \
docker/scripts/collect-cpython-source.py \
/usr/local/bin/
RUN apt-get update && apt-get upgrade -y && \
list_installed_perl_cve_packages() { \
dpkg-query -W -f='${binary:Package} ${db:Status-Abbrev}\n' \
Expand Down Expand Up @@ -150,8 +171,16 @@ ENV PATH="/app/.venv/bin:$PATH"

# Copy installed packages and application
COPY --chown=nvs:nvs --from=py-builder /app /app
COPY --chown=nvs:nvs --from=py-builder /source-distributions/auditor-tasks/ /usr/share/nemo-platform/source-distributions/auditor-tasks/
ARG CACHE_HOME
COPY --chown=nvs:nvs --from=py-builder ${CACHE_HOME} ${CACHE_HOME}
ARG NMP_COLLECT_SOURCES=0
ENV NMP_COLLECT_SOURCES=${NMP_COLLECT_SOURCES}
RUN bash /usr/local/bin/collect-apt-sources.sh /usr/share/nemo-platform/source-distributions/auditor-tasks/apt --installed && \
uv run --no-project --python /usr/local/bin/python \
/usr/local/bin/collect-cpython-source.py \
--python /usr/local/bin/python \
--output /usr/share/nemo-platform/source-distributions/auditor-tasks

ENV USERNAME=nvs \
HOME=/home/nvs
Expand Down
20 changes: 20 additions & 0 deletions docker/Dockerfile.nmp-api
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,25 @@ RUN if find /tmp/fastembed_cache/models--qdrant--all-MiniLM-L6-v2-onnx/snapshots
uv run --no-sync python -c 'import os, tempfile; from huggingface_hub import snapshot_download; snapshot_download(repo_id="qdrant/all-MiniLM-L6-v2-onnx", cache_dir=os.path.join(tempfile.gettempdir(), "fastembed_cache"))'; \
fi

ARG NMP_COLLECT_SOURCES=0
ENV NMP_COLLECT_SOURCES=${NMP_COLLECT_SOURCES}
RUN --mount=type=cache,target=/root/.cache/uv \
uv run --no-project --python /app/.venv/bin/python \
/usr/local/bin/collect-workspace-sdists.py \
--python /app/.venv/bin/python \
--output /app/.source-distributions/nmp-api && \
uv run --no-project --python /app/.venv/bin/python \
/usr/local/bin/collect-python-sdists.py \
--python /app/.venv/bin/python \
--output /app/.source-distributions/nmp-api \
--lock-file /app/uv.lock \
--label app-venv && \
bash /usr/local/bin/collect-apt-sources.sh /app/.source-distributions/nmp-api/apt --installed && \
uv run --no-project --python /app/.venv/bin/python \
/usr/local/bin/collect-cpython-source.py \
--python /app/.venv/bin/python \
--output /app/.source-distributions/nmp-api

FROM ${NMP_API_RUNTIME_BASE} AS runtime
WORKDIR /app

Expand Down Expand Up @@ -83,6 +102,7 @@ ENV USERNAME=nvs \
# DuckDB extension cache (aws, httpfs) for S3 log storage
COPY --chown=1000:1000 --from=builder /root/.duckdb /home/nvs/.duckdb
COPY --chown=1000:1000 --from=builder /app/.venv /app/.venv
COPY --chown=1000:1000 --from=builder /app/.source-distributions/nmp-api/ /usr/share/nemo-platform/source-distributions/nmp-api/
ENV VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH" \
PYTHONPATH="/app/.venv/lib/python${PY_VERSION}/site-packages"
Expand Down
19 changes: 19 additions & 0 deletions docker/Dockerfile.nmp-core
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ RUN /app/.venv/bin/python -c 'from nmp.core.auth.app.embedded_pdp.policy_wasm im
# Download the extension artifacts directly over HTTPS and install from local files
# because DuckDB's default remote INSTALL path can be blocked or flaky in some build environments.
RUN sh /app/script/install_duckdb_extensions.sh
ARG NMP_COLLECT_SOURCES=0
ENV NMP_COLLECT_SOURCES=${NMP_COLLECT_SOURCES}
RUN --mount=type=cache,target=/root/.cache/uv \
uv run --no-project --python /app/.venv/bin/python \
/usr/local/bin/collect-workspace-sdists.py \
--python /app/.venv/bin/python \
--output /app/.source-distributions/nmp-core && \
uv run --no-project --python /app/.venv/bin/python \
/usr/local/bin/collect-python-sdists.py \
--python /app/.venv/bin/python \
--output /app/.source-distributions/nmp-core \
--lock-file /app/uv.lock \
--label app-venv && \
bash /usr/local/bin/collect-apt-sources.sh /app/.source-distributions/nmp-core/apt --installed && \
uv run --no-project --python /app/.venv/bin/python \
/usr/local/bin/collect-cpython-source.py \
--python /app/.venv/bin/python \
--output /app/.source-distributions/nmp-core

FROM ${NMP_CORE_RUNTIME_BASE} AS runtime
WORKDIR /app
Expand Down Expand Up @@ -48,6 +66,7 @@ ENV USERNAME=nvs \
COPY --chown=1000:1000 --from=builder /root/.duckdb /root/.duckdb
COPY --chown=1000:1000 --from=builder /root/.duckdb /home/nvs/.duckdb
COPY --chown=1000:1000 --from=builder /app/.venv /app/.venv
COPY --chown=1000:1000 --from=builder /app/.source-distributions/nmp-core/ /usr/share/nemo-platform/source-distributions/nmp-core/
ENV VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH" \
PYTHONPATH="/app/.venv/lib/python${PY_VERSION}/site-packages"
Expand Down
Loading
Loading