diff --git a/.github/workflows/spotbugs.yml b/.github/workflows/spotbugs.yml index abca5e07..6a4967f2 100644 --- a/.github/workflows/spotbugs.yml +++ b/.github/workflows/spotbugs.yml @@ -46,18 +46,29 @@ jobs: # Each module writes its own target/spotbugsSarif.json. upload-sarif reads # a directory only for files named *.sarif, so they are gathered under one # directory and renamed per module to keep the findings attributable. + # + # Every module's run carries the same SpotBugs tool driver, so code + # scanning would see seven indistinguishable runs in one delivery and + # reject the upload ("multiple SARIF runs with the same category"). The + # run's category is its automationDetails.id, so each file gets the + # module's own — which upload-sarif then leaves alone, since it only fills + # in an id where none is set. One category per module, one run per + # category. run: | mkdir -p target/sarif find . -path '*/target/spotbugsSarif.json' -print0 | while IFS= read -r -d '' report; do module=$(echo "${report}" | sed -e 's|^\./||' -e 's|/target/spotbugsSarif\.json$||' -e 's|/|-|g') - cp "${report}" "target/sarif/${module}.sarif" + jq --arg id "spotbugs/${module}/" '.runs[].automationDetails.id = $id' \ + "${report}" > "target/sarif/${module}.sarif" done echo "Collected $(find target/sarif -name '*.sarif' | wc -l) SARIF reports." - name: Publish SARIF to code scanning + # No category input: it would only apply to runs that have no + # automationDetails.id of their own, and the step above gives every run + # the per-module id that keeps the delivery's runs distinct. uses: github/codeql-action/upload-sarif@988661ebb5e81487b3fb31b2185d2856c0a10679 # v4 with: sarif_file: target/sarif - category: spotbugs - name: Upload SpotBugs reports uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: diff --git a/AGENTS.md b/AGENTS.md index 50119968..57788079 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -779,8 +779,12 @@ module's `*IT`s stay unrun until it gets its own copy. Run them with has read it, and it is **report-only**: the tree carries findings today, so a `check` goal would fail every build instead of surfacing them. `spotbugs.yml` publishes the SARIF to the code-scanning tab, which is where the findings are - meant to be triaged. The same two generated-code modules opt out with - `spotbugs.skip`, for the same reason they set `jacoco.skip` and `pitest.skip`. + meant to be triaged. It publishes each module's report under its own category, + `spotbugs//`, written into the run's `automationDetails.id` before the + upload: every module's run names the same SpotBugs driver, and code scanning + rejects a delivery holding two runs it cannot tell apart. The same two + generated-code modules opt out with `spotbugs.skip`, for the same reason they + set `jacoco.skip` and `pitest.skip`. A finding that has been decided about rather than fixed is excluded in the module's own filter file, wired in from the module pom — today only