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
85 changes: 65 additions & 20 deletions .github/actions/fetch_ctk/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,76 @@ inputs:
description: "where the CTK components will be installed to, relative to $PWD"
required: false
default: "./cuda_toolkit"
redist-base-url:
description: >
Base URL of a redistrib server (manifest and component archives).
Defaults to the public NVIDIA developer server.
Override to install from an alternate redistrib server.
required: false
default: "https://developer.download.nvidia.com/compute/cuda/redist"

runs:
using: composite
steps:
- name: Install Unix dependencies
if: ${{ runner.os == 'Linux' }}
uses: ./.github/actions/install_unix_deps
with:
dependencies: "zstd curl xz-utils"
dependent_exes: "zstd curl xz"

- name: Install Windows dependencies
if: ${{ runner.os == 'Windows' }}
uses: ./.github/actions/install_windows_deps
with:
dependent_exes: "curl unzip tar sha256sum cygpath"

- name: Set up CTK cache variable
shell: bash --noprofile --norc -xeuo pipefail {0}
run: |
# Pre-process the component list to ensure hash uniqueness
# Use the runtime workspace mount so this also works inside container jobs.
CTK_REDIST_TOOL="${GITHUB_WORKSPACE}/ci/tools/fetch_ctk_redistrib.py"
CTK_CACHE_COMPONENTS=${{ inputs.cuda-components }}
CTK_JSON_URL="https://developer.download.nvidia.com/compute/cuda/redist/redistrib_${{ inputs.cuda-version }}.json"
CTK_BASE_URL="${{ inputs.redist-base-url }}"
# A trailing slash would defeat the public-server comparison below and double up in URLs.
CTK_BASE_URL="${CTK_BASE_URL%/}"
# RUNNER_TEMP persists across steps, so "Get CUDA components" reuses this file.
CTK_JSON_FILE="$RUNNER_TEMP/redistrib-${{ inputs.cuda-version }}.json"
curl -LSs --fail --retry 3 --retry-delay 2 "${CTK_BASE_URL}/redistrib_${{ inputs.cuda-version }}.json" -o "$CTK_JSON_FILE"

# Pin the metadata JSON: the per-archive sha256 checks below are only
# trustworthy if the JSON that carries those hashes is itself trusted.
# The pins describe the public server; alternate servers only warn.
if [[ "$CTK_BASE_URL" == "https://developer.download.nvidia.com/compute/cuda/redist" ]]; then
METADATA_SOURCE=public
else
METADATA_SOURCE=custom
fi
python "$CTK_REDIST_TOOL" verify-metadata \
--cuda-version "${{ inputs.cuda-version }}" \
--metadata-path "$CTK_JSON_FILE" \
--metadata-source "$METADATA_SOURCE"

# Pre-process the component list to ensure hash uniqueness
CTK_CACHE_COMPONENTS="$(python "$CTK_REDIST_TOOL" filter-components \
--host-platform "${{ inputs.host-platform }}" \
--cuda-version "${{ inputs.cuda-version }}" \
--components "$CTK_CACHE_COMPONENTS" \
--metadata-url "$CTK_JSON_URL")"
--components "${{ inputs.cuda-components }}" \
--metadata-path "$CTK_JSON_FILE")"

# Alternate redist servers (non-default) publish different manifests for the
# same CUDA version; keying on the full manifest hash keeps them from restoring
# each other's toolkit (a truncated hash could be collided on purpose).
# Hash via stdin: with a backslash in the path (Windows RUNNER_TEMP), sha256sum
# prefixes its output line with "\", which would end up in the cache key.
MANIFEST_SHA256="$(sha256sum < "$CTK_JSON_FILE" | awk '{print $1}')"
HASH=$(echo -n "${CTK_CACHE_COMPONENTS}" | sha256sum | awk '{print $1}')
echo "CTK_CACHE_KEY=mini-ctk-${{ inputs.cuda-version }}-${{ inputs.host-platform }}-$HASH" >> $GITHUB_ENV
echo "CTK_CACHE_FILENAME=mini-ctk-${{ inputs.cuda-version }}-${{ inputs.host-platform }}-$HASH.tar.gz" >> $GITHUB_ENV
echo "CTK_CACHE_COMPONENTS=${CTK_CACHE_COMPONENTS}" >> $GITHUB_ENV

