Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
OpenDAS
dynamo
Commits
01a4b6d6
Unverified
Commit
01a4b6d6
authored
Apr 15, 2026
by
Harrison Saturley-Hall
Committed by
GitHub
Apr 15, 2026
Browse files
chore: bump dynamo version numbers (#8191)
parent
6d4d0a61
Changes
23
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
970 additions
and
118 deletions
+970
-118
.github/workflows/release.yml
.github/workflows/release.yml
+14
-48
Cargo.lock
Cargo.lock
+17
-17
Cargo.toml
Cargo.toml
+16
-16
container/compliance/generate_go_deps.py
container/compliance/generate_go_deps.py
+589
-0
container/compliance/generate_rust_deps.py
container/compliance/generate_rust_deps.py
+297
-0
deploy/helm/charts/platform/Chart.yaml
deploy/helm/charts/platform/Chart.yaml
+2
-2
deploy/helm/charts/platform/README.md
deploy/helm/charts/platform/README.md
+2
-2
deploy/helm/charts/platform/components/operator/Chart.yaml
deploy/helm/charts/platform/components/operator/Chart.yaml
+2
-2
deploy/helm/charts/snapshot/Chart.yaml
deploy/helm/charts/snapshot/Chart.yaml
+2
-2
lib/bindings/kvbm/Cargo.lock
lib/bindings/kvbm/Cargo.lock
+10
-10
lib/bindings/kvbm/Cargo.toml
lib/bindings/kvbm/Cargo.toml
+1
-1
lib/bindings/kvbm/pyproject.toml
lib/bindings/kvbm/pyproject.toml
+1
-1
lib/bindings/python/Cargo.lock
lib/bindings/python/Cargo.lock
+10
-10
lib/bindings/python/Cargo.toml
lib/bindings/python/Cargo.toml
+1
-1
lib/bindings/python/pyproject.toml
lib/bindings/python/pyproject.toml
+1
-1
lib/kvbm-common/Cargo.toml
lib/kvbm-common/Cargo.toml
+1
-1
lib/kvbm-engine/Cargo.toml
lib/kvbm-engine/Cargo.toml
+1
-1
lib/kvbm-kernels/Cargo.toml
lib/kvbm-kernels/Cargo.toml
+1
-1
lib/kvbm-logical/Cargo.toml
lib/kvbm-logical/Cargo.toml
+1
-1
lib/kvbm-physical/Cargo.toml
lib/kvbm-physical/Cargo.toml
+1
-1
No files found.
.github/workflows/release.yml
View file @
01a4b6d6
...
...
@@ -181,8 +181,6 @@ jobs:
ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
ECR_HOSTNAME="${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com"
ARCHITECTURES=("amd64" "arm64")
echo "========================================"
echo "Copying images from ECR to NGC (registry-to-registry)"
echo "Source commit SHA: ${COMMIT_SHA}"
...
...
@@ -190,14 +188,11 @@ jobs:
echo "========================================"
copy_image() {
local SRC="$1" DST="$2" LABEL="$3" PLATFORM="${4:-}"
local PLATFORM_ARG=""
if [ -n "${PLATFORM}" ]; then
PLATFORM_ARG="--platform ${PLATFORM}"
fi
local SRC="$1" DST="$2" LABEL="$3"
echo "----------------------------------------"
echo "Copying: ${LABEL}"
if crane copy ${PLATFORM_ARG} "${SRC}" "${DST}"; then
# crane copy preserves multi-arch manifest lists by default (no --platform needed)
if crane copy "${SRC}" "${DST}"; then
echo " Copied: ${LABEL}"
SUCCESSFUL_COPIES+=("${LABEL}")
return 0
...
...
@@ -208,36 +203,15 @@ jobs:
fi
}
create_manifest() {
local MANIFEST="$1" AMD64_IMG="$2" ARM64_IMG="$3" LABEL="$4"
echo "Creating manifest: ${MANIFEST}"
docker manifest create "${MANIFEST}" "${AMD64_IMG}" "${ARM64_IMG}" || true
if docker manifest push "${MANIFEST}"; then
echo " Created multi-arch: ${LABEL}"
SUCCESSFUL_COPIES+=("${LABEL} (multi-arch)")
else
echo " Failed to create multi-arch: ${LABEL}"
FAILED_COPIES+=("${LABEL} (multi-arch)")
fi
}
# ---- CUDA 12 runtime images (vllm and sglang) ----
echo ""
echo "=== CUDA 12 Runtime Images (vllm, sglang) ==="
CUDA12_FRAMEWORKS=("vllm" "sglang")
for FRAMEWORK in "${CUDA12_FRAMEWORKS[@]}"; do
NGC_NAME="${FRAMEWORK}-runtime"
for ARCH in "${ARCHITECTURES[@]}"; do
SOURCE="${ECR_HOSTNAME}/${REGISTRY_IMAGE}:${COMMIT_SHA}-${FRAMEWORK}-runtime-cuda12"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-${ARCH}"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}-${ARCH}" "linux/${ARCH}"
done
create_manifest \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-amd64" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-arm64" \
"${NGC_NAME}:${NGC_VERSION_TAG}"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}"
done
# ---- CUDA 13 runtime images (vllm, sglang, trtllm) ----
...
...
@@ -251,17 +225,9 @@ jobs:
NGC_NAME="${FRAMEWORK}-runtime"
fi
for ARCH in "${ARCHITECTURES[@]}"; do
SOURCE="${ECR_HOSTNAME}/${REGISTRY_IMAGE}:${COMMIT_SHA}-${FRAMEWORK}-runtime-cuda13"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-${ARCH}"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-${ARCH}" "linux/${ARCH}"
done
create_manifest \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-amd64" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-arm64" \
"${NGC_NAME}:${NGC_VERSION_TAG}-cuda13"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}-cuda13"
done
# ---- EFA runtime images (amd64 only, no multi-arch manifest needed) ----
...
...
@@ -392,13 +358,13 @@ jobs:
echo "### Expected Images" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Runtime images (CUDA 12 - default):" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}\`
(multi-arch)
" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}\`
(multi-arch)
" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Runtime images (CUDA 13):" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}-cuda13\`
(multi-arch)
" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}-cuda13\`
(multi-arch)
" >> $GITHUB_STEP_SUMMARY
echo "- \`tensorrtllm-runtime:${NGC_VERSION_TAG}-cuda13\`
(multi-arch)
" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}-cuda13\`" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}-cuda13\`" >> $GITHUB_STEP_SUMMARY
echo "- \`tensorrtllm-runtime:${NGC_VERSION_TAG}-cuda13\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "EFA runtime images (amd64 only):" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}-efa\`" >> $GITHUB_STEP_SUMMARY
...
...
Cargo.lock
View file @
01a4b6d6
...
...
@@ -2310,7 +2310,7 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "dynamo-bench"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-trait",
...
...
@@ -2343,14 +2343,14 @@ dependencies = [
[[package]]
name = "dynamo-config"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
]
[[package]]
name = "dynamo-kv-router"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-trait",
...
...
@@ -2383,7 +2383,7 @@ dependencies = [
[[package]]
name = "dynamo-llm"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"aho-corasick",
"aligned-vec",
...
...
@@ -2483,7 +2483,7 @@ dependencies = [
[[package]]
name = "dynamo-memory"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"cudarc",
...
...
@@ -2501,7 +2501,7 @@ dependencies = [
[[package]]
name = "dynamo-mocker"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"dashmap",
...
...
@@ -2530,7 +2530,7 @@ dependencies = [
[[package]]
name = "dynamo-parsers"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"dynamo-protocols",
...
...
@@ -2548,7 +2548,7 @@ dependencies = [
[[package]]
name = "dynamo-protocols"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"async-openai",
"derive_builder",
...
...
@@ -2565,7 +2565,7 @@ dependencies = [
[[package]]
name = "dynamo-runtime"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"arc-swap",
...
...
@@ -2640,7 +2640,7 @@ dependencies = [
[[package]]
name = "dynamo-tokens"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"bs58",
"bytemuck",
...
...
@@ -4455,7 +4455,7 @@ dependencies = [
[[package]]
name = "kvbm-common"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"dynamo-tokens",
"serde",
...
...
@@ -4463,7 +4463,7 @@ dependencies = [
[[package]]
name = "kvbm-config"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"dynamo-memory",
...
...
@@ -4483,7 +4483,7 @@ dependencies = [
[[package]]
name = "kvbm-engine"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-nats",
...
...
@@ -4523,7 +4523,7 @@ dependencies = [
[[package]]
name = "kvbm-kernels"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"clap 4.6.0",
"cudarc",
...
...
@@ -4534,7 +4534,7 @@ dependencies = [
[[package]]
name = "kvbm-logical"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-stream",
...
...
@@ -4564,7 +4564,7 @@ dependencies = [
[[package]]
name = "kvbm-physical"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"aligned-vec",
"anyhow",
...
...
@@ -4620,7 +4620,7 @@ checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
[[package]]
name = "libdynamo_llm"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-once-cell",
...
...
Cargo.toml
View file @
01a4b6d6
...
...
@@ -25,7 +25,7 @@ members = [
resolver
=
"3"
[workspace.package]
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition
=
"2024"
description
=
"Dynamo Inference Framework"
authors
=
[
"NVIDIA Inc. <sw-dl-dynamo@nvidia.com>"
]
...
...
@@ -36,25 +36,25 @@ keywords = ["llm", "genai", "inference", "nvidia", "distributed"]
[workspace.dependencies]
# Local crates
dynamo-runtime
=
{
path
=
"lib/runtime"
,
version
=
"1.
0
.0"
}
dynamo-llm
=
{
path
=
"lib/llm"
,
version
=
"1.
0
.0"
}
dynamo-config
=
{
path
=
"lib/config"
,
version
=
"1.
0
.0"
}
dynamo-tokens
=
{
path
=
"lib/tokens"
,
version
=
"1.
0
.0"
}
dynamo-memory
=
{
path
=
"lib/memory"
,
version
=
"1.
0
.0"
}
dynamo-mocker
=
{
path
=
"lib/mocker"
,
version
=
"1.
0
.0"
}
dynamo-kv-router
=
{
path
=
"lib/kv-router"
,
version
=
"1.
0
.0"
,
features
=
[
"metrics"
,
"runtime-protocols"
]
}
dynamo-protocols
=
{
path
=
"lib/protocols"
,
version
=
"1.
0
.0"
}
dynamo-parsers
=
{
path
=
"lib/parsers"
,
version
=
"1.
0
.0"
}
dynamo-runtime
=
{
path
=
"lib/runtime"
,
version
=
"1.
1
.0"
}
dynamo-llm
=
{
path
=
"lib/llm"
,
version
=
"1.
1
.0"
}
dynamo-config
=
{
path
=
"lib/config"
,
version
=
"1.
1
.0"
}
dynamo-tokens
=
{
path
=
"lib/tokens"
,
version
=
"1.
1
.0"
}
dynamo-memory
=
{
path
=
"lib/memory"
,
version
=
"1.
1
.0"
}
dynamo-mocker
=
{
path
=
"lib/mocker"
,
version
=
"1.
1
.0"
}
dynamo-kv-router
=
{
path
=
"lib/kv-router"
,
version
=
"1.
1
.0"
,
features
=
[
"metrics"
,
"runtime-protocols"
]
}
dynamo-protocols
=
{
path
=
"lib/protocols"
,
version
=
"1.
1
.0"
}
dynamo-parsers
=
{
path
=
"lib/parsers"
,
version
=
"1.
1
.0"
}
fastokens
=
{
version
=
"0.1.0"
}
# kvbm
kvbm-common
=
{
path
=
"lib/kvbm-common"
,
version
=
"1.
0
.0"
}
kvbm-config
=
{
path
=
"lib/kvbm-config"
,
version
=
"1.
0
.0"
}
kvbm-engine
=
{
path
=
"lib/kvbm-engine"
,
version
=
"1.
0
.0"
}
kvbm-kernels
=
{
path
=
"lib/kvbm-kernels"
,
version
=
"1.
0
.0"
}
kvbm-logical
=
{
path
=
"lib/kvbm-logical"
,
version
=
"1.
0
.0"
}
kvbm-physical
=
{
path
=
"lib/kvbm-physical"
,
version
=
"1.
0
.0"
}
kvbm-common
=
{
path
=
"lib/kvbm-common"
,
version
=
"1.
1
.0"
}
kvbm-config
=
{
path
=
"lib/kvbm-config"
,
version
=
"1.
1
.0"
}
kvbm-engine
=
{
path
=
"lib/kvbm-engine"
,
version
=
"1.
1
.0"
}
kvbm-kernels
=
{
path
=
"lib/kvbm-kernels"
,
version
=
"1.
1
.0"
}
kvbm-logical
=
{
path
=
"lib/kvbm-logical"
,
version
=
"1.
1
.0"
}
kvbm-physical
=
{
path
=
"lib/kvbm-physical"
,
version
=
"1.
1
.0"
}
# velo
velo
=
{
version
=
"0.1.0"
}
...
...
container/compliance/generate_go_deps.py
0 → 100755
View file @
01a4b6d6
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Generate a dependency CSV (and optional attribution markdown) for Go modules.
Extracts Go module dependencies from one or more Go module directories using
``go list -deps`` for names/versions and ``go-licenses report`` for SPDX
license identifiers. Falls back gracefully when ``go-licenses`` is not
installed. Optionally generates an attribution markdown file with full
license texts.
Usage:
python generate_go_deps.py -o go_deps.csv
python generate_go_deps.py --attributions ATTRIBUTIONS-Go.md
python generate_go_deps.py --module-dirs deploy/operator -o operator_deps.csv -v
"""
import
argparse
import
csv
import
io
import
json
import
logging
import
re
import
subprocess
import
sys
from
pathlib
import
Path
_SCRIPT_DIR
=
Path
(
__file__
).
resolve
().
parent
_REPO_ROOT
=
_SCRIPT_DIR
.
parent
.
parent
log
=
logging
.
getLogger
(
__name__
)
FIELDNAMES
=
[
"dependency_type"
,
"package_name"
,
"version"
,
"spdx_license"
,
"repo_url"
]
DEFAULT_MODULE_DIRS
=
[
"deploy/operator"
,
"deploy/snapshot"
,
]
DEFAULT_IGNORE_PREFIXES
=
"github.com/ai-dynamo/dynamo"
# Transitive test/indirect deps that go-licenses requires to be fetched
# before it can scan certain modules. Keyed by module directory (relative to
# repo root). See deploy/snapshot/deps.md for background.
_PREFETCH_DEPS
:
dict
[
str
,
list
[
str
]]
=
{
"deploy/snapshot"
:
[
"github.com/opencontainers/runtime-spec/schema@v1.2.0"
,
"github.com/evanphx/json-patch"
,
"github.com/jessevdk/go-flags"
,
],
}
_LICENSE_NAMES
=
[
"LICENSE"
,
"LICENSE.md"
,
"LICENSE.txt"
,
"LICENSE-MIT"
,
"LICENSE-APACHE"
,
"LICENCE"
,
"LICENCE.md"
,
"LICENCE.txt"
,
"COPYING"
,
"COPYING.md"
,
]
_ATTRIBUTION_PREAMBLE
=
"""
\
<!--
SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->
# Third-Party Software Attributions
This project uses the following third-party libraries. Each library is
\
open-source and licensed under the terms indicated below.
This file is automatically generated. Please do not edit it directly.
## Dependencies
"""
# Well-known Go module path -> repository URL mappings
_WELLKNOWN_REPOS
:
dict
[
str
,
str
]
=
{
"google.golang.org/grpc"
:
"https://github.com/grpc/grpc-go"
,
"google.golang.org/protobuf"
:
"https://github.com/protocolbuffers/protobuf-go"
,
"google.golang.org/genproto"
:
"https://github.com/googleapis/go-genproto"
,
"google.golang.org/api"
:
"https://github.com/googleapis/google-api-go-client"
,
"google.golang.org/appengine"
:
"https://github.com/golang/appengine"
,
"cloud.google.com/go"
:
"https://github.com/googleapis/google-cloud-go"
,
}
# Prefix-based mappings (checked in order)
_PREFIX_REPOS
:
list
[
tuple
[
str
,
str
]]
=
[
(
"golang.org/x/"
,
"https://github.com/golang/"
),
(
"k8s.io/"
,
"https://github.com/kubernetes/"
),
(
"sigs.k8s.io/"
,
"https://github.com/kubernetes-sigs/"
),
(
"go.uber.org/"
,
"https://github.com/uber-go/"
),
(
"go.opentelemetry.io/"
,
"https://github.com/open-telemetry/"
),
(
"go.etcd.io/"
,
"https://github.com/etcd-io/"
),
]
def
_parse_json_stream
(
text
:
str
)
->
list
[
dict
]:
"""Parse a stream of concatenated JSON objects (as emitted by ``go list -json``)."""
decoder
=
json
.
JSONDecoder
()
results
=
[]
idx
=
0
length
=
len
(
text
)
while
idx
<
length
:
# Skip whitespace
while
idx
<
length
and
text
[
idx
]
in
"
\t\n\r
"
:
idx
+=
1
if
idx
>=
length
:
break
obj
,
end
=
decoder
.
raw_decode
(
text
,
idx
)
results
.
append
(
obj
)
idx
=
end
return
results
def
prefetch_deps
(
module_dir
:
Path
,
go_cmd
:
str
,
deps
:
list
[
str
])
->
None
:
"""Run ``go get`` to fetch transitive deps that go-licenses needs present."""
cmd
=
[
go_cmd
,
"get"
]
+
deps
log
.
debug
(
"Pre-fetching in %s: %s"
,
module_dir
,
" "
.
join
(
cmd
))
result
=
subprocess
.
run
(
cmd
,
capture_output
=
True
,
text
=
True
,
timeout
=
300
,
cwd
=
str
(
module_dir
)
)
if
result
.
returncode
!=
0
:
log
.
warning
(
"go get pre-fetch failed (exit %d) in %s: %s"
,
result
.
returncode
,
module_dir
,
result
.
stderr
.
strip
(),
)
else
:
log
.
info
(
"Pre-fetched %d transitive deps in %s"
,
len
(
deps
),
module_dir
)
def
get_go_modules
(
module_dir
:
Path
,
go_cmd
:
str
,
packages
:
list
[
str
]
)
->
dict
[
str
,
str
]:
"""Return a {module_path: version} map for modules actually imported by *packages*.
Uses ``go list -deps`` to walk the transitive import graph so that modules
which are in the module graph (``go list -m all``) but never imported are
excluded.
"""
cmd
=
[
go_cmd
,
"list"
,
"-deps"
,
"-f"
,
"{{if .Module}}{{.Module.Path}}
\t
{{.Module.Version}}{{end}}"
,
]
+
packages
log
.
debug
(
"Running in %s: %s ..."
,
module_dir
,
" "
.
join
(
cmd
[:
6
]))
result
=
subprocess
.
run
(
cmd
,
capture_output
=
True
,
text
=
True
,
timeout
=
300
,
cwd
=
str
(
module_dir
)
)
if
result
.
returncode
!=
0
:
log
.
error
(
"go list -deps failed (exit %d) in %s: %s"
,
result
.
returncode
,
module_dir
,
result
.
stderr
,
)
raise
RuntimeError
(
f
"go list -deps failed in
{
module_dir
}
:
{
result
.
stderr
}
"
)
modules
:
dict
[
str
,
str
]
=
{}
for
line
in
result
.
stdout
.
strip
().
splitlines
():
if
not
line
or
"
\t
"
not
in
line
:
continue
path
,
version
=
line
.
split
(
"
\t
"
,
1
)
if
path
and
version
:
modules
[
path
]
=
version
return
modules
def
resolve_go_packages
(
module_dir
:
Path
,
go_cmd
:
str
)
->
list
[
str
]:
"""Resolve the list of Go packages in *module_dir*.
Finds subdirectories containing ``.go`` files and runs ``go list`` on them,
skipping stale/non-module directories (e.g. ``srcs/``, ``vendor/``).
"""
go_dirs
:
set
[
str
]
=
set
()
for
go_file
in
module_dir
.
rglob
(
"*.go"
):
rel
=
go_file
.
parent
.
relative_to
(
module_dir
)
parts
=
rel
.
parts
if
parts
and
any
(
p
in
(
"vendor"
,
"srcs"
,
"testdata"
)
or
"@"
in
p
for
p
in
parts
):
continue
go_dirs
.
add
(
str
(
rel
))
if
go_dirs
:
top_dirs
=
{
d
.
split
(
"/"
)[
0
]
if
"/"
in
d
else
d
for
d
in
go_dirs
if
d
!=
"."
}
if
"."
in
go_dirs
:
top_dirs
.
add
(
"."
)
patterns
=
[
f
"./
{
d
}
/..."
for
d
in
sorted
(
top_dirs
)]
if
top_dirs
else
[
"./..."
]
else
:
patterns
=
[
"./..."
]
list_result
=
subprocess
.
run
(
[
go_cmd
,
"list"
]
+
patterns
,
capture_output
=
True
,
text
=
True
,
timeout
=
300
,
cwd
=
str
(
module_dir
),
)
if
list_result
.
returncode
!=
0
:
log
.
warning
(
"go list failed in %s: %s"
,
module_dir
,
list_result
.
stderr
.
strip
())
return
patterns
packages
=
[
p
for
p
in
list_result
.
stdout
.
strip
().
splitlines
()
if
p
]
if
not
packages
:
return
patterns
log
.
debug
(
"Resolved %d packages in %s"
,
len
(
packages
),
module_dir
)
return
packages
def
get_go_licenses
(
module_dir
:
Path
,
go_licenses_cmd
:
str
,
ignore_prefix
:
str
,
packages
:
list
[
str
]
)
->
dict
[
str
,
tuple
[
str
,
str
]]:
"""Run ``go-licenses report`` and return a {package_path: (license_url, spdx)} map."""
cmd
=
[
go_licenses_cmd
,
"report"
]
+
packages
if
ignore_prefix
:
cmd
.
extend
([
"--ignore"
,
ignore_prefix
])
log
.
debug
(
"Running in %s: %s"
,
module_dir
,
" "
.
join
(
cmd
[:
5
])
+
" ..."
)
result
=
subprocess
.
run
(
cmd
,
capture_output
=
True
,
text
=
True
,
timeout
=
300
,
cwd
=
str
(
module_dir
)
)
if
result
.
returncode
!=
0
:
log
.
warning
(
"go-licenses failed (exit %d) in %s: %s"
,
result
.
returncode
,
module_dir
,
result
.
stderr
.
strip
(),
)
raise
RuntimeError
(
f
"go-licenses failed in
{
module_dir
}
"
)
licenses
=
{}
reader
=
csv
.
reader
(
io
.
StringIO
(
result
.
stdout
))
for
row
in
reader
:
if
len
(
row
)
<
3
:
continue
pkg_path
,
license_url
,
spdx
=
row
[
0
],
row
[
1
],
row
[
2
]
licenses
[
pkg_path
]
=
(
license_url
,
spdx
)
return
licenses
def
find_license_for_module
(
module_path
:
str
,
licenses
:
dict
[
str
,
tuple
[
str
,
str
]]
)
->
tuple
[
str
,
str
]:
"""Find the SPDX license and license URL for a module using longest prefix match.
Returns (license_url, spdx_license) or ("", "UNKNOWN") if not found.
"""
best_match
=
""
best_value
=
(
""
,
"UNKNOWN"
)
for
pkg_path
,
(
license_url
,
spdx
)
in
licenses
.
items
():
# Check if the package path starts with the module path
if
pkg_path
==
module_path
or
pkg_path
.
startswith
(
module_path
+
"/"
):
if
len
(
module_path
)
>
len
(
best_match
):
best_match
=
module_path
best_value
=
(
license_url
,
spdx
)
# Also check if the module path starts with the package path
# (for cases where go-licenses reports a parent package)
elif
module_path
.
startswith
(
pkg_path
+
"/"
)
or
module_path
==
pkg_path
:
if
len
(
pkg_path
)
>
len
(
best_match
):
best_match
=
pkg_path
best_value
=
(
license_url
,
spdx
)
return
best_value
def
_strip_version_suffix
(
module_path
:
str
)
->
str
:
"""Strip Go major version suffix like /v2, /v3, etc."""
return
re
.
sub
(
r
"/v\d+$"
,
""
,
module_path
)
def
derive_repo_url
(
module_path
:
str
,
license_url
:
str
=
""
)
->
str
:
"""Derive a repository URL from a Go module path and optional license URL.
Tries to extract the repo URL from the license URL first (most reliable),
then falls back to heuristics based on the module path.
"""
# Try to extract repo URL from license URL (e.g., https://github.com/X/Y/blob/vN/LICENSE)
if
license_url
:
m
=
re
.
match
(
r
"(https://github\.com/[^/]+/[^/]+)"
,
license_url
)
if
m
:
return
m
.
group
(
1
)
m
=
re
.
match
(
r
"(https://gitlab\.com/[^/]+/[^/]+)"
,
license_url
)
if
m
:
return
m
.
group
(
1
)
clean_path
=
_strip_version_suffix
(
module_path
)
# Check well-known exact mappings
for
prefix
,
url
in
_WELLKNOWN_REPOS
.
items
():
if
clean_path
==
prefix
or
clean_path
.
startswith
(
prefix
+
"/"
):
return
url
# Check prefix-based mappings
for
prefix
,
url_base
in
_PREFIX_REPOS
:
if
clean_path
.
startswith
(
prefix
):
# Extract the first path component after the prefix
remainder
=
clean_path
[
len
(
prefix
)
:]
name
=
remainder
.
split
(
"/"
)[
0
]
return
url_base
+
name
# github.com/X/Y/... -> https://github.com/X/Y
if
clean_path
.
startswith
(
"github.com/"
):
parts
=
clean_path
.
split
(
"/"
)
if
len
(
parts
)
>=
3
:
return
f
"https://github.com/
{
parts
[
1
]
}
/
{
parts
[
2
]
}
"
# gitlab.com/X/Y/... -> https://gitlab.com/X/Y
if
clean_path
.
startswith
(
"gitlab.com/"
):
parts
=
clean_path
.
split
(
"/"
)
if
len
(
parts
)
>=
3
:
return
f
"https://gitlab.com/
{
parts
[
1
]
}
/
{
parts
[
2
]
}
"
# gopkg.in/X.vN -> https://github.com/go-X/X (single element)
# gopkg.in/USER/X.vN -> https://github.com/USER/X (two elements)
if
clean_path
.
startswith
(
"gopkg.in/"
):
remainder
=
clean_path
[
len
(
"gopkg.in/"
)
:]
# Strip .vN suffix
remainder
=
re
.
sub
(
r
"\.v\d+$"
,
""
,
remainder
)
parts
=
remainder
.
split
(
"/"
)
if
len
(
parts
)
==
1
:
return
f
"https://github.com/go-
{
parts
[
0
]
}
/
{
parts
[
0
]
}
"
elif
len
(
parts
)
>=
2
:
return
f
"https://github.com/
{
parts
[
0
]
}
/
{
parts
[
1
]
}
"
# Fallback: link to pkg.go.dev
return
f
"https://pkg.go.dev/
{
module_path
}
"
def
deduplicate
(
entries
:
list
[
dict
[
str
,
str
]])
->
list
[
dict
[
str
,
str
]]:
"""Deduplicate entries by (package_name, version)."""
seen
:
dict
[
tuple
[
str
,
str
],
dict
[
str
,
str
]]
=
{}
for
entry
in
entries
:
key
=
(
entry
[
"package_name"
],
entry
[
"version"
])
if
key
not
in
seen
:
seen
[
key
]
=
entry
return
list
(
seen
.
values
())
def
get_module_cache_dirs
(
module_dir
:
Path
,
go_cmd
:
str
)
->
dict
[
str
,
str
]:
"""Run ``go list -m -json all`` and return a {module_path: dir} map.
Only includes modules that have a local ``Dir`` (i.e. are cached).
"""
cmd
=
[
go_cmd
,
"list"
,
"-m"
,
"-json"
,
"all"
]
log
.
debug
(
"Fetching module cache dirs in %s ..."
,
module_dir
)
result
=
subprocess
.
run
(
cmd
,
capture_output
=
True
,
text
=
True
,
timeout
=
300
,
cwd
=
str
(
module_dir
)
)
if
result
.
returncode
!=
0
:
log
.
warning
(
"go list -m -json all failed: %s"
,
result
.
stderr
.
strip
())
return
{}
dirs
:
dict
[
str
,
str
]
=
{}
for
obj
in
_parse_json_stream
(
result
.
stdout
):
path
=
obj
.
get
(
"Path"
,
""
)
mod_dir
=
obj
.
get
(
"Dir"
,
""
)
if
path
and
mod_dir
and
not
obj
.
get
(
"Main"
):
dirs
[
path
]
=
mod_dir
return
dirs
def
_find_license_text
(
directory
:
Path
)
->
str
:
"""Find and read a license file in *directory*."""
for
name
in
_LICENSE_NAMES
:
path
=
directory
/
name
if
path
.
is_file
():
return
path
.
read_text
(
errors
=
"replace"
).
rstrip
()
return
""
def
write_attributions_md
(
packages
:
list
[
dict
[
str
,
str
]],
output_path
:
str
,
module_dirs_map
:
dict
[
str
,
str
],
)
->
None
:
"""Write a markdown attribution file following the ATTRIBUTIONS-Go.md style."""
sorted_packages
=
sorted
(
packages
,
key
=
lambda
p
:
(
p
[
"package_name"
].
lower
(),
p
[
"version"
])
)
lines
=
[
_ATTRIBUTION_PREAMBLE
]
found
=
0
for
pkg
in
sorted_packages
:
mod_dir
=
module_dirs_map
.
get
(
pkg
[
"package_name"
],
""
)
license_text
=
_find_license_text
(
Path
(
mod_dir
))
if
mod_dir
else
""
lines
.
append
(
f
"###
{
pkg
[
'package_name'
]
}
"
)
lines
.
append
(
""
)
lines
.
append
(
f
"License Identifier:
{
pkg
[
'spdx_license'
]
}
"
)
lines
.
append
(
"License Text:"
)
if
license_text
:
lines
.
append
(
f
"```
\n
{
license_text
}
\n
```"
)
found
+=
1
else
:
lines
.
append
(
"```
\n
License text not available locally.
\n
```"
)
lines
.
append
(
""
)
with
open
(
output_path
,
"w"
)
as
f
:
f
.
write
(
"
\n
"
.
join
(
lines
)
+
"
\n
"
)
log
.
info
(
"Wrote attribution markdown to %s (%d/%d with license text)"
,
output_path
,
found
,
len
(
sorted_packages
),
)
def
write_csv
(
packages
:
list
[
dict
[
str
,
str
]],
output_path
:
str
|
None
)
->
None
:
"""Write packages to CSV, sorted by package_name."""
sorted_packages
=
sorted
(
packages
,
key
=
lambda
p
:
p
[
"package_name"
])
if
output_path
:
with
open
(
output_path
,
"w"
,
newline
=
""
)
as
f
:
writer
=
csv
.
DictWriter
(
f
,
fieldnames
=
FIELDNAMES
)
writer
.
writeheader
()
writer
.
writerows
(
sorted_packages
)
log
.
info
(
"Wrote %d entries to %s"
,
len
(
sorted_packages
),
output_path
)
else
:
writer
=
csv
.
DictWriter
(
sys
.
stdout
,
fieldnames
=
FIELDNAMES
)
writer
.
writeheader
()
writer
.
writerows
(
sorted_packages
)
def
parse_args
()
->
argparse
.
Namespace
:
parser
=
argparse
.
ArgumentParser
(
description
=
"Generate a dependency CSV for Go modules"
,
formatter_class
=
argparse
.
RawDescriptionHelpFormatter
,
epilog
=
"""
Examples:
%(prog)s -o go_deps.csv
%(prog)s --module-dirs deploy/operator -o operator_deps.csv
%(prog)s -v
"""
,
)
parser
.
add_argument
(
"--output"
,
"-o"
,
help
=
"Output CSV file path (default: stdout)"
,
)
parser
.
add_argument
(
"--attributions"
,
help
=
"Output attribution markdown file path (e.g. ATTRIBUTIONS-Go.md)"
,
)
parser
.
add_argument
(
"--module-dirs"
,
default
=
","
.
join
(
DEFAULT_MODULE_DIRS
),
help
=
(
"Comma-separated Go module directories relative to repo root "
f
"(default:
{
','
.
join
(
DEFAULT_MODULE_DIRS
)
}
)"
),
)
parser
.
add_argument
(
"--go-cmd"
,
default
=
"go"
,
help
=
"Path to go binary (default: go)"
,
)
parser
.
add_argument
(
"--go-licenses-cmd"
,
default
=
"go-licenses"
,
help
=
"Path to go-licenses binary (default: go-licenses)"
,
)
parser
.
add_argument
(
"--ignore-prefixes"
,
default
=
DEFAULT_IGNORE_PREFIXES
,
help
=
(
"Comma-separated module prefixes to exclude from license scan "
f
"(default:
{
DEFAULT_IGNORE_PREFIXES
}
)"
),
)
parser
.
add_argument
(
"--verbose"
,
"-v"
,
action
=
"store_true"
,
help
=
"Enable verbose logging"
,
)
return
parser
.
parse_args
()
def
main
()
->
None
:
args
=
parse_args
()
logging
.
basicConfig
(
level
=
logging
.
DEBUG
if
args
.
verbose
else
logging
.
INFO
,
format
=
"%(levelname)s: %(message)s"
,
stream
=
sys
.
stderr
,
)
module_dirs
=
[
d
.
strip
()
for
d
in
args
.
module_dirs
.
split
(
","
)
if
d
.
strip
()]
ignore_prefix
=
args
.
ignore_prefixes
.
strip
()
all_entries
:
list
[
dict
[
str
,
str
]]
=
[]
for
rel_dir
in
module_dirs
:
abs_dir
=
_REPO_ROOT
/
rel_dir
if
not
(
abs_dir
/
"go.mod"
).
is_file
():
log
.
error
(
"go.mod not found in %s"
,
abs_dir
)
sys
.
exit
(
1
)
# Resolve packages (skips stale dirs like srcs/)
packages
=
resolve_go_packages
(
abs_dir
,
args
.
go_cmd
)
# Pre-fetch transitive deps that go-licenses requires
prefetch
=
_PREFETCH_DEPS
.
get
(
rel_dir
,
[])
if
prefetch
:
prefetch_deps
(
abs_dir
,
args
.
go_cmd
,
prefetch
)
# Pass 1: get only transitively-imported modules
log
.
info
(
"Listing imported modules in %s ..."
,
rel_dir
)
try
:
modules
=
get_go_modules
(
abs_dir
,
args
.
go_cmd
,
packages
)
except
(
RuntimeError
,
FileNotFoundError
)
as
exc
:
log
.
error
(
"Failed to list modules in %s: %s"
,
rel_dir
,
exc
)
sys
.
exit
(
1
)
log
.
info
(
"Found %d imported modules in %s"
,
len
(
modules
),
rel_dir
)
# Pass 2: get license info via go-licenses
licenses
:
dict
[
str
,
tuple
[
str
,
str
]]
=
{}
try
:
licenses
=
get_go_licenses
(
abs_dir
,
args
.
go_licenses_cmd
,
ignore_prefix
,
packages
)
log
.
info
(
"Found %d license entries in %s"
,
len
(
licenses
),
rel_dir
)
except
FileNotFoundError
:
log
.
warning
(
"go-licenses not found on PATH. Install with: "
"go install github.com/google/go-licenses@v1.6.0"
)
log
.
warning
(
"License info will be UNKNOWN for all modules."
)
except
RuntimeError
:
log
.
warning
(
"go-licenses failed for %s, license info will be UNKNOWN."
,
rel_dir
)
# Merge: build entries for each module
for
mod_path
,
version
in
modules
.
items
():
license_url
,
spdx
=
find_license_for_module
(
mod_path
,
licenses
)
repo_url
=
derive_repo_url
(
mod_path
,
license_url
)
all_entries
.
append
(
{
"dependency_type"
:
"go"
,
"package_name"
:
mod_path
,
"version"
:
version
,
"spdx_license"
:
spdx
,
"repo_url"
:
repo_url
,
}
)
deduplicated
=
deduplicate
(
all_entries
)
log
.
info
(
"Total unique Go dependencies: %d"
,
len
(
deduplicated
))
if
args
.
output
or
not
args
.
attributions
:
write_csv
(
deduplicated
,
args
.
output
)
if
args
.
attributions
:
# Fetch local cache dirs from each Go module directory and merge.
unique_mods
=
{
e
[
"package_name"
]
for
e
in
deduplicated
}
module_dirs_map
:
dict
[
str
,
str
]
=
{}
for
rel_dir
in
module_dirs
:
abs_dir
=
_REPO_ROOT
/
rel_dir
partial
=
get_module_cache_dirs
(
abs_dir
,
args
.
go_cmd
)
# Only keep modules we actually need
for
mod_path
,
mod_dir
in
partial
.
items
():
if
mod_path
in
unique_mods
and
mod_path
not
in
module_dirs_map
:
module_dirs_map
[
mod_path
]
=
mod_dir
log
.
info
(
"Resolved %d/%d module cache dirs"
,
len
(
module_dirs_map
),
len
(
unique_mods
)
)
write_attributions_md
(
deduplicated
,
args
.
attributions
,
module_dirs_map
)
if
__name__
==
"__main__"
:
main
()
container/compliance/generate_rust_deps.py
0 → 100755
View file @
01a4b6d6
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Generate a dependency CSV (and optional attribution markdown) for Rust crates.
Extracts external Rust dependencies from one or more Cargo workspaces using
``cargo metadata`` and writes a CSV with dependency type, package name,
version, SPDX license identifier, and repository URL. Optionally generates
an attribution markdown file with full license texts.
Usage:
python generate_rust_deps.py -o rust_deps.csv
python generate_rust_deps.py --attributions ATTRIBUTIONS-Rust.md
python generate_rust_deps.py -o rust_deps.csv --attributions attr.md -v
"""
import
argparse
import
csv
import
json
import
logging
import
re
import
subprocess
import
sys
from
pathlib
import
Path
_SCRIPT_DIR
=
Path
(
__file__
).
resolve
().
parent
_REPO_ROOT
=
_SCRIPT_DIR
.
parent
.
parent
log
=
logging
.
getLogger
(
__name__
)
FIELDNAMES
=
[
"dependency_type"
,
"package_name"
,
"version"
,
"spdx_license"
,
"repo_url"
]
DEFAULT_MANIFEST_PATHS
=
[
"Cargo.toml"
,
"lib/bindings/python/Cargo.toml"
,
"lib/bindings/kvbm/Cargo.toml"
,
]
_LICENSE_NAMES
=
[
"LICENSE"
,
"LICENSE.md"
,
"LICENSE.txt"
,
"LICENSE-MIT"
,
"LICENSE-APACHE"
,
"LICENCE"
,
"LICENCE.md"
,
"LICENCE.txt"
,
"COPYING"
,
"COPYING.md"
,
]
_ATTRIBUTION_PREAMBLE
=
"""
\
<!--
SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->
# Third-Party Software Attributions
This project uses the following third-party libraries. Each library is
\
open-source and licensed under the terms indicated below.
This file is automatically generated. Please do not edit it directly.
"""
def
get_cargo_metadata
(
manifest_path
:
Path
,
cargo_cmd
:
str
)
->
dict
:
"""Run ``cargo metadata`` and return the parsed JSON."""
cmd
=
[
cargo_cmd
,
"metadata"
,
"--format-version"
,
"1"
,
"--locked"
,
"--manifest-path"
,
str
(
manifest_path
),
]
log
.
debug
(
"Running: %s"
,
" "
.
join
(
cmd
))
result
=
subprocess
.
run
(
cmd
,
capture_output
=
True
,
text
=
True
,
timeout
=
300
)
if
result
.
returncode
!=
0
:
log
.
error
(
"cargo metadata failed (exit %d) for %s: %s"
,
result
.
returncode
,
manifest_path
,
result
.
stderr
,
)
raise
RuntimeError
(
f
"cargo metadata failed for
{
manifest_path
}
:
{
result
.
stderr
}
"
)
return
json
.
loads
(
result
.
stdout
)
def
extract_external_deps
(
metadata
:
dict
)
->
list
[
dict
[
str
,
str
]]:
"""Extract external (non-workspace, non-local) dependencies from cargo metadata."""
workspace_member_ids
=
set
(
metadata
.
get
(
"workspace_members"
,
[]))
packages
=
[]
for
pkg
in
metadata
.
get
(
"packages"
,
[]):
# Skip workspace members (local crates)
if
pkg
[
"id"
]
in
workspace_member_ids
:
continue
# Skip path-only dependencies (local crates outside the workspace)
if
pkg
.
get
(
"source"
)
is
None
:
continue
repo_url
=
pkg
.
get
(
"repository"
)
or
""
if
not
repo_url
:
repo_url
=
f
"https://crates.io/crates/
{
pkg
[
'name'
]
}
"
packages
.
append
(
{
"dependency_type"
:
"rust"
,
"package_name"
:
pkg
[
"name"
],
"version"
:
pkg
[
"version"
],
"spdx_license"
:
pkg
.
get
(
"license"
)
or
"UNKNOWN"
,
"repo_url"
:
repo_url
,
"manifest_path"
:
pkg
.
get
(
"manifest_path"
,
""
),
}
)
return
packages
def
deduplicate
(
entries
:
list
[
dict
[
str
,
str
]])
->
list
[
dict
[
str
,
str
]]:
"""Deduplicate entries by (package_name, version)."""
seen
:
dict
[
tuple
[
str
,
str
],
dict
[
str
,
str
]]
=
{}
for
entry
in
entries
:
key
=
(
entry
[
"package_name"
],
entry
[
"version"
])
if
key
not
in
seen
:
seen
[
key
]
=
entry
return
list
(
seen
.
values
())
def
_find_license_text
(
directory
:
Path
)
->
str
:
"""Find and read a license file in *directory*."""
for
name
in
_LICENSE_NAMES
:
path
=
directory
/
name
if
path
.
is_file
():
return
path
.
read_text
(
errors
=
"replace"
).
rstrip
()
return
""
def
_raw_license_url
(
repo_url
:
str
,
license_filename
:
str
=
"LICENSE"
)
->
str
:
"""Convert a GitHub/GitLab repo URL to a raw license URL for display."""
m
=
re
.
match
(
r
"https://github\.com/([^/]+/[^/]+)"
,
repo_url
)
if
m
:
return
f
"https://raw.githubusercontent.com/
{
m
.
group
(
1
)
}
/HEAD/
{
license_filename
}
"
return
repo_url
def
write_attributions_md
(
packages
:
list
[
dict
[
str
,
str
]],
output_path
:
str
)
->
None
:
"""Write a markdown attribution file following the ATTRIBUTIONS-Rust.md style."""
sorted_packages
=
sorted
(
packages
,
key
=
lambda
p
:
(
p
[
"package_name"
].
lower
(),
p
[
"version"
])
)
lines
=
[
_ATTRIBUTION_PREAMBLE
]
found
=
0
for
pkg
in
sorted_packages
:
manifest
=
pkg
.
get
(
"manifest_path"
,
""
)
license_text
=
""
license_filename
=
"LICENSE"
if
manifest
:
pkg_dir
=
Path
(
manifest
).
parent
for
name
in
_LICENSE_NAMES
:
path
=
pkg_dir
/
name
if
path
.
is_file
():
license_text
=
path
.
read_text
(
errors
=
"replace"
).
rstrip
()
license_filename
=
name
break
raw_url
=
_raw_license_url
(
pkg
[
"repo_url"
],
license_filename
)
lines
.
append
(
f
"
\n
##
{
pkg
[
'package_name'
]
}
-
{
pkg
[
'version'
]
}
"
)
lines
.
append
(
f
"**Repository URL**:
{
pkg
[
'repo_url'
]
}
"
)
lines
.
append
(
f
"**License Type(s)**:
{
pkg
[
'spdx_license'
]
}
"
)
lines
.
append
(
f
"### License:
{
raw_url
}
"
)
if
license_text
:
lines
.
append
(
f
"```
\n
{
license_text
}
\n
```"
)
found
+=
1
else
:
lines
.
append
(
"```
\n
License text not available locally.
\n
```"
)
with
open
(
output_path
,
"w"
)
as
f
:
f
.
write
(
"
\n
"
.
join
(
lines
)
+
"
\n
"
)
log
.
info
(
"Wrote attribution markdown to %s (%d/%d with license text)"
,
output_path
,
found
,
len
(
sorted_packages
),
)
def
write_csv
(
packages
:
list
[
dict
[
str
,
str
]],
output_path
:
str
|
None
)
->
None
:
"""Write packages to CSV, sorted by package_name."""
sorted_packages
=
sorted
(
packages
,
key
=
lambda
p
:
p
[
"package_name"
])
if
output_path
:
with
open
(
output_path
,
"w"
,
newline
=
""
)
as
f
:
writer
=
csv
.
DictWriter
(
f
,
fieldnames
=
FIELDNAMES
,
extrasaction
=
"ignore"
)
writer
.
writeheader
()
writer
.
writerows
(
sorted_packages
)
log
.
info
(
"Wrote %d entries to %s"
,
len
(
sorted_packages
),
output_path
)
else
:
writer
=
csv
.
DictWriter
(
sys
.
stdout
,
fieldnames
=
FIELDNAMES
,
extrasaction
=
"ignore"
)
writer
.
writeheader
()
writer
.
writerows
(
sorted_packages
)
def
parse_args
()
->
argparse
.
Namespace
:
parser
=
argparse
.
ArgumentParser
(
description
=
"Generate a dependency CSV for Rust crates in the workspace"
,
formatter_class
=
argparse
.
RawDescriptionHelpFormatter
,
epilog
=
"""
Examples:
%(prog)s -o rust_deps.csv
%(prog)s --manifest-paths Cargo.toml -o rust_deps.csv
%(prog)s -v
"""
,
)
parser
.
add_argument
(
"--output"
,
"-o"
,
help
=
"Output CSV file path (default: stdout)"
,
)
parser
.
add_argument
(
"--attributions"
,
help
=
"Output attribution markdown file path (e.g. ATTRIBUTIONS-Rust.md)"
,
)
parser
.
add_argument
(
"--manifest-paths"
,
default
=
","
.
join
(
DEFAULT_MANIFEST_PATHS
),
help
=
(
"Comma-separated Cargo.toml paths relative to repo root "
f
"(default:
{
','
.
join
(
DEFAULT_MANIFEST_PATHS
)
}
)"
),
)
parser
.
add_argument
(
"--cargo-cmd"
,
default
=
"cargo"
,
help
=
"Path to cargo binary (default: cargo)"
,
)
parser
.
add_argument
(
"--verbose"
,
"-v"
,
action
=
"store_true"
,
help
=
"Enable verbose logging"
,
)
return
parser
.
parse_args
()
def
main
()
->
None
:
args
=
parse_args
()
logging
.
basicConfig
(
level
=
logging
.
DEBUG
if
args
.
verbose
else
logging
.
INFO
,
format
=
"%(levelname)s: %(message)s"
,
stream
=
sys
.
stderr
,
)
manifest_paths
=
[
p
.
strip
()
for
p
in
args
.
manifest_paths
.
split
(
","
)
if
p
.
strip
()]
all_entries
:
list
[
dict
[
str
,
str
]]
=
[]
for
rel_path
in
manifest_paths
:
abs_path
=
_REPO_ROOT
/
rel_path
if
not
abs_path
.
is_file
():
log
.
warning
(
"Manifest not found, skipping: %s"
,
abs_path
)
continue
log
.
info
(
"Scanning %s ..."
,
rel_path
)
try
:
metadata
=
get_cargo_metadata
(
abs_path
,
args
.
cargo_cmd
)
except
(
RuntimeError
,
FileNotFoundError
)
as
exc
:
log
.
error
(
"Failed to get metadata for %s: %s"
,
rel_path
,
exc
)
sys
.
exit
(
1
)
entries
=
extract_external_deps
(
metadata
)
log
.
info
(
"Found %d external deps in %s"
,
len
(
entries
),
rel_path
)
all_entries
.
extend
(
entries
)
deduplicated
=
deduplicate
(
all_entries
)
log
.
info
(
"Total unique Rust dependencies: %d"
,
len
(
deduplicated
))
if
args
.
output
or
not
args
.
attributions
:
write_csv
(
deduplicated
,
args
.
output
)
if
args
.
attributions
:
write_attributions_md
(
deduplicated
,
args
.
attributions
)
if
__name__
==
"__main__"
:
main
()
deploy/helm/charts/platform/Chart.yaml
View file @
01a4b6d6
...
...
@@ -19,11 +19,11 @@ maintainers:
url
:
https://www.nvidia.com
description
:
A Helm chart for NVIDIA Dynamo Platform.
type
:
application
version
:
1.
0
.0
version
:
1.
1
.0
home
:
https://nvidia.com
dependencies
:
-
name
:
dynamo-operator
version
:
1.
0
.0
version
:
1.
1
.0
repository
:
file://components/operator
condition
:
dynamo-operator.enabled
-
name
:
nats
...
...
deploy/helm/charts/platform/README.md
View file @
01a4b6d6
...
...
@@ -19,7 +19,7 @@ limitations under the License.
A Helm chart for NVIDIA Dynamo Platform.




## 🚀 Overview
...
...
@@ -97,7 +97,7 @@ The chart includes built-in validation to prevent all operator conflicts:
| Repository | Name | Version |
|------------|------|---------|
| file://components/operator | dynamo-operator | 1.
0
.0 |
| file://components/operator | dynamo-operator | 1.
1
.0 |
| https://charts.bitnami.com/bitnami | etcd | 12.0.18 |
| https://nats-io.github.io/k8s/helm/charts/ | nats | 1.3.2 |
| oci://ghcr.io/ai-dynamo/grove | grove(grove-charts) | v0.1.0-alpha.7 |
...
...
deploy/helm/charts/platform/components/operator/Chart.yaml
View file @
01a4b6d6
...
...
@@ -27,9 +27,9 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version
:
1.
0
.0
version
:
1.
1
.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion
:
"
1.
0
.0"
appVersion
:
"
1.
1
.0"
deploy/helm/charts/snapshot/Chart.yaml
View file @
01a4b6d6
...
...
@@ -16,8 +16,8 @@ apiVersion: v2
name
:
snapshot
description
:
Checkpoint/Restore infrastructure for Dynamo (PVC + DaemonSet + CRIU Agent)
type
:
application
version
:
1.
0
.0
appVersion
:
"
1.
0
.0"
version
:
1.
1
.0
appVersion
:
"
1.
1
.0"
keywords
:
-
nvidia
-
dynamo
...
...
lib/bindings/kvbm/Cargo.lock
View file @
01a4b6d6
...
...
@@ -1490,14 +1490,14 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "dynamo-config"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
]
[[package]]
name = "dynamo-kv-router"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-trait",
...
...
@@ -1524,7 +1524,7 @@ dependencies = [
[[package]]
name = "dynamo-llm"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"aho-corasick",
"aligned-vec",
...
...
@@ -1609,7 +1609,7 @@ dependencies = [
[[package]]
name = "dynamo-memory"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"cudarc",
...
...
@@ -1625,7 +1625,7 @@ dependencies = [
[[package]]
name = "dynamo-mocker"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"dashmap",
...
...
@@ -1652,7 +1652,7 @@ dependencies = [
[[package]]
name = "dynamo-parsers"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"dynamo-protocols",
...
...
@@ -1669,7 +1669,7 @@ dependencies = [
[[package]]
name = "dynamo-protocols"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"async-openai",
"derive_builder",
...
...
@@ -1684,7 +1684,7 @@ dependencies = [
[[package]]
name = "dynamo-runtime"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"arc-swap",
...
...
@@ -1751,7 +1751,7 @@ dependencies = [
[[package]]
name = "dynamo-tokens"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"bs58",
"bytemuck",
...
...
@@ -3229,7 +3229,7 @@ dependencies = [
[[package]]
name = "kvbm-py3"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"cudarc",
...
...
lib/bindings/kvbm/Cargo.toml
View file @
01a4b6d6
...
...
@@ -5,7 +5,7 @@
[package]
name
=
"kvbm-py3"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition
=
"2024"
authors
=
["NVIDIA"]
license
=
"Apache-2.0"
...
...
lib/bindings/kvbm/pyproject.toml
View file @
01a4b6d6
...
...
@@ -16,7 +16,7 @@
[project]
name
=
"kvbm"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
description
=
"Dynamo KVBM"
readme
=
"README.md"
authors
=
[
...
...
lib/bindings/python/Cargo.lock
View file @
01a4b6d6
...
...
@@ -1498,14 +1498,14 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "dynamo-config"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
]
[[package]]
name = "dynamo-kv-router"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-trait",
...
...
@@ -1536,7 +1536,7 @@ dependencies = [
[[package]]
name = "dynamo-llm"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"aho-corasick",
"aligned-vec",
...
...
@@ -1624,7 +1624,7 @@ dependencies = [
[[package]]
name = "dynamo-memory"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"cudarc",
...
...
@@ -1640,7 +1640,7 @@ dependencies = [
[[package]]
name = "dynamo-mocker"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"dashmap",
...
...
@@ -1667,7 +1667,7 @@ dependencies = [
[[package]]
name = "dynamo-parsers"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"dynamo-protocols",
...
...
@@ -1684,7 +1684,7 @@ dependencies = [
[[package]]
name = "dynamo-protocols"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"async-openai",
"derive_builder",
...
...
@@ -1699,7 +1699,7 @@ dependencies = [
[[package]]
name = "dynamo-py3"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"async-trait",
...
...
@@ -1730,7 +1730,7 @@ dependencies = [
[[package]]
name = "dynamo-runtime"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"anyhow",
"arc-swap",
...
...
@@ -1798,7 +1798,7 @@ dependencies = [
[[package]]
name = "dynamo-tokens"
version = "1.
0
.0"
version = "1.
1
.0"
dependencies = [
"bs58",
"bytemuck",
...
...
lib/bindings/python/Cargo.toml
View file @
01a4b6d6
...
...
@@ -7,7 +7,7 @@
[package]
name
=
"dynamo-py3"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition
=
"2024"
authors
=
["NVIDIA"]
license
=
"Apache-2.0"
...
...
lib/bindings/python/pyproject.toml
View file @
01a4b6d6
...
...
@@ -16,7 +16,7 @@
[project]
name
=
"ai-dynamo-runtime"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
description
=
"Dynamo Inference Framework Runtime"
readme
=
"README.md"
authors
=
[
...
...
lib/kvbm-common/Cargo.toml
View file @
01a4b6d6
...
...
@@ -3,7 +3,7 @@
[package]
name
=
"kvbm-common"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition.workspace
=
true
description.workspace
=
true
authors.workspace
=
true
...
...
lib/kvbm-engine/Cargo.toml
View file @
01a4b6d6
...
...
@@ -3,7 +3,7 @@
[package]
name
=
"kvbm-engine"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition.workspace
=
true
authors.workspace
=
true
license.workspace
=
true
...
...
lib/kvbm-kernels/Cargo.toml
View file @
01a4b6d6
...
...
@@ -3,7 +3,7 @@
[package]
name
=
"kvbm-kernels"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition.workspace
=
true
authors.workspace
=
true
license.workspace
=
true
...
...
lib/kvbm-logical/Cargo.toml
View file @
01a4b6d6
...
...
@@ -3,7 +3,7 @@
[package]
name
=
"kvbm-logical"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition.workspace
=
true
authors.workspace
=
true
license.workspace
=
true
...
...
lib/kvbm-physical/Cargo.toml
View file @
01a4b6d6
...
...
@@ -3,7 +3,7 @@
[package]
name
=
"kvbm-physical"
version
=
"1.
0
.0"
version
=
"1.
1
.0"
edition.workspace
=
true
authors.workspace
=
true
license.workspace
=
true
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment