From 1bd3b7d47d798c47a12e6ed882476214e859c474 Mon Sep 17 00:00:00 2001 From: gmanal Date: Tue, 3 Nov 2026 16:34:10 +0530 Subject: [PATCH 1/3] ci: enable the Pulse vulnerability and malware scans in the Security Suite Turns on enable-vuln-scan and enable-malware-scan and moves every security-workflows pin -- the reusable suite and the secret-scan pre-commit hook -- to the v0.5.0 release commit, the first release carrying either workflow. The vulnerability scan starts report-only so a finding baseline can be built before it gates merges; scanner and transport errors still fail the job, and inventory writeback stays off. The malware scan keeps the upstream default of strict, where SUSPICIOUS blocks as well as MALICIOUS. On main the vulnerability scan inspects installed wheels, because Detect cannot resolve cuda_core's CUDA-dependent build or cuda_python's dynamic setup.py from source; two new jobs build and collect them. Wheel mode is refused on pull-request/* mirrors, which instead scan source with those two packages excluded. Both scans report to the same nSpect registration, because an nSpect ID identifies the repository rather than one scan. nspect-id reads the NSPECT_ID Actions variable -- a reusable workflow's inputs cannot read secrets -- and an empty value fails the suite preflight rather than reporting to the wrong program. No permission change: the suite's union is contents/actions read plus id-token and security-events write, all of which this caller already grants. Both scans cross a Charon tunnel that authorizes per repository and per ref; the prerequisites are summarised in ci/README.md. --- .github/workflows/security-suite.yml | 83 ++++++++++++++++++++++++++-- .pre-commit-config.yaml | 2 +- ci/README.md | 15 +++++ 3 files changed, 94 insertions(+), 6 deletions(-) diff --git a/.github/workflows/security-suite.yml b/.github/workflows/security-suite.yml index 64eb4846483..c61b69c2aa3 100644 --- a/.github/workflows/security-suite.yml +++ b/.github/workflows/security-suite.yml @@ -2,10 +2,12 @@ # # SPDX-License-Identifier: Apache-2.0 # -# CI security scanning via the NVIDIA/security-workflows suite: Pulse secret scan + CodeQL SAST. +# CI security scanning via the NVIDIA/security-workflows suite: Pulse secret scan, +# Pulse OSS vulnerability scan (SCA), Pulse malware scan, and CodeQL SAST. # Pulse runs on Linux nv-gha-runners (Docker image + OIDC/Vault) — Linux-only by design. # The local secret-scan-trufflehog pre-commit hook is cross-platform (Linux/macOS/Windows). -# Pinned to a reviewed commit SHA. +# Pinned by commit SHA to the security-workflows v0.5.0 release. +# The vulnerability and malware scans cross a Charon tunnel; see ci/README.md. name: Security Suite (Pulse + CodeQL) @@ -29,16 +31,71 @@ permissions: actions: read jobs: + # On main the vulnerability scan inspects installed wheels: Detect cannot resolve + # cuda_core's CUDA-dependent build or cuda_python's dynamic setup.py from source. + # Wheel mode is refused on pull-request/* mirrors. Python 3.12 matches the scanner image. + build-wheels: + name: Build wheels for the vulnerability scan + if: >- + github.ref == 'refs/heads/main' && + (github.repository == 'NVIDIA/cuda-python' || + vars.CI_CUSTOMIZATIONS_SECURITY_SUITE_ENABLED == 'true') + permissions: + actions: read + contents: read + secrets: inherit + uses: ./.github/workflows/build-wheel.yml + with: + host-platform: linux-64 + cuda-version: "13.4.2" + prev-cuda-version: "12.9.1" + single-cuda-major: true + python-versions: '["3.12"]' + + # The scan installs offline, so the artifact carries every runtime dependency wheel too. + python-wheels: + name: Collect runtime wheels for the vulnerability scan + needs: build-wheels + runs-on: linux-amd64-cpu8 + permissions: + contents: read + steps: + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + pattern: cuda-* + path: built + merge-multiple: true + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.12" + - name: Add runtime dependency wheels + run: | + set -euo pipefail + mkdir wheelhouse + cp built/*.whl wheelhouse/ + python -m pip download --only-binary=:all: --dest wheelhouse wheelhouse/*.whl + ls wheelhouse + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: python-wheels + path: wheelhouse/*.whl + if-no-files-found: error + security-suite: name: Security Suite + needs: python-wheels # Repository-specific workflow opt-ins use CI_CUSTOMIZATIONS_* Actions variables; # see ci/README.md. Enable this only after the security-suite prerequisites exist. if: >- - github.repository == 'NVIDIA/cuda-python' || - vars.CI_CUSTOMIZATIONS_SECURITY_SUITE_ENABLED == 'true' - uses: NVIDIA/security-workflows/.github/workflows/security-suite.yml@c736f0454dc99764a66af6b906adfcdfbf621985 # v0.4.0 + !cancelled() && + (needs.python-wheels.result == 'success' || github.ref != 'refs/heads/main') && + (github.repository == 'NVIDIA/cuda-python' || + vars.CI_CUSTOMIZATIONS_SECURITY_SUITE_ENABLED == 'true') + uses: NVIDIA/security-workflows/.github/workflows/security-suite.yml@0659a2e36defdf66209a135d216f40a63b7aec94 # v0.5.0 with: enable-secret-scan: true + enable-vuln-scan: true + enable-malware-scan: true enable-sast-scan: true secret-runs-on: linux-amd64-cpu4 # Set failure_policy explicitly so enforcement can't drift with upstream defaults. @@ -48,3 +105,19 @@ jobs: secret-failure-policy: unverified # Same analysis the retired codeql.yml performed: python, build-mode none, security-extended. sast-languages: '["python"]' + # NSPECT_ID must be an Actions *variable*: a reusable workflow's inputs cannot read secrets. + # Empty fails the suite preflight rather than reporting to the wrong nSpect program. + nspect-id: ${{ vars.NSPECT_ID }} + vuln-runs-on: linux-amd64-cpu4 + vuln-python-wheels-artifact: ${{ github.ref == 'refs/heads/main' && 'python-wheels' || '' }} + vuln-python-project: ${{ github.ref == 'refs/heads/main' && 'cuda-python' || '' }} + # Pull-request mirrors scan source, minus the two packages Detect cannot resolve from it. + vuln-detect-properties: >- + ${{ github.ref == 'refs/heads/main' && '{}' || + '{"detect.excluded.directories": "cuda_core,cuda_python"}' }} + # report-only (default) — findings warn; fail-on-vulnerability — any finding fails. Errors always fail. + vuln-failure-policy: report-only + vuln-upload-report: true + malware-runs-on: linux-amd64-cpu4 + # strict (default) — SUSPICIOUS fails too; malicious-only — it only warns. MALICIOUS always fails. + malware-failure-policy: strict diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 86bd18bed93..9d4c6ad4dc4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: # Self-installing: the hook downloads a pinned, checksum-verified trufflehog on # first use (no manual install). Skipped on pre-commit.ci; Pulse CI enforces server-side. - repo: https://github.com/NVIDIA/security-workflows - rev: c736f0454dc99764a66af6b906adfcdfbf621985 # frozen: v0.4.0 + rev: 0659a2e36defdf66209a135d216f40a63b7aec94 # frozen: v0.5.0 hooks: - id: secret-scan-trufflehog diff --git a/ci/README.md b/ci/README.md index 2fcd5b4ab1d..aa635a43614 100644 --- a/ci/README.md +++ b/ci/README.md @@ -232,3 +232,18 @@ The canonical `NVIDIA/cuda-python` repository does not need this variable because its standard workflow behavior is enabled directly. Before enabling a customization elsewhere, document the repository-specific prerequisites and verification procedure in that repository's own documentation. + +### Security Suite scan prerequisites + +The secret scan and CodeQL SAST need only the Vault variables already +provisioned for this repository. The Pulse OSS vulnerability scan and the Pulse +malware scan additionally reach NVIDIA-internal services through a Charon +tunnel, which authorizes **per repository and per ref**, and both read the +repository's `NSPECT_ID` Actions variable. + +The Charon tenant must list every ref the suite scans — `main`, `ctk-next`, and +the `pull-request/*` mirrors — and grant the routes each scan calls, including +`POST /v1/sourceCode/scan`, which is not granted to tenants by default. An +unlisted ref or route surfaces as an opaque `403` from inside the scanner, so +confirm the tenant before debugging anything else. The secret scan and SAST are +unaffected; neither crosses the tunnel. From aff64b7bb1a68eb372f59e4204b0d547557e8629 Mon Sep 17 00:00:00 2001 From: gmanal Date: Tue, 3 Nov 2026 17:30:54 +0530 Subject: [PATCH 2/3] ci: name all Security Suite scans and limit Charon scans to authorized refs --- .github/workflows/security-suite.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/security-suite.yml b/.github/workflows/security-suite.yml index c61b69c2aa3..a9c76b6d05c 100644 --- a/.github/workflows/security-suite.yml +++ b/.github/workflows/security-suite.yml @@ -9,7 +9,7 @@ # Pinned by commit SHA to the security-workflows v0.5.0 release. # The vulnerability and malware scans cross a Charon tunnel; see ci/README.md. -name: Security Suite (Pulse + CodeQL) +name: Security Suite (Secret, Vulnerability, Malware, SAST) on: push: @@ -94,8 +94,9 @@ jobs: uses: NVIDIA/security-workflows/.github/workflows/security-suite.yml@0659a2e36defdf66209a135d216f40a63b7aec94 # v0.5.0 with: enable-secret-scan: true - enable-vuln-scan: true - enable-malware-scan: true + # The vulnerability and malware scans use a Charon tenant that authorizes only these refs. + enable-vuln-scan: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/pull-request/') }} + enable-malware-scan: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/pull-request/') }} enable-sast-scan: true secret-runs-on: linux-amd64-cpu4 # Set failure_policy explicitly so enforcement can't drift with upstream defaults. From e359e0d7679d3d866cd94b8c5ba2287c6dc39c2d Mon Sep 17 00:00:00 2001 From: gmanal Date: Tue, 3 Nov 2026 19:07:16 +0530 Subject: [PATCH 3/3] ci: add the GuardWords pre-commit hook --- .pre-commit-config.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9d4c6ad4dc4..47aebb828a4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ ci: autoupdate_branch: '' autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate' autoupdate_schedule: quarterly - skip: [lychee, check-precommit-installed, secret-scan-trufflehog] + skip: [lychee, check-precommit-installed, secret-scan-trufflehog, guardwords-scan-code-scanning] submodules: false # Please update the rev: SHAs below with this command: @@ -18,10 +18,12 @@ repos: # Runs first so a leaked credential blocks the commit before any formatter runs. # Self-installing: the hook downloads a pinned, checksum-verified trufflehog on # first use (no manual install). Skipped on pre-commit.ci; Pulse CI enforces server-side. + # GuardWords needs NVIDIA's internal client and network; it skips with a notice elsewhere. - repo: https://github.com/NVIDIA/security-workflows rev: 0659a2e36defdf66209a135d216f40a63b7aec94 # frozen: v0.5.0 hooks: - id: secret-scan-trufflehog + - id: guardwords-scan-code-scanning - repo: https://github.com/astral-sh/ruff-pre-commit rev: f368fb366ff7f2f808dd324b83a6d32267799e19 # frozen: v0.17.2