diff --git a/.github/workflows/security-suite.yml b/.github/workflows/security-suite.yml index 64eb4846483..a9c76b6d05c 100644 --- a/.github/workflows/security-suite.yml +++ b/.github/workflows/security-suite.yml @@ -2,12 +2,14 @@ # # 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) +name: Security Suite (Secret, Vulnerability, Malware, SAST) on: push: @@ -29,16 +31,72 @@ 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 + # 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. @@ -48,3 +106,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..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: c736f0454dc99764a66af6b906adfcdfbf621985 # frozen: v0.4.0 + 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 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.