From e27a1a01bd972c600c80bfacaf8ca8bed54ab4c4 Mon Sep 17 00:00:00 2001 From: "Harlow, Jordan" Date: Mon, 27 Jul 2026 14:24:30 -0600 Subject: [PATCH 1/2] task: opensource coverity --- .github/workflows/coverity.yml | 131 +++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 .github/workflows/coverity.yml diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml new file mode 100644 index 0000000..247713e --- /dev/null +++ b/.github/workflows/coverity.yml @@ -0,0 +1,131 @@ +name: Coverity Scan + +# Public static analysis via the free Coverity Scan service (scan.coverity.com, +# operated by Black Duck). Coverity is a compiled-language analyzer: it must wrap +# the real C/C++ build with `cov-build`, so this workflow installs MKL, compiles +# the extension under capture, and uploads the result for analysis. +# +# One-time setup required before the first run (see the PR/commit notes): +# 1. Register IntelPython/mkl_random at https://scan.coverity.com/github +# (sign in with GitHub; the project name must match COVERITY_PROJECT below). +# 2. Add two repository secrets (Settings -> Secrets and variables -> Actions): +# COVERITY_SCAN_TOKEN - the project token from the Project Settings tab +# COVERITY_SCAN_EMAIL - a maintainer email for build notifications +# +# Free-tier quota for a project under 100K LOC (mkl_random is ~10K) is 28 +# builds/week, max 4/day. This scans every push to master; the concurrency +# group below cancels a superseded in-progress scan, so a burst of merges +# collapses toward a single upload and stays within quota. The weekly cron is +# a safety net for weeks with no commits to master. + +on: + push: + branches: [master] + schedule: + - cron: "0 1 * * 1" # weekly safety net; well under the free build quota + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: coverity-${{ github.ref }} + cancel-in-progress: true + +env: + COVERITY_PROJECT: IntelPython/mkl_random + ONEAPI_ROOT: /opt/intel/oneapi + +jobs: + coverity-scan: + # Forks lack the COVERITY_SCAN_* secrets; only run on the canonical repo. + if: github.repository == 'IntelPython/mkl_random' + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.12" + architecture: x64 + + - name: Install build dependencies + run: pip install cython "setuptools>=77" "numpy>=2" + + - name: Add Intel repository + run: | + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB + sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" + sudo apt-get update + + - name: Install Intel MKL + run: sudo apt-get install -y intel-oneapi-mkl-devel + + - name: Export MKLROOT + run: | + source "${ONEAPI_ROOT}/setvars.sh" + if [ -z "${MKLROOT:-}" ]; then + echo "::error::MKLROOT was not set after sourcing setvars.sh" + exit 1 + fi + echo "MKLROOT=${MKLROOT}" >> "$GITHUB_ENV" + echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> "$GITHUB_ENV" + + - name: Download Coverity Build Tool + env: + COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} + run: | + curl --location --no-progress-meter \ + --data-urlencode "token=${COVERITY_SCAN_TOKEN}" \ + --data-urlencode "project=${COVERITY_PROJECT}" \ + --output cov-analysis.tar.gz \ + https://scan.coverity.com/download/linux64 + # An invalid token/project returns a small HTML error page, not the + # multi-hundred-MB tarball. Fail loudly with a clear hint if so. + if [ "$(stat -c '%s' cov-analysis.tar.gz)" -lt 1000000 ]; then + echo "::error::Coverity build tool download failed. Verify the COVERITY_SCAN_TOKEN secret and that the registered project name matches '${COVERITY_PROJECT}'." + head -c 512 cov-analysis.tar.gz || true + exit 1 + fi + mkdir -p cov-analysis + tar -xzf cov-analysis.tar.gz --strip 1 -C cov-analysis + echo "${PWD}/cov-analysis/bin" >> "$GITHUB_PATH" + + - name: Configure Coverity for GCC/G++ + run: cov-configure --gcc + + - name: Build under cov-build + run: | + # Force a clean rebuild so g++ genuinely runs and Coverity can capture + # it. A stale .so or generated .cpp would skip compilation and yield + # "No files were emitted", which the upload rejects. + rm -rf build/ mkl_random/*.so mkl_random/mklrand.cpp + cov-build --dir cov-int pip install -e . --no-build-isolation --no-deps 2>&1 | tee cov-build.log + # The extension has 3 translation units (mklrand.cpp + the two src/*.cpp); + # bail out if none were captured. + if ! grep -qE "Emitted [1-9][0-9]* .*compilation unit" cov-build.log; then + echo "::error::Coverity captured 0 compilation units — the C++ build did not run under cov-build." + exit 1 + fi + + - name: Submit results to Coverity Scan + env: + COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} + COVERITY_SCAN_EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }} + run: | + tar -czf cov-int.tgz cov-int + curl --no-progress-meter \ + --form token="${COVERITY_SCAN_TOKEN}" \ + --form email="${COVERITY_SCAN_EMAIL}" \ + --form file=@cov-int.tgz \ + --form version="${GITHUB_SHA}" \ + --form description="GitHub Actions ${GITHUB_REF_NAME} (run ${GITHUB_RUN_ID})" \ + --form project="${COVERITY_PROJECT}" \ + https://scan.coverity.com/builds From 83c66dd4b00340de722b37d0e7ef3b1815b229f0 Mon Sep 17 00:00:00 2001 From: "Harlow, Jordan" Date: Tue, 28 Jul 2026 10:56:44 -0600 Subject: [PATCH 2/2] fix: review + badge --- .github/workflows/coverity.yml | 43 +++++++++++++++------------------- README.md | 1 + 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 247713e..a93cd81 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -13,16 +13,12 @@ name: Coverity Scan # COVERITY_SCAN_EMAIL - a maintainer email for build notifications # # Free-tier quota for a project under 100K LOC (mkl_random is ~10K) is 28 -# builds/week, max 4/day. This scans every push to master; the concurrency -# group below cancels a superseded in-progress scan, so a burst of merges -# collapses toward a single upload and stays within quota. The weekly cron is -# a safety net for weeks with no commits to master. +# builds/week, max 4/day, so this runs on a weekly schedule plus on demand +# rather than per-push. on: - push: - branches: [master] schedule: - - cron: "0 1 * * 1" # weekly safety net; well under the free build quota + - cron: "0 1 * * 1" # Mondays 01:00 UTC; well under the free build quota workflow_dispatch: permissions: @@ -34,7 +30,6 @@ concurrency: env: COVERITY_PROJECT: IntelPython/mkl_random - ONEAPI_ROOT: /opt/intel/oneapi jobs: coverity-scan: @@ -55,28 +50,28 @@ jobs: architecture: x64 - name: Install build dependencies - run: pip install cython "setuptools>=77" "numpy>=2" - - - name: Add Intel repository - run: | - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB - sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main" - sudo apt-get update - - - name: Install Intel MKL - run: sudo apt-get install -y intel-oneapi-mkl-devel + run: pip install cython "setuptools>=77" "numpy>=2" mkl-devel - name: Export MKLROOT run: | - source "${ONEAPI_ROOT}/setvars.sh" - if [ -z "${MKLROOT:-}" ]; then - echo "::error::MKLROOT was not set after sourcing setvars.sh" + # mkl-devel installs mkl.h + libmkl_rt into the Python prefix. + MKLROOT="$(python -c 'import sys; print(sys.prefix)')" + if [ ! -f "${MKLROOT}/include/mkl.h" ]; then + echo "::error::mkl.h not found under ${MKLROOT}; mkl-devel did not install as expected." exit 1 fi + # The wheel ships only the versioned libmkl_rt.so.3, not the bare + # linker name, so `g++ -lmkl_rt` fails until we add the symlink. + if [ ! -e "${MKLROOT}/lib/libmkl_rt.so" ]; then + rt_so=("${MKLROOT}/lib/"libmkl_rt.so.*) + if [ ! -e "${rt_so[0]}" ]; then + echo "::error::libmkl_rt.so.* not found under ${MKLROOT}/lib." + exit 1 + fi + ln -s "${rt_so[0]}" "${MKLROOT}/lib/libmkl_rt.so" + fi echo "MKLROOT=${MKLROOT}" >> "$GITHUB_ENV" - echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> "$GITHUB_ENV" + echo "LD_LIBRARY_PATH=${MKLROOT}/lib:${LD_LIBRARY_PATH}" >> "$GITHUB_ENV" - name: Download Coverity Build Tool env: diff --git a/README.md b/README.md index b58ae37..f820d03 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ ## `mkl_random` -- a NumPy-based Python interface to Intel® oneAPI Math Kernel Library (OneMKL) Random Number Generation functionality [![Conda package using conda-forge](https://github.com/IntelPython/mkl_random/actions/workflows/conda-package-cf.yml/badge.svg)](https://github.com/IntelPython/mkl_random/actions/workflows/conda-package-cf.yml) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/33198/badge.svg)](https://scan.coverity.com/projects/intelpython-mkl_random) `mkl_random` started as a part of Intel® Distribution for Python optimizations to NumPy.