- name: Install dependencies
uses: ./.github/actions/install_unix_deps
continue-on-error: false
with:
dependencies: "zstd curl xz-utils"
dependent_exes: "zstd curl xz"
{
echo "CTK_CACHE_KEY=mini-ctk-${{ inputs.cuda-version }}-${{ inputs.host-platform }}-$HASH-m$MANIFEST_SHA256"
echo "CTK_CACHE_FILENAME=mini-ctk-${{ inputs.cuda-version }}-${{ inputs.host-platform }}-$HASH-m$MANIFEST_SHA256.tar.gz"
echo "CTK_CACHE_COMPONENTS=${CTK_CACHE_COMPONENTS}"
echo "CTK_BASE_URL=${CTK_BASE_URL}"
echo "CTK_JSON_FILE=${CTK_JSON_FILE}"
} >> "$GITHUB_ENV"

- name: Download CTK cache
id: ctk-get-cache
Expand All @@ -68,13 +109,10 @@ runs:
rm -rf $CACHE_TMP_DIR
mkdir $CACHE_TMP_DIR

# The binary archives (redist) are guaranteed to be updated as part of the release posting.
# Use the runtime workspace mount so this also works inside container jobs.
CTK_REDIST_TOOL="${GITHUB_WORKSPACE}/ci/tools/fetch_ctk_redistrib.py"
CTK_BASE_URL="https://developer.download.nvidia.com/compute/cuda/redist/"
CTK_JSON_URL="$CTK_BASE_URL/redistrib_${{ inputs.cuda-version }}.json"
CTK_JSON_FILE="$CACHE_TMP_DIR/redistrib.json"
curl -LSs "$CTK_JSON_URL" -o "$CTK_JSON_FILE"
# CTK_BASE_URL and the verified manifest at CTK_JSON_FILE come from
# "Set up CTK cache variable".
if [[ "${{ inputs.host-platform }}" == linux* ]]; then
function extract() {
tar -xvf $1 -C $CACHE_TMP_DIR --strip-components=1
Expand Down Expand Up @@ -102,6 +140,13 @@ runs:
CTK_COMPONENT_URL="${CTK_BASE_URL}/${CTK_COMPONENT_REL_PATH}"
CTK_COMPONENT_COMPONENT_FILENAME="$(basename $CTK_COMPONENT_REL_PATH)"
download $CTK_COMPONENT_URL $CTK_COMPONENT_COMPONENT_FILENAME
# Verify the downloaded archive against the sha256 in the (pinned)
# metadata before extracting; fail closed on any mismatch.
CTK_COMPONENT_SHA256="$(python "$CTK_REDIST_TOOL" component-sha256 \
--host-platform "${{ inputs.host-platform }}" \
--component "$CTK_COMPONENT" \
--metadata-path "$CTK_JSON_FILE")"
echo "${CTK_COMPONENT_SHA256} ${CTK_COMPONENT_COMPONENT_FILENAME}" | sha256sum --check --strict -
extract $CTK_COMPONENT_COMPONENT_FILENAME
rm $CTK_COMPONENT_COMPONENT_FILENAME
}
Expand Down
92 changes: 92 additions & 0 deletions .github/actions/install_windows_deps/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: Install dependencies on Windows

description: Install Git Bash tools from a verified portable Git bundle when required executables are missing.

inputs:
dependent_exes:
description: Space-separated executable names provided by Git for Windows
required: true

