From 743e9550e1d0a7a93fd664c1d03d33743bd05399 Mon Sep 17 00:00:00 2001 From: Seth Van Niekerk Date: Wed, 12 Aug 2026 08:55:26 -0400 Subject: [PATCH] fix(ci): make inline CodeQL suppression comments work, dedupe repeated finding text Overriding queries: security-extended on codeql-action/init silently dropped each language's AlertSuppression.ql, so correctly-placed inline `codeql[]` comments never populated SARIF suppressions and were always ignored (confirmed against PR #207). Move the query suite into a codeql-config.yml and add the advanced-security/-alert-suppression packs there, since packs: only works for single-language init. Also dedupe repeated sentences in data-flow finding descriptions, which could render the same sentence a dozen times in one PR comment table row. --- .github/codeql/codeql-config.yml | 24 +++++++++++++++ .github/workflows/validate-plugin.yml | 44 +++++++++++++++++++-------- 2 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 .github/codeql/codeql-config.yml diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000..b8a7b9f4 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,24 @@ +# Extra CodeQL packs applied alongside the `security-extended` suite used by +# validate-plugin.yml. `packs:` is required here (rather than the simpler +# `packs:` input on codeql-action/init) because that input only works for +# single-language analyses, and our workflow can initialize multiple +# languages at once. Each pack bundles that language's built-in +# AlertSuppression.ql (kind: alert-suppression), which is what makes inline +# `codeql[]` comments actually populate SARIF `suppressions` - +# without it, our custom `queries:` override silently drops suppression +# support and inline suppression comments are ignored. +queries: + - uses: security-extended +packs: + python: + - advanced-security/python-alert-suppression + javascript: + - advanced-security/javascript-alert-suppression + go: + - advanced-security/go-alert-suppression + ruby: + - advanced-security/ruby-alert-suppression + java: + - advanced-security/java-alert-suppression + cpp: + - advanced-security/cpp-alert-suppression diff --git a/.github/workflows/validate-plugin.yml b/.github/workflows/validate-plugin.yml index 71929c79..4d0a977c 100644 --- a/.github/workflows/validate-plugin.yml +++ b/.github/workflows/validate-plugin.yml @@ -432,9 +432,10 @@ jobs: - name: Limit checkout to changed plugin folders only run: | - echo '${{ needs.detect-changes.outputs.matrix }}' \ - | jq -r '.[] | "plugins/\(.)"' \ - | git sparse-checkout set --stdin + { + echo '.github/codeql' + echo '${{ needs.detect-changes.outputs.matrix }}' | jq -r '.[] | "plugins/\(.)"' + } | git sparse-checkout set --stdin git checkout - name: Populate external plugin source for analysis @@ -534,11 +535,10 @@ jobs: with: languages: ${{ steps.detect-langs.outputs.languages }} build-mode: none - # Query suite options (slowest → fastest): - # security-and-quality – security + maintainability/style (quality results are discarded by our SARIF filter anyway) - # security-extended – all security severities, no quality queries (current) - # (omit queries:) – high-confidence security only; drops CVSS 6.0–6.9 medium findings our report surfaces - queries: security-extended + # Query suite (security-extended: all security severities, no quality queries) and + # per-language alert-suppression packs (so inline `codeql[]` comments work) + # both live in this config file - see .github/codeql/codeql-config.yml for why. + config-file: .github/codeql/codeql-config.yml - name: Perform CodeQL Analysis if: steps.detect-langs.outputs.found == 'true' @@ -688,7 +688,12 @@ jobs: select((($secmap[$rid] // "0") | tonumber) >= 7.0) | (.locations[0].physicalLocation.artifactLocation.uri // "?") as $uri | ((.locations[0].physicalLocation.region.startLine // "?") | tostring) as $line | - (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]")) as $msg | + (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]") + # Data-flow queries can repeat the same sentence once per source/flow reaching + # the same sink - collapse repeats while preserving first-seen order. + | [splits("(?<=[.!?]) ")] as $sentences + | reduce $sentences[] as $s ([]; if any(.[]; . == $s) then . else . + [$s] end) + | join(" ")) as $msg | ([$external_prefixes[] | . as $p | $uri | startswith($p)] | any) as $is_external | (if ($uri != "?" and $line != "?" and ($is_external | not)) then "[\($uri):\($line)](https://github.com/\($repo)/blob/\($sha)/\($uri)#L\($line))" else "\($uri):\($line)" end) as $loc | "| `\($rid)` | \($loc) | \($msg) |"' @@ -727,7 +732,12 @@ jobs: select($sev >= 6.0 and $sev < 7.0) | (.locations[0].physicalLocation.artifactLocation.uri // "?") as $uri | ((.locations[0].physicalLocation.region.startLine // "?") | tostring) as $line | - (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]")) as $msg | + (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]") + # Data-flow queries can repeat the same sentence once per source/flow reaching + # the same sink - collapse repeats while preserving first-seen order. + | [splits("(?<=[.!?]) ")] as $sentences + | reduce $sentences[] as $s ([]; if any(.[]; . == $s) then . else . + [$s] end) + | join(" ")) as $msg | ([$external_prefixes[] | . as $p | $uri | startswith($p)] | any) as $is_external | (if ($uri != "?" and $line != "?" and ($is_external | not)) then "[\($uri):\($line)](https://github.com/\($repo)/blob/\($sha)/\($uri)#L\($line))" else "\($uri):\($line)" end) as $loc | "| `\($rid)` | \($loc) | \($msg) |"' @@ -766,7 +776,12 @@ jobs: select($sev < 6.0) | (.locations[0].physicalLocation.artifactLocation.uri // "?") as $uri | ((.locations[0].physicalLocation.region.startLine // "?") | tostring) as $line | - (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]")) as $msg | + (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]") + # Data-flow queries can repeat the same sentence once per source/flow reaching + # the same sink - collapse repeats while preserving first-seen order. + | [splits("(?<=[.!?]) ")] as $sentences + | reduce $sentences[] as $s ([]; if any(.[]; . == $s) then . else . + [$s] end) + | join(" ")) as $msg | ([$external_prefixes[] | . as $p | $uri | startswith($p)] | any) as $is_external | (if ($uri != "?" and $line != "?" and ($is_external | not)) then "[\($uri):\($line)](https://github.com/\($repo)/blob/\($sha)/\($uri)#L\($line))" else "\($uri):\($line)" end) as $loc | "| `\($rid)` | \($loc) | \($msg) |"' @@ -800,7 +815,12 @@ jobs: (($result.ruleId // $result.rule.id // "") | tostring) as $rid | (.locations[0].physicalLocation.artifactLocation.uri // "?") as $uri | ((.locations[0].physicalLocation.region.startLine // "?") | tostring) as $line | - (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]")) as $msg | + (.message.text // "no description" | gsub("\n"; " ") | gsub("://"; "\u200b://") | gsub("www\\."; "www\u200b.") | gsub("#(?=[0-9])"; "#\u200b") | gsub("\\[(?[^\\]]+)\\][(][0-9]+[)]"; .c) | gsub("\\["; "[") | gsub("\\]"; "]") + # Data-flow queries can repeat the same sentence once per source/flow reaching + # the same sink - collapse repeats while preserving first-seen order. + | [splits("(?<=[.!?]) ")] as $sentences + | reduce $sentences[] as $s ([]; if any(.[]; . == $s) then . else . + [$s] end) + | join(" ")) as $msg | ([$external_prefixes[] | . as $p | $uri | startswith($p)] | any) as $is_external | (if ($uri != "?" and $line != "?" and ($is_external | not)) then "[\($uri):\($line)](https://github.com/\($repo)/blob/\($sha)/\($uri)#L\($line))" else "\($uri):\($line)" end) as $loc | "| `\($rid)` | \($loc) | \($msg) |"'