From 2b1b87215ba9a7e115efc8bf33bd82883e5a41bb Mon Sep 17 00:00:00 2001 From: Ralf Juengling Date: Thu, 5 Nov 2026 15:14:04 -0800 Subject: [PATCH 1/4] CI: Use the matrix CTK's compute-sanitizer instead of the latest release Fetch cuda_sanitizer_api from the same pinned redistrib manifest as the rest of the mini CTK, rather than from whatever release ci/tools/guess_latest.sh scrapes from the redist directory listing. Remove guess_latest.sh, which has no other users. --- .github/workflows/test-wheel-linux.yml | 4 +-- ci/tools/compute_ci_plan.py | 1 - ci/tools/env-vars | 1 - ci/tools/guess_latest.sh | 42 -------------------------- ci/tools/tests/test_compute_ci_plan.py | 1 - 5 files changed, 2 insertions(+), 47 deletions(-) delete mode 100644 ci/tools/guess_latest.sh diff --git a/.github/workflows/test-wheel-linux.yml b/.github/workflows/test-wheel-linux.yml index c2c7523b68c..4b35c689a05 100644 --- a/.github/workflows/test-wheel-linux.yml +++ b/.github/workflows/test-wheel-linux.yml @@ -361,13 +361,13 @@ jobs: host-platform: ${{ inputs.host-platform }} cuda-version: ${{ matrix.CUDA_VER }} - - name: Set up latest cuda_sanitizer_api + - name: Set up cuda_sanitizer_api if: ${{ (env.TEST_BINDINGS == 'true' || env.TEST_CORE == 'true') && env.SETUP_SANITIZER == '1' }} uses: ./.github/actions/fetch_ctk continue-on-error: false with: host-platform: ${{ inputs.host-platform }} - cuda-version: ${{ env.LATEST_CUDA_VERSION }} + cuda-version: ${{ matrix.CUDA_VER }} cuda-components: "cuda_sanitizer_api" - name: Set up compute-sanitizer diff --git a/ci/tools/compute_ci_plan.py b/ci/tools/compute_ci_plan.py index 51493044569..1ab4b2961b9 100644 --- a/ci/tools/compute_ci_plan.py +++ b/ci/tools/compute_ci_plan.py @@ -56,7 +56,6 @@ ".github/workflows/test-wheel-linux.yml": "linux", ".github/workflows/test-wheel-windows.yml": "windows", "ci/tools/configure_driver_mode.ps1": "windows", - "ci/tools/guess_latest.sh": "linux", "ci/tools/install_gpu_driver.ps1": "windows", "ci/tools/install_gpu_driver.sh": "linux", "ci/tools/setup-sanitizer": "linux", diff --git a/ci/tools/env-vars b/ci/tools/env-vars index 262de423065..9946ad549de 100755 --- a/ci/tools/env-vars +++ b/ci/tools/env-vars @@ -119,7 +119,6 @@ elif [[ "${1}" == "test" ]]; then # We only test compute-sanitizer on python 3.12 arbitrarily; we don't need to use sanitizer on the entire matrix # Only local ctk installs have compute-sanitizer; there is no wheel for it if [[ "${PY_VER}" == "3.12" && "${CUDA_VER}" != "11.8.0" && "${LOCAL_CTK}" == 1 && "${HOST_PLATFORM}" == linux* ]]; then - echo "LATEST_CUDA_VERSION=$(bash ci/tools/guess_latest.sh $TEST_CUDA_MAJOR)" >> $GITHUB_ENV SETUP_SANITIZER=1 else SETUP_SANITIZER=0 diff --git a/ci/tools/guess_latest.sh b/ci/tools/guess_latest.sh deleted file mode 100644 index f9d383f2094..00000000000 --- a/ci/tools/guess_latest.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# -# SPDX-License-Identifier: Apache-2.0 - -# URL to search -URL="https://developer.download.nvidia.com/compute/cuda/redist/" - -# Ensure exactly one argument is provided -if [ "$#" -ne 1 ]; then - echo "Usage: $0 " - exit 1 -fi - -# Accept major version as the first argument -MAJOR_VERSION="$1" - -# Fetch the directory listing and extract the latest version number -get_latest_version() { - # Get the HTML content of the page - local html_content=$(wget -q -O - "$URL") - - # Extract links matching the pattern redistrib_?.?.?.json - local files=$(echo "$html_content" | grep -oP "redistrib_${MAJOR_VERSION}\.[0-9]+\.[0-9]+\.json" | cut -d'"' -f2) - - # If files were found, extract the version numbers and find the latest - if [ -n "$files" ]; then - # Extract just the version numbers using regex - local versions=$(echo "$files" | grep -oP "redistrib_\K${MAJOR_VERSION}\.[0-9]+\.[0-9]+(?=\.json)") - - # Sort the versions and get the latest - local latest_version=$(echo "$versions" | sort -V | tail -n 1) - echo "$latest_version" - else - echo "No files matching the pattern were found." - return 1 - fi -} - -# Call the function and store the result -latest_version=$(get_latest_version) -echo $latest_version diff --git a/ci/tools/tests/test_compute_ci_plan.py b/ci/tools/tests/test_compute_ci_plan.py index b87326420ee..c08eddb6dcd 100644 --- a/ci/tools/tests/test_compute_ci_plan.py +++ b/ci/tools/tests/test_compute_ci_plan.py @@ -85,7 +85,6 @@ def test_test_infrastructure_platforms(self) -> None: ".github/workflows/test-wheel-linux.yml": {"linux"}, ".github/workflows/test-wheel-windows.yml": {"windows"}, "ci/tools/configure_driver_mode.ps1": {"windows"}, - "ci/tools/guess_latest.sh": {"linux"}, "ci/tools/install_gpu_driver.ps1": {"windows"}, "ci/tools/install_gpu_driver.sh": {"linux"}, "ci/tools/setup-sanitizer": {"linux"}, From 241ef09518d1d0aab9e3c8de046cecf6065f24d9 Mon Sep 17 00:00:00 2001 From: Ralf Juengling Date: Thu, 5 Nov 2026 15:31:04 -0800 Subject: [PATCH 2/4] CI: Fail closed on unpinned redistrib manifests verify-metadata used to warn and pass when a public-server CUDA version had no pinned manifest hash, so the 13.4.2 -> 13.5.0 bump ran unpinned. Fail closed instead, with an explicit fetch_ctk allow-unpinned input (and --allow-unpinned flag) as the opt-out; it never overrides a mismatch against an existing pin. Manifests from an alternate redist server stay warn-only. Pin 13.5.0 and add a test that every CUDA version in ci/versions.yml and every LOCAL_CTK row of ci/test-matrix.yml is pinned. --- .github/actions/fetch_ctk/action.yml | 15 ++++- ci/tools/fetch_ctk_redistrib.py | 36 ++++++++---- ci/tools/tests/test_fetch_ctk_redistrib.py | 64 ++++++++++++++++++++-- 3 files changed, 99 insertions(+), 16 deletions(-) diff --git a/.github/actions/fetch_ctk/action.yml b/.github/actions/fetch_ctk/action.yml index 65b05a66acf..9931403f8b0 100644 --- a/.github/actions/fetch_ctk/action.yml +++ b/.github/actions/fetch_ctk/action.yml @@ -26,6 +26,13 @@ inputs: Override to install from an alternate redistrib server. required: false default: "https://developer.download.nvidia.com/compute/cuda/redist" + allow-unpinned: + description: > + Set to "true" to accept a public-server CUDA version whose manifest hash is + not pinned in ci/tools/fetch_ctk_redistrib.py (warn instead of fail). + A mismatch against an existing pin always fails. + required: false + default: "false" runs: using: composite @@ -63,10 +70,16 @@ runs: else METADATA_SOURCE=custom fi + case "${{ inputs.allow-unpinned }}" in + true) ALLOW_UNPINNED_FLAG=--allow-unpinned ;; + false) ALLOW_UNPINNED_FLAG= ;; + *) echo "ERROR: allow-unpinned must be 'true' or 'false'" >&2; exit 1 ;; + esac python "$CTK_REDIST_TOOL" verify-metadata \ --cuda-version "${{ inputs.cuda-version }}" \ --metadata-path "$CTK_JSON_FILE" \ - --metadata-source "$METADATA_SOURCE" + --metadata-source "$METADATA_SOURCE" \ + ${ALLOW_UNPINNED_FLAG} # Pre-process the component list to ensure hash uniqueness CTK_CACHE_COMPONENTS="$(python "$CTK_REDIST_TOOL" filter-components \ diff --git a/ci/tools/fetch_ctk_redistrib.py b/ci/tools/fetch_ctk_redistrib.py index 1a75ed471a8..a6ad3e4116e 100644 --- a/ci/tools/fetch_ctk_redistrib.py +++ b/ci/tools/fetch_ctk_redistrib.py @@ -29,10 +29,11 @@ # Known-good sha256 of the redistrib metadata JSON, keyed by CUDA version. # Per-archive verification is only trustworthy if the JSON that carries the -# archive hashes is itself trusted, so we pin the metadata too. A version that -# is absent here is not blocked -- failing closed would break CI on every new -# CTK -- but `verify-metadata` emits a warning; add the version's hash below as -# it enters the matrix to pin it. Regenerate with: +# archive hashes is itself trusted, so we pin the metadata too. `verify-metadata` +# fails on a public-server version that is absent here unless the caller opts +# out with `--allow-unpinned`. Add a version's hash below in the same change +# that adds it to ci/versions.yml or a LOCAL_CTK row of ci/test-matrix.yml; +# tests/test_fetch_ctk_redistrib.py enforces this. Regenerate with: # curl -fsSL \ # https://developer.download.nvidia.com/compute/cuda/redist/redistrib_.json \ # | sha256sum @@ -41,6 +42,7 @@ "12.9.1": "8335301010b0023ee1ff61eb11e2600ca62002d76780de4089011ad77e0c7630", "13.0.2": "fce66717a81c510ffeb89ecc3e79849ab34af3b80139f750876d9033e31d71c2", "13.4.2": "015b97aa3977d4d0bade1631b226b6d4cbe48751cc841aad9193295df7f9047a", + "13.5.0": "401529e951b845788177f999c0756c520c4d0db1cd4cd05c0a295e331884b596", } @@ -146,7 +148,9 @@ def compute_file_sha256(path: str) -> str: return digest.hexdigest() -def verify_metadata_sha256(*, cuda_version: str, metadata_path: str, metadata_source: str = "public") -> int: +def verify_metadata_sha256( + *, cuda_version: str, metadata_path: str, metadata_source: str = "public", allow_unpinned: bool = False +) -> int: """Verify the redistrib JSON against the pinned hash for its CUDA version. The pins describe the public developer.download.nvidia.com manifests. A @@ -154,8 +158,10 @@ def verify_metadata_sha256(*, cuda_version: str, metadata_path: str, metadata_so manifest under the same version number, so it is never checked against them; it only gets a warning. - Returns a process exit code: 1 on a mismatch (fail closed), 0 when the hash - matches, the version is not pinned yet, or the source is custom (warn only). + Returns a process exit code: 1 on a mismatch or an unpinned public version + (fail closed), 0 when the hash matches, the source is custom, or the version + is unpinned and ``allow_unpinned`` is set (warn only). ``allow_unpinned`` + never overrides a mismatch against an existing pin. """ actual = compute_file_sha256(metadata_path) if metadata_source == "custom": @@ -167,12 +173,20 @@ def verify_metadata_sha256(*, cuda_version: str, metadata_path: str, metadata_so return 0 expected = KNOWN_REDISTRIB_SHA256.get(cuda_version) if expected is None: + if allow_unpinned: + print( + f"WARNING: no pinned redistrib sha256 for CUDA {cuda_version!r}; got {actual}. " + "Continuing because unpinned versions are explicitly allowed.", + file=sys.stderr, + ) + return 0 print( - f"WARNING: no pinned redistrib sha256 for CUDA {cuda_version!r}; got {actual}. " - f"Add it to KNOWN_REDISTRIB_SHA256 in {Path(__file__).name} to pin it.", + f"ERROR: no pinned redistrib sha256 for CUDA {cuda_version!r}; got {actual}. " + f"Add it to KNOWN_REDISTRIB_SHA256 in {Path(__file__).name}, " + "or pass --allow-unpinned (fetch_ctk input allow-unpinned) to accept it unverified.", file=sys.stderr, ) - return 0 + return 1 if actual != expected: print( f"ERROR: redistrib metadata sha256 mismatch for CUDA {cuda_version!r}: expected {expected}, got {actual}", @@ -207,6 +221,7 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: verify_parser.add_argument("--cuda-version", required=True) verify_parser.add_argument("--metadata-path", required=True) verify_parser.add_argument("--metadata-source", choices=("public", "custom"), default="public") + verify_parser.add_argument("--allow-unpinned", action="store_true") return parser.parse_args(argv) @@ -221,6 +236,7 @@ def main(argv: list[str] | None = None) -> int: cuda_version=args.cuda_version, metadata_path=args.metadata_path, metadata_source=args.metadata_source, + allow_unpinned=args.allow_unpinned, ) metadata = load_metadata(args.metadata_path) diff --git a/ci/tools/tests/test_fetch_ctk_redistrib.py b/ci/tools/tests/test_fetch_ctk_redistrib.py index dad75da1a1b..5a06c2c9c37 100644 --- a/ci/tools/tests/test_fetch_ctk_redistrib.py +++ b/ci/tools/tests/test_fetch_ctk_redistrib.py @@ -4,13 +4,16 @@ from __future__ import annotations import json +import re import sys from pathlib import Path import pytest +import yaml sys.path.insert(0, str(Path(__file__).parent.parent)) from fetch_ctk_redistrib import ( + KNOWN_REDISTRIB_SHA256, compute_file_sha256, get_component_relative_path, get_component_sha256, @@ -18,6 +21,9 @@ verify_metadata_sha256, ) +CI_DIR = Path(__file__).resolve().parents[2] +SHA256_RE = re.compile(r"^[0-9a-f]{64}$") + # Minimal redistrib-shaped metadata. "cccl" exercises the cuda_cccl -> cccl # alias; "no_sha" lacks the sha256 field. FAKE_METADATA = { @@ -101,16 +107,64 @@ def test_verify_metadata_mismatch_fails_closed(tmp_path, monkeypatch): assert verify_metadata_sha256(cuda_version="1.2.3", metadata_path=str(f)) == 1 -@pytest.mark.agent_authored(model="claude-opus-4.8") -def test_verify_metadata_unknown_version_warns(tmp_path, capsys): +@pytest.mark.agent_authored(model="claude-opus-5.5") +def test_verify_metadata_unknown_version_fails_closed(tmp_path, capsys): + f = tmp_path / "redistrib.json" + f.write_bytes(b"whatever") + assert verify_metadata_sha256(cuda_version="99.9.9", metadata_path=str(f)) == 1 + assert "ERROR" in capsys.readouterr().err + + +@pytest.mark.agent_authored(model="claude-opus-5.5") +def test_verify_metadata_unknown_version_allowed_warns(tmp_path, capsys): + f = tmp_path / "redistrib.json" + f.write_bytes(b"whatever") + assert verify_metadata_sha256(cuda_version="99.9.9", metadata_path=str(f), allow_unpinned=True) == 0 + assert "WARNING" in capsys.readouterr().err + + +@pytest.mark.agent_authored(model="claude-opus-5.5") +def test_verify_metadata_allow_unpinned_does_not_bypass_mismatch(tmp_path, monkeypatch): + f = tmp_path / "redistrib.json" + f.write_bytes(b"tampered-metadata") + monkeypatch.setitem( + sys.modules["fetch_ctk_redistrib"].KNOWN_REDISTRIB_SHA256, + "1.2.3", + "f" * 64, + ) + assert verify_metadata_sha256(cuda_version="1.2.3", metadata_path=str(f), allow_unpinned=True) == 1 + + +@pytest.mark.agent_authored(model="claude-opus-5.5") +def test_main_verify_metadata_allow_unpinned_flag(tmp_path, capsys): f = tmp_path / "redistrib.json" f.write_bytes(b"whatever") - # An unpinned version must not fail closed (it would break CI on every new - # CTK), but it must emit a warning. - assert verify_metadata_sha256(cuda_version="99.9.9", metadata_path=str(f)) == 0 + assert main(["verify-metadata", "--cuda-version", "99.9.9", "--metadata-path", str(f)]) == 1 + rc = main(["verify-metadata", "--cuda-version", "99.9.9", "--metadata-path", str(f), "--allow-unpinned"]) + assert rc == 0 assert "WARNING" in capsys.readouterr().err +@pytest.mark.agent_authored(model="claude-opus-5.5") +def test_known_redistrib_sha256_covers_ci_cuda_versions(): + # Every CUDA version CI fetches from the public server must be pinned, so a + # version bump fails here instead of in the fetch_ctk step. + versions = yaml.safe_load((CI_DIR / "versions.yml").read_text(encoding="utf-8")) + matrix = yaml.safe_load((CI_DIR / "test-matrix.yml").read_text(encoding="utf-8")) + required = {str(entry["version"]) for entry in versions["cuda"].values()} + required |= { + str(row["CUDA_VER"]) + for platform in ("linux", "windows") + for rows in matrix[platform].values() + for row in rows + if str(row.get("LOCAL_CTK")) == "1" + } + assert required + assert sorted(required - KNOWN_REDISTRIB_SHA256.keys()) == [] + for version, sha256 in KNOWN_REDISTRIB_SHA256.items(): + assert SHA256_RE.fullmatch(sha256), f"invalid pinned sha256 for CUDA {version}" + + @pytest.mark.agent_authored(model="claude-opus-4.8") def test_main_component_sha256(tmp_path, capsys): f = tmp_path / "redistrib.json" From baa5ab69a51587712deedd4113abb92ea4960c49 Mon Sep 17 00:00:00 2001 From: Ralf Juengling Date: Thu, 5 Nov 2026 15:34:30 -0800 Subject: [PATCH 3/4] CI: Drop the allow-unpinned escape hatch from fetch_ctk No caller sets it, and pinning a new CUDA version is a one-line addition to KNOWN_REDISTRIB_SHA256 that the error message points to. Remove the fetch_ctk input and the --allow-unpinned flag; fetch_ctk/action.yml is back to its main-branch form. --- .github/actions/fetch_ctk/action.yml | 15 +---------- ci/tools/fetch_ctk_redistrib.py | 29 +++++---------------- ci/tools/tests/test_fetch_ctk_redistrib.py | 30 ---------------------- 3 files changed, 8 insertions(+), 66 deletions(-) diff --git a/.github/actions/fetch_ctk/action.yml b/.github/actions/fetch_ctk/action.yml index 9931403f8b0..65b05a66acf 100644 --- a/.github/actions/fetch_ctk/action.yml +++ b/.github/actions/fetch_ctk/action.yml @@ -26,13 +26,6 @@ inputs: Override to install from an alternate redistrib server. required: false default: "https://developer.download.nvidia.com/compute/cuda/redist" - allow-unpinned: - description: > - Set to "true" to accept a public-server CUDA version whose manifest hash is - not pinned in ci/tools/fetch_ctk_redistrib.py (warn instead of fail). - A mismatch against an existing pin always fails. - required: false - default: "false" runs: using: composite @@ -70,16 +63,10 @@ runs: else METADATA_SOURCE=custom fi - case "${{ inputs.allow-unpinned }}" in - true) ALLOW_UNPINNED_FLAG=--allow-unpinned ;; - false) ALLOW_UNPINNED_FLAG= ;; - *) echo "ERROR: allow-unpinned must be 'true' or 'false'" >&2; exit 1 ;; - esac python "$CTK_REDIST_TOOL" verify-metadata \ --cuda-version "${{ inputs.cuda-version }}" \ --metadata-path "$CTK_JSON_FILE" \ - --metadata-source "$METADATA_SOURCE" \ - ${ALLOW_UNPINNED_FLAG} + --metadata-source "$METADATA_SOURCE" # Pre-process the component list to ensure hash uniqueness CTK_CACHE_COMPONENTS="$(python "$CTK_REDIST_TOOL" filter-components \ diff --git a/ci/tools/fetch_ctk_redistrib.py b/ci/tools/fetch_ctk_redistrib.py index a6ad3e4116e..6217dad42da 100644 --- a/ci/tools/fetch_ctk_redistrib.py +++ b/ci/tools/fetch_ctk_redistrib.py @@ -30,10 +30,10 @@ # Known-good sha256 of the redistrib metadata JSON, keyed by CUDA version. # Per-archive verification is only trustworthy if the JSON that carries the # archive hashes is itself trusted, so we pin the metadata too. `verify-metadata` -# fails on a public-server version that is absent here unless the caller opts -# out with `--allow-unpinned`. Add a version's hash below in the same change -# that adds it to ci/versions.yml or a LOCAL_CTK row of ci/test-matrix.yml; -# tests/test_fetch_ctk_redistrib.py enforces this. Regenerate with: +# fails on a public-server version that is absent here, so add a version's hash +# below in the same change that adds it to ci/versions.yml or a LOCAL_CTK row of +# ci/test-matrix.yml; tests/test_fetch_ctk_redistrib.py enforces this. +# Regenerate with: # curl -fsSL \ # https://developer.download.nvidia.com/compute/cuda/redist/redistrib_.json \ # | sha256sum @@ -148,9 +148,7 @@ def compute_file_sha256(path: str) -> str: return digest.hexdigest() -def verify_metadata_sha256( - *, cuda_version: str, metadata_path: str, metadata_source: str = "public", allow_unpinned: bool = False -) -> int: +def verify_metadata_sha256(*, cuda_version: str, metadata_path: str, metadata_source: str = "public") -> int: """Verify the redistrib JSON against the pinned hash for its CUDA version. The pins describe the public developer.download.nvidia.com manifests. A @@ -159,9 +157,7 @@ def verify_metadata_sha256( them; it only gets a warning. Returns a process exit code: 1 on a mismatch or an unpinned public version - (fail closed), 0 when the hash matches, the source is custom, or the version - is unpinned and ``allow_unpinned`` is set (warn only). ``allow_unpinned`` - never overrides a mismatch against an existing pin. + (fail closed), 0 when the hash matches or the source is custom (warn only). """ actual = compute_file_sha256(metadata_path) if metadata_source == "custom": @@ -173,17 +169,9 @@ def verify_metadata_sha256( return 0 expected = KNOWN_REDISTRIB_SHA256.get(cuda_version) if expected is None: - if allow_unpinned: - print( - f"WARNING: no pinned redistrib sha256 for CUDA {cuda_version!r}; got {actual}. " - "Continuing because unpinned versions are explicitly allowed.", - file=sys.stderr, - ) - return 0 print( f"ERROR: no pinned redistrib sha256 for CUDA {cuda_version!r}; got {actual}. " - f"Add it to KNOWN_REDISTRIB_SHA256 in {Path(__file__).name}, " - "or pass --allow-unpinned (fetch_ctk input allow-unpinned) to accept it unverified.", + f"Add it to KNOWN_REDISTRIB_SHA256 in {Path(__file__).name} to pin it.", file=sys.stderr, ) return 1 @@ -221,8 +209,6 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: verify_parser.add_argument("--cuda-version", required=True) verify_parser.add_argument("--metadata-path", required=True) verify_parser.add_argument("--metadata-source", choices=("public", "custom"), default="public") - verify_parser.add_argument("--allow-unpinned", action="store_true") - return parser.parse_args(argv) @@ -236,7 +222,6 @@ def main(argv: list[str] | None = None) -> int: cuda_version=args.cuda_version, metadata_path=args.metadata_path, metadata_source=args.metadata_source, - allow_unpinned=args.allow_unpinned, ) metadata = load_metadata(args.metadata_path) diff --git a/ci/tools/tests/test_fetch_ctk_redistrib.py b/ci/tools/tests/test_fetch_ctk_redistrib.py index 5a06c2c9c37..59a7cadfba9 100644 --- a/ci/tools/tests/test_fetch_ctk_redistrib.py +++ b/ci/tools/tests/test_fetch_ctk_redistrib.py @@ -115,36 +115,6 @@ def test_verify_metadata_unknown_version_fails_closed(tmp_path, capsys): assert "ERROR" in capsys.readouterr().err -@pytest.mark.agent_authored(model="claude-opus-5.5") -def test_verify_metadata_unknown_version_allowed_warns(tmp_path, capsys): - f = tmp_path / "redistrib.json" - f.write_bytes(b"whatever") - assert verify_metadata_sha256(cuda_version="99.9.9", metadata_path=str(f), allow_unpinned=True) == 0 - assert "WARNING" in capsys.readouterr().err - - -@pytest.mark.agent_authored(model="claude-opus-5.5") -def test_verify_metadata_allow_unpinned_does_not_bypass_mismatch(tmp_path, monkeypatch): - f = tmp_path / "redistrib.json" - f.write_bytes(b"tampered-metadata") - monkeypatch.setitem( - sys.modules["fetch_ctk_redistrib"].KNOWN_REDISTRIB_SHA256, - "1.2.3", - "f" * 64, - ) - assert verify_metadata_sha256(cuda_version="1.2.3", metadata_path=str(f), allow_unpinned=True) == 1 - - -@pytest.mark.agent_authored(model="claude-opus-5.5") -def test_main_verify_metadata_allow_unpinned_flag(tmp_path, capsys): - f = tmp_path / "redistrib.json" - f.write_bytes(b"whatever") - assert main(["verify-metadata", "--cuda-version", "99.9.9", "--metadata-path", str(f)]) == 1 - rc = main(["verify-metadata", "--cuda-version", "99.9.9", "--metadata-path", str(f), "--allow-unpinned"]) - assert rc == 0 - assert "WARNING" in capsys.readouterr().err - - @pytest.mark.agent_authored(model="claude-opus-5.5") def test_known_redistrib_sha256_covers_ci_cuda_versions(): # Every CUDA version CI fetches from the public server must be pinned, so a From bc927090690aade55899edf803009e8eb0b1bc56 Mon Sep 17 00:00:00 2001 From: Ralf Juengling Date: Thu, 5 Nov 2026 15:39:10 -0800 Subject: [PATCH 4/4] CI: Point CTK version bumps at the redistrib manifest pins Note in ci/versions.yml that each CUDA version there and in LOCAL_CTK matrix rows needs a pin in KNOWN_REDISTRIB_SHA256, and make the coverage test's failure message say where to add the pin and how to compute it. --- ci/tools/tests/test_fetch_ctk_redistrib.py | 7 ++++++- ci/versions.yml | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ci/tools/tests/test_fetch_ctk_redistrib.py b/ci/tools/tests/test_fetch_ctk_redistrib.py index 59a7cadfba9..03f9a29df50 100644 --- a/ci/tools/tests/test_fetch_ctk_redistrib.py +++ b/ci/tools/tests/test_fetch_ctk_redistrib.py @@ -130,7 +130,12 @@ def test_known_redistrib_sha256_covers_ci_cuda_versions(): if str(row.get("LOCAL_CTK")) == "1" } assert required - assert sorted(required - KNOWN_REDISTRIB_SHA256.keys()) == [] + missing = sorted(required - KNOWN_REDISTRIB_SHA256.keys()) + assert not missing, ( + f"CUDA versions used by CI have no pinned redistrib manifest hash: {missing}. " + "Add them to KNOWN_REDISTRIB_SHA256 in ci/tools/fetch_ctk_redistrib.py; compute each hash with " + "`curl -fsSL https://developer.download.nvidia.com/compute/cuda/redist/redistrib_.json | sha256sum`." + ) for version, sha256 in KNOWN_REDISTRIB_SHA256.items(): assert SHA256_RE.fullmatch(sha256), f"invalid pinned sha256 for CUDA {version}" diff --git a/ci/versions.yml b/ci/versions.yml index 2a48f83497c..de50338604d 100644 --- a/ci/versions.yml +++ b/ci/versions.yml @@ -6,6 +6,9 @@ backport_branch: "12.9.x" # keep in sync with target-branch in .github/dependab # This controls the version of the upstream CTK to install to build the wheels. # It is not the version of cuda_bindings/cuda_python being released, which is # solely determined by git tags via setuptools_scm. +# Each version here, and in every LOCAL_CTK: '1' row of ci/test-matrix.yml, +# needs a pinned manifest hash in KNOWN_REDISTRIB_SHA256 in +# ci/tools/fetch_ctk_redistrib.py; fetch_ctk fails without one. cuda: build: version: "13.5.0"