runs:
using: composite
steps:
- name: Install dependencies
shell: powershell
env:
DEPENDENT_EXES: ${{ inputs.dependent_exes }}
run: |
$ErrorActionPreference = 'Stop'
if ($env:DEPENDENT_EXES -notmatch '^\s*[a-zA-Z0-9_.-]+(\s+[a-zA-Z0-9_.-]+)*\s*$') {
throw 'Expected a space-separated list of executable names.'
}
# Fail the check if the list did not reach Bash (a WSL bash would not receive it).
# Keep double quotes out of $check: Windows PowerShell 5.1 strips them when
# passing arguments to native commands. The names are validated above.
$check = 'missing=0; set -- $DEPENDENT_EXES; [ $# -gt 0 ] || missing=1; for tool in $DEPENDENT_EXES; do command -v $tool || missing=1; done; exit $missing'
# Skip the WSL launcher in System32/WindowsApps: it is not a Git for Windows bash.
$bash = Get-Command bash -All -ErrorAction SilentlyContinue |
Where-Object { $_.Source -notmatch '\\(System32|SysWOW64|WindowsApps)\\' } |
Select-Object -First 1
Comment thread
juenglin marked this conversation as resolved.
Resolved
if ($bash) {
& $bash.Source --noprofile --norc -c $check
if ($LASTEXITCODE -eq 0) {
# Later `shell: bash` steps resolve `bash` through PATH. If that is not the
# Git Bash validated above (e.g. the WSL launcher comes first), put it first.
$pathBash = Get-Command bash -ErrorAction SilentlyContinue
if ($pathBash -and ($pathBash.Source -ne $bash.Source)) {
$bashDir = Split-Path -Parent $bash.Source
$env:PATH = "$bashDir;$env:PATH"
$bashDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
Write-Host "Prepended $bashDir to PATH so steps use Git Bash instead of $($pathBash.Source)."
}
Write-Host 'All dependencies are found. Do nothing.'
exit 0
}
}

$architecture = [Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()
switch ($architecture) {
'Arm64' {
$package = 'arm64'
$expectedHash = '3bf26b94d9399b16a890776e468334f501742861576cbcdea2d9134643c374bd'
}
'X64' {
$package = '64-bit'
$expectedHash = 'ab00566336b5472120f9a52d34f2e79c5406535792acb0548001ffd0bd090e5d'
}
default { throw "Unsupported Windows architecture: $architecture" }
}
$root = Join-Path $env:RUNNER_TOOL_CACHE "WindowsDeps\Git-2.55.0.3-$package"
$complete = "$root.complete"
if (-not (Test-Path -LiteralPath $complete)) {
$archive = Join-Path $env:RUNNER_TEMP "PortableGit-2.55.0.3-$package.7z.exe"
try {
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/git-for-windows/git/releases/download/v2.55.0.windows.3/PortableGit-2.55.0.3-$package.7z.exe" -OutFile $archive
$actualHash = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actualHash -ne $expectedHash) {
throw "Portable Git checksum mismatch: expected $expectedHash, got $actualHash."
}
if (Test-Path -LiteralPath $root) {
Remove-Item -LiteralPath $root -Recurse -Force
}
$process = Start-Process -FilePath $archive -ArgumentList @('-y', ('-o"{0}"' -f $root)) -Wait -PassThru
if ($process.ExitCode -ne 0) {
throw "Portable Git extraction failed with exit code $($process.ExitCode)."
}
}
finally {
if (Test-Path -LiteralPath $archive) {
Remove-Item -LiteralPath $archive -Force
}
}
}
$env:PATH = "$root\bin;$root\usr\bin;$env:PATH"
& "$root\bin\bash.exe" --noprofile --norc -c $check
if ($LASTEXITCODE -ne 0) {
throw 'Required executables are still missing after installing portable Git.'
}
New-Item -ItemType File -Force -Path $complete | Out-Null
@("$root\bin", "$root\usr\bin") | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
Loading
Loading