From de756315ec43bdca54599a7d0ba772fa7fbf7cf6 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 5 Jun 2026 07:27:50 +0000 Subject: Add pvs skill to run PVS-Studio analysis for a board Bundle a run_pvs.sh helper (takes BOARD as its first argument) that follows the PVS-Studio static-analysis flow from AGENTS.md: build all examples with an exported compile_commands.json, run pvs-studio-analyzer against .PVS-Studio/.pvsconfig, then emit errorfile + SARIF reports. https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX --- .claude/skills/pvs/SKILL.md | 74 ++++++++++++++++++++++++++++++++++++++ .claude/skills/pvs/run_pvs.sh | 82 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 .claude/skills/pvs/SKILL.md create mode 100755 .claude/skills/pvs/run_pvs.sh diff --git a/.claude/skills/pvs/SKILL.md b/.claude/skills/pvs/SKILL.md new file mode 100644 index 000000000..cde453d9a --- /dev/null +++ b/.claude/skills/pvs/SKILL.md @@ -0,0 +1,74 @@ +--- +name: pvs +description: Use when running PVS-Studio static analysis (SAST + MISRA C:2023 / C++:2008) on TinyUSB for a given board. Wraps building the examples with an exported compile_commands.json and running pvs-studio-analyzer against .PVS-Studio/.pvsconfig, then converts the log to readable + SARIF output. +--- + +# PVS-Studio Static Analysis + +Run PVS-Studio on TinyUSB for one board. The skill bundles `run_pvs.sh`, which +follows the "Static Analysis (PVS-Studio)" section of AGENTS.md / CLAUDE.md: +build all examples for the board with `compile_commands.json` exported, run +`pvs-studio-analyzer` against it using `.PVS-Studio/.pvsconfig`, then convert the +log to an `errorfile` view and a SARIF report. + +## Quick start + +```bash +# Whole project for a board: +.claude/skills/pvs/run_pvs.sh raspberry_pi_pico + +# Specific files only — -S takes a plaintext list (one path per line), NOT a +# source file directly (the AGENTS.md "-S src/foo.c" snippet is inaccurate): +printf 'src/tusb.c\nsrc/class/cdc/cdc_device.c\n' > /tmp/files.txt +.claude/skills/pvs/run_pvs.sh stm32f407disco -S /tmp/files.txt +``` + +The first positional argument is **BOARD** (required). Everything after it is +forwarded verbatim to `pvs-studio-analyzer analyze`. + +## What the script does + +1. **License** — if no license file is registered, materializes one from the + `PVS_STUDIO_CREDENTIALS` env var (` `, same secret CI uses). +2. **Build** — `cmake examples -B examples/cmake-build- -G Ninja + -DBOARD= -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_EXPORT_COMPILE_COMMANDS=ON` + then `cmake --build`. The exported `compile_commands.json` is what PVS reads. +3. **Analyze** — `pvs-studio-analyzer analyze -f + -R .PVS-Studio/.pvsconfig -o pvs-.log -j + --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser`. + (AGENTS.md shows `--dump-files`; it's omitted because it scatters + `.PVS-Studio.i/.cfg` dumps across the tree — only useful for debugging FPs.) +4. **Report** — `plog-converter -a GA:1,2 -t errorfile` (printed) and + `-t sarif` → `pvs-.sarif`. + +`.PVS-Studio/.pvsconfig` already excludes vendored code (`lib/`, `hw/mcu/`, +`pico-sdk/`, `esp-idf/`, IAR runtime) and suppresses the project's accepted +MISRA deviations — don't duplicate those excludes on the command line. + +## Choosing a board + +Match the build prerequisites (same as the rest of the repo): + +- `raspberry_pi_pico` — what CI's PVS-Studio job uses (needs Pico SDK deps). +- `stm32f407disco` — no external SDK; fastest to get a clean compile DB. +- Anything under `hw/bsp//boards/` works if its deps are fetched + (`python3 tools/get_deps.py -b `). + +## Outputs + +- `pvs-.log` — raw analyzer log (input to plog-converter). +- `pvs-.sarif` — SARIF report (same format CI uploads). +- errorfile findings are printed to stdout for a quick read. + +## Timing + +Dominated by the example build (tens of seconds to a few minutes depending on +board/deps). The analysis pass itself is ~10-30 s. Use a timeout ≥ 10 minutes +for boards whose deps must be fetched/built first. + +## Reporting results + +After a run, summarize the findings by rule/severity from the errorfile output +and point the user at `pvs-.sarif`. Cross-check anything flagged in +`src/` against `.pvsconfig` — if it's an already-accepted deviation it will have +been suppressed, so surviving findings are genuinely new. diff --git a/.claude/skills/pvs/run_pvs.sh b/.claude/skills/pvs/run_pvs.sh new file mode 100755 index 000000000..3a829327d --- /dev/null +++ b/.claude/skills/pvs/run_pvs.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# Run PVS-Studio static analysis on TinyUSB for a given BOARD. +# +# Mirrors the "Static Analysis (PVS-Studio)" section in AGENTS.md / CLAUDE.md: +# - build all examples for BOARD with compile_commands.json exported +# - run pvs-studio-analyzer against that compile DB using .PVS-Studio/.pvsconfig +# - convert the log to human-readable (errorfile) and SARIF output +# +# Usage: +# .claude/skills/pvs/run_pvs.sh [extra pvs-studio-analyzer args...] +# +# Examples: +# .claude/skills/pvs/run_pvs.sh raspberry_pi_pico +# # Scope to specific files via a plaintext list (one path per line): +# printf 'src/tusb.c\nsrc/class/cdc/cdc_device.c\n' > /tmp/files.txt +# .claude/skills/pvs/run_pvs.sh stm32f407disco -S /tmp/files.txt +set -euo pipefail + +BOARD="${1:-}" +if [ -z "$BOARD" ]; then + echo "Usage: $0 [extra pvs-studio-analyzer args...]" >&2 + echo "Example: $0 raspberry_pi_pico" >&2 + exit 2 +fi +shift + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +cd "$REPO_ROOT" + +BUILD_DIR="examples/cmake-build-${BOARD}" +COMPILE_DB="${BUILD_DIR}/compile_commands.json" +REPORT_LOG="pvs-${BOARD}.log" +SARIF_OUT="pvs-${BOARD}.sarif" +JOBS="$(nproc 2>/dev/null || echo 4)" + +# --- License --------------------------------------------------------------- +# Use an existing license file, else materialize one from PVS_STUDIO_CREDENTIALS +# (format: " ", as supplied by the CI secret of the same name). +if ! pvs-studio-analyzer lic-info >/dev/null 2>&1; then + if [ -n "${PVS_STUDIO_CREDENTIALS:-}" ]; then + echo ">>> Registering PVS-Studio license from PVS_STUDIO_CREDENTIALS" + # shellcheck disable=SC2086 # credentials expects two whitespace-separated args + pvs-studio-analyzer credentials $PVS_STUDIO_CREDENTIALS + else + echo "ERROR: no PVS-Studio license found and PVS_STUDIO_CREDENTIALS is unset." >&2 + exit 1 + fi +fi + +# --- Build (exports compile_commands.json) --------------------------------- +echo ">>> Building all examples for ${BOARD} (this also fetches the compile DB)" +cmake examples -B "${BUILD_DIR}" -G Ninja \ + -DBOARD="${BOARD}" \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON +cmake --build "${BUILD_DIR}" + +if [ ! -f "${COMPILE_DB}" ]; then + echo "ERROR: ${COMPILE_DB} was not produced by the build." >&2 + exit 1 +fi + +# --- Analyze --------------------------------------------------------------- +echo ">>> Running PVS-Studio analyzer (-j${JOBS})" +# Note: AGENTS.md shows --dump-files, but that scatters .PVS-Studio.i/.cfg dump +# files across the source tree (only useful for debugging false positives). It is +# omitted here to keep the working tree clean; add it back via "$@" if needed. +pvs-studio-analyzer analyze \ + -f "${COMPILE_DB}" \ + -R .PVS-Studio/.pvsconfig \ + -o "${REPORT_LOG}" -j"${JOBS}" \ + --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser \ + "$@" + +# --- Report ---------------------------------------------------------------- +echo ">>> General-analysis + MISRA findings (errorfile):" +plog-converter -a GA:1,2 -t errorfile "${REPORT_LOG}" || true +plog-converter -t sarif -o "${SARIF_OUT}" "${REPORT_LOG}" >/dev/null + +echo ">>> Done." +echo " Raw log : ${REPORT_LOG}" +echo " SARIF : ${SARIF_OUT}" -- cgit v1.3.1 From c3b4ef03aa26f29d5ab28313130b677c1ea00c51 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 5 Jun 2026 07:30:23 +0000 Subject: Compact pvs skill; fix PVS-Studio -S/--dump-files docs in AGENTS.md The AGENTS.md '-S src/foo.c' example was inaccurate: -S takes a plaintext file listing source paths, not paths directly. Drop --dump-files from the documented commands (it scatters .PVS-Studio.i/.cfg dumps across the tree; FP-debugging only) and reference the new pvs skill. https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX --- .claude/skills/pvs/SKILL.md | 84 +++++++++++++-------------------------------- AGENTS.md | 16 +++++---- 2 files changed, 33 insertions(+), 67 deletions(-) diff --git a/.claude/skills/pvs/SKILL.md b/.claude/skills/pvs/SKILL.md index cde453d9a..bc4bf01bd 100644 --- a/.claude/skills/pvs/SKILL.md +++ b/.claude/skills/pvs/SKILL.md @@ -1,74 +1,36 @@ --- name: pvs -description: Use when running PVS-Studio static analysis (SAST + MISRA C:2023 / C++:2008) on TinyUSB for a given board. Wraps building the examples with an exported compile_commands.json and running pvs-studio-analyzer against .PVS-Studio/.pvsconfig, then converts the log to readable + SARIF output. +description: Use when running PVS-Studio static analysis (SAST + MISRA C:2023 / C++:2008) on TinyUSB for a given board. Builds the examples with an exported compile_commands.json, runs pvs-studio-analyzer against .PVS-Studio/.pvsconfig, and emits readable + SARIF output. --- # PVS-Studio Static Analysis -Run PVS-Studio on TinyUSB for one board. The skill bundles `run_pvs.sh`, which -follows the "Static Analysis (PVS-Studio)" section of AGENTS.md / CLAUDE.md: -build all examples for the board with `compile_commands.json` exported, run -`pvs-studio-analyzer` against it using `.PVS-Studio/.pvsconfig`, then convert the -log to an `errorfile` view and a SARIF report. - -## Quick start +`run_pvs.sh ` builds all examples for the board (with +`compile_commands.json` exported), runs `pvs-studio-analyzer` against +`.PVS-Studio/.pvsconfig`, then writes `pvs-.log` and `pvs-.sarif` +plus printed errorfile findings. Needs a license file or `$PVS_STUDIO_CREDENTIALS`. ```bash -# Whole project for a board: -.claude/skills/pvs/run_pvs.sh raspberry_pi_pico +.claude/skills/pvs/run_pvs.sh raspberry_pi_pico # whole project for a board -# Specific files only — -S takes a plaintext list (one path per line), NOT a -# source file directly (the AGENTS.md "-S src/foo.c" snippet is inaccurate): +# Scope to specific files — -S takes a plaintext list (one path per line), +# NOT a source file directly. Extra args pass through to the analyzer. printf 'src/tusb.c\nsrc/class/cdc/cdc_device.c\n' > /tmp/files.txt .claude/skills/pvs/run_pvs.sh stm32f407disco -S /tmp/files.txt ``` -The first positional argument is **BOARD** (required). Everything after it is -forwarded verbatim to `pvs-studio-analyzer analyze`. - -## What the script does - -1. **License** — if no license file is registered, materializes one from the - `PVS_STUDIO_CREDENTIALS` env var (` `, same secret CI uses). -2. **Build** — `cmake examples -B examples/cmake-build- -G Ninja - -DBOARD= -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_EXPORT_COMPILE_COMMANDS=ON` - then `cmake --build`. The exported `compile_commands.json` is what PVS reads. -3. **Analyze** — `pvs-studio-analyzer analyze -f - -R .PVS-Studio/.pvsconfig -o pvs-.log -j - --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser`. - (AGENTS.md shows `--dump-files`; it's omitted because it scatters - `.PVS-Studio.i/.cfg` dumps across the tree — only useful for debugging FPs.) -4. **Report** — `plog-converter -a GA:1,2 -t errorfile` (printed) and - `-t sarif` → `pvs-.sarif`. - -`.PVS-Studio/.pvsconfig` already excludes vendored code (`lib/`, `hw/mcu/`, -`pico-sdk/`, `esp-idf/`, IAR runtime) and suppresses the project's accepted -MISRA deviations — don't duplicate those excludes on the command line. - -## Choosing a board - -Match the build prerequisites (same as the rest of the repo): - -- `raspberry_pi_pico` — what CI's PVS-Studio job uses (needs Pico SDK deps). -- `stm32f407disco` — no external SDK; fastest to get a clean compile DB. -- Anything under `hw/bsp//boards/` works if its deps are fetched - (`python3 tools/get_deps.py -b `). - -## Outputs - -- `pvs-.log` — raw analyzer log (input to plog-converter). -- `pvs-.sarif` — SARIF report (same format CI uploads). -- errorfile findings are printed to stdout for a quick read. - -## Timing - -Dominated by the example build (tens of seconds to a few minutes depending on -board/deps). The analysis pass itself is ~10-30 s. Use a timeout ≥ 10 minutes -for boards whose deps must be fetched/built first. - -## Reporting results - -After a run, summarize the findings by rule/severity from the errorfile output -and point the user at `pvs-.sarif`. Cross-check anything flagged in -`src/` against `.pvsconfig` — if it's an already-accepted deviation it will have -been suppressed, so surviving findings are genuinely new. +## Notes + +- **Board:** `raspberry_pi_pico` mirrors CI (needs Pico SDK deps); + `stm32f407disco` is fastest (no external SDK). Any board works once its deps + are fetched (`python3 tools/get_deps.py -b `). +- `.pvsconfig` already excludes vendored code and suppresses accepted MISRA + deviations — don't re-add those on the command line. Surviving `src/` findings + are genuinely new. +- Timing is dominated by the build (deps may push it past a minute); the analysis + pass is ~10-30 s. Use a timeout ≥ 10 min when deps must be fetched first. +- `--dump-files` is intentionally omitted — it scatters `.PVS-Studio.i/.cfg` + dumps across the tree (FP-debugging only); add it back via the passthrough args. + +After a run, summarize findings by rule/severity from the errorfile output and +point the user at `pvs-.sarif`. diff --git a/AGENTS.md b/AGENTS.md index 5c9908d19..8ea650ecb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -153,28 +153,32 @@ Reports land in `cmake-metrics//metrics_compare.md` (per-board) and `cmak ## Static Analysis (PVS-Studio) -Requires `compile_commands.json` (CMake `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`). +Requires `compile_commands.json` (CMake `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`). The +`pvs` skill (`.claude/skills/pvs/SKILL.md`) wraps the build + analyze flow for a +board; the commands below are the underlying steps. ```bash # Whole project: pvs-studio-analyzer analyze \ -f examples/cmake-build-raspberry_pi_pico/compile_commands.json \ -R .PVS-Studio/.pvsconfig \ - -o pvs-report.log -j12 --dump-files \ + -o pvs-report.log -j12 \ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser -# Specific files (add one or more `-S `): +# Specific files: -S takes a plaintext list (one path per line), not paths directly: +printf 'src/foo.c\nsrc/bar.c\n' > files.txt pvs-studio-analyzer analyze \ -f examples/cmake-build-raspberry_pi_pico/compile_commands.json \ -R .PVS-Studio/.pvsconfig \ - -S src/foo.c -S src/bar.c \ - -o pvs-report.log -j12 --dump-files \ + -S files.txt \ + -o pvs-report.log -j12 \ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser plog-converter -a GA:1,2 -t errorfile pvs-report.log # view results ``` -Takes ~10-30 s. +Takes ~10-30 s. (`--dump-files` adds preprocessed `.PVS-Studio.i/.cfg` dumps next +to every source for false-positive debugging — omit it for normal runs.) ## Validation After Changes -- cgit v1.3.1 From 65b2aeb6a92a4681ec495a4d89565862dfaa55cf Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 11 Jun 2026 14:53:24 +0000 Subject: pvs skill: mirror CI --security-related-issues flag and ignore SARIF output - Add --security-related-issues to run_pvs.sh and AGENTS.md analyze commands so local runs reproduce the CI SAST classification (static_analysis.yml). - Ignore *.sarif so a successful run leaves the worktree clean. Addresses Codex review on #3695. --- .claude/skills/pvs/run_pvs.sh | 1 + .gitignore | 1 + AGENTS.md | 2 ++ 3 files changed, 4 insertions(+) diff --git a/.claude/skills/pvs/run_pvs.sh b/.claude/skills/pvs/run_pvs.sh index 3a829327d..d8604b697 100755 --- a/.claude/skills/pvs/run_pvs.sh +++ b/.claude/skills/pvs/run_pvs.sh @@ -69,6 +69,7 @@ pvs-studio-analyzer analyze \ -f "${COMPILE_DB}" \ -R .PVS-Studio/.pvsconfig \ -o "${REPORT_LOG}" -j"${JOBS}" \ + --security-related-issues \ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser \ "$@" diff --git a/.gitignore b/.gitignore index c11e51bb9..f3bd8c926 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ latex *.env *.ind *.log +*.sarif *.map *.obj *.jlink diff --git a/AGENTS.md b/AGENTS.md index 8ea650ecb..c26887425 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -163,6 +163,7 @@ pvs-studio-analyzer analyze \ -f examples/cmake-build-raspberry_pi_pico/compile_commands.json \ -R .PVS-Studio/.pvsconfig \ -o pvs-report.log -j12 \ + --security-related-issues \ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser # Specific files: -S takes a plaintext list (one path per line), not paths directly: @@ -172,6 +173,7 @@ pvs-studio-analyzer analyze \ -R .PVS-Studio/.pvsconfig \ -S files.txt \ -o pvs-report.log -j12 \ + --security-related-issues \ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser plog-converter -a GA:1,2 -t errorfile pvs-report.log # view results -- cgit v1.3.1 From dd31ba4530f1904b0d2d83fa6b008502354fb400 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 11 Jun 2026 14:56:16 +0000 Subject: pvs skill: harden credentials parsing; note compile DB is exported by default - Parse PVS_STUDIO_CREDENTIALS into two quoted fields (no glob/word-split). - AGENTS.md: examples build sets CMAKE_EXPORT_COMPILE_COMMANDS ON already. Addresses Copilot review on #3695. --- .claude/skills/pvs/run_pvs.sh | 6 ++++-- AGENTS.md | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.claude/skills/pvs/run_pvs.sh b/.claude/skills/pvs/run_pvs.sh index d8604b697..7406a3b4f 100755 --- a/.claude/skills/pvs/run_pvs.sh +++ b/.claude/skills/pvs/run_pvs.sh @@ -39,8 +39,10 @@ JOBS="$(nproc 2>/dev/null || echo 4)" if ! pvs-studio-analyzer lic-info >/dev/null 2>&1; then if [ -n "${PVS_STUDIO_CREDENTIALS:-}" ]; then echo ">>> Registering PVS-Studio license from PVS_STUDIO_CREDENTIALS" - # shellcheck disable=SC2086 # credentials expects two whitespace-separated args - pvs-studio-analyzer credentials $PVS_STUDIO_CREDENTIALS + # Split " " into exactly two fields, quoted, so a key containing + # glob chars or extra spaces can't be word-split/expanded. + read -r _pvs_name _pvs_key <<< "$PVS_STUDIO_CREDENTIALS" + pvs-studio-analyzer credentials "$_pvs_name" "$_pvs_key" else echo "ERROR: no PVS-Studio license found and PVS_STUDIO_CREDENTIALS is unset." >&2 exit 1 diff --git a/AGENTS.md b/AGENTS.md index c26887425..69efe916a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -153,7 +153,8 @@ Reports land in `cmake-metrics//metrics_compare.md` (per-board) and `cmak ## Static Analysis (PVS-Studio) -Requires `compile_commands.json` (CMake `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`). The +Requires `compile_commands.json`, which the examples build exports by default +(`hw/bsp/family_support.cmake` sets `CMAKE_EXPORT_COMPILE_COMMANDS ON`). The `pvs` skill (`.claude/skills/pvs/SKILL.md`) wraps the build + analyze flow for a board; the commands below are the underlying steps. -- cgit v1.3.1