From 028c90a9c851eb9dbb2cc4cea480f56d457a231d Mon Sep 17 00:00:00 2001 From: Yishai Beeri Date: Tue, 17 Feb 2026 09:34:56 +0200 Subject: [PATCH 1/2] feat: add extractCheckmarxFindings plugin Add a new filter plugin to extract security findings from Checkmarx PR comments. Parses findings by scanner type (SAST, SCA, KICS) and severity level (critical, high, medium, low, info), counting only new issues from the latest scan comment. Co-Authored-By: Claude --- .../filters/extractCheckmarxFindings/LICENSE | 21 +++++ .../extractCheckmarxFindings/README.md | 24 +++++ .../extract_checkmarx_findings.cm | 28 ++++++ .../filters/extractCheckmarxFindings/index.js | 91 +++++++++++++++++++ .../extractCheckmarxFindings/reference.md | 19 ++++ 5 files changed, 183 insertions(+) create mode 100644 plugins/filters/extractCheckmarxFindings/LICENSE create mode 100644 plugins/filters/extractCheckmarxFindings/README.md create mode 100644 plugins/filters/extractCheckmarxFindings/extract_checkmarx_findings.cm create mode 100644 plugins/filters/extractCheckmarxFindings/index.js create mode 100644 plugins/filters/extractCheckmarxFindings/reference.md diff --git a/plugins/filters/extractCheckmarxFindings/LICENSE b/plugins/filters/extractCheckmarxFindings/LICENSE new file mode 100644 index 000000000..5d3cca0ac --- /dev/null +++ b/plugins/filters/extractCheckmarxFindings/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 LinearB + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/filters/extractCheckmarxFindings/README.md b/plugins/filters/extractCheckmarxFindings/README.md new file mode 100644 index 000000000..23fa27376 --- /dev/null +++ b/plugins/filters/extractCheckmarxFindings/README.md @@ -0,0 +1,24 @@ +--8<-- "plugins/filters/extractCheckmarxFindings/reference.md" + +Usage example, that adds labels based on Checkmarx scan findings. + +??? note "Plugin Code: extractCheckmarxFindings" + ```javascript + --8<-- "plugins/filters/extractCheckmarxFindings/index.js" + ``` +
+ + +
+ + +??? example "gitStream CM Example: extractCheckmarxFindings" + ```yaml+jinja + --8<-- "plugins/filters/extractCheckmarxFindings/extract_checkmarx_findings.cm" + ``` +
+ + +
+ +[Download Source Code](https://github.com/linear-b/gitstream/tree/main/plugins/filters/extractCheckmarxFindings) diff --git a/plugins/filters/extractCheckmarxFindings/extract_checkmarx_findings.cm b/plugins/filters/extractCheckmarxFindings/extract_checkmarx_findings.cm new file mode 100644 index 000000000..41090c1db --- /dev/null +++ b/plugins/filters/extractCheckmarxFindings/extract_checkmarx_findings.cm @@ -0,0 +1,28 @@ +# -*- mode: yaml -*- + +manifest: + version: 1.0 + +automations: + {% for item in reports %} + label_checkmarx_{{ item.name }}: + if: + - {{ item.count > 0 }} + run: + - action: add-label@v1 + args: + label: 'checkmarx:{{ item.name }}' + {% endfor %} + +checkmarx: {{ pr | extractCheckmarxFindings }} + +reports: + - name: sast-findings + count: {{ checkmarx.sast.count }} + - name: sca-findings + count: {{ checkmarx.sca.count }} + - name: iac-findings + count: {{ checkmarx.kics.count }} + +colors: + red: 'b60205' diff --git a/plugins/filters/extractCheckmarxFindings/index.js b/plugins/filters/extractCheckmarxFindings/index.js new file mode 100644 index 000000000..0e61b62de --- /dev/null +++ b/plugins/filters/extractCheckmarxFindings/index.js @@ -0,0 +1,91 @@ +/** + * @module extractCheckmarxFindings + * @description Extract security findings from Checkmarx PR comments + * @param {Object} pr - the gitStream's PR context variable + * @returns {Object} Findings + * Findings.sast: { count: null, severity: '' }, + * Findings.sca: { count: null, severity: '' }, + * Findings.kics: { count: null, severity: '' }, + * @example {{ pr | extractCheckmarxFindings }} + * @license MIT +**/ + +const SCANNERS = ['sast', 'sca', 'kics']; +const SEVERITY_LEVELS = ['critical', 'high', 'medium', 'low', 'info']; + +function emptySeverity() { + return { critical: 0, high: 0, medium: 0, low: 0, info: 0 }; +} + +function emptyFindings() { + return { count: null, severity: '' }; +} + +function detectScanner(line) { + if (/\b(IaC[\s-]*Security|KICS)\b/i.test(line)) return 'kics'; + if (/\bSAST\b/i.test(line)) return 'sast'; + if (/\bSCA\b/i.test(line)) return 'sca'; + return null; +} + +function parseCheckmarxComment(content) { + const findings = {}; + SCANNERS.forEach(s => { findings[s] = emptyFindings(); }); + + const severityCounts = {}; + SCANNERS.forEach(s => { severityCounts[s] = emptySeverity(); }); + + const lines = content.split('\n'); + let currentScanner = null; + let inNewIssues = false; + + for (const line of lines) { + // Track whether we're in a "New Issues" or "Fixed Issues" section. + // Only count findings from the "New Issues" section. + if (/\bNew\s+Issues\b/i.test(line)) { + inNewIssues = true; + } else if (/\bFixed\s+Issues\b/i.test(line)) { + inNewIssues = false; + } + + // Update current scanner section when we see a scanner name + const scanner = detectScanner(line); + if (scanner) { + currentScanner = scanner; + } + + // Match table rows where the first cell contains a severity level + // Checkmarx tables use: | SEVERITY | Issue | ... | + if (!inNewIssues) continue; + const tableMatch = line.match(/^\s*\|\s*(CRITICAL|HIGH|MEDIUM|LOW|INFO)\b/i); + if (tableMatch && currentScanner) { + const level = tableMatch[1].toLowerCase(); + severityCounts[currentScanner][level]++; + } + } + + SCANNERS.forEach(s => { + const counts = severityCounts[s]; + const total = counts.critical + counts.high + counts.medium + counts.low + counts.info; + findings[s] = { count: total, severity: counts }; + }); + + return findings; +} + +module.exports = (pr) => { + let checkmarxObject = {}; + SCANNERS.forEach(s => { checkmarxObject[s] = emptyFindings(); }); + + // Checkmarx comments can appear as PR comments or reviews + const checkmarxComment = pr.comments + .filter(x => x.commenter.includes('checkmarx')) + .concat(pr.reviews.filter(x => x.commenter.includes('checkmarx'))); + + if (checkmarxComment.length) { + const latestComment = checkmarxComment[checkmarxComment.length - 1].content; + checkmarxObject = parseCheckmarxComment(latestComment); + } + + return JSON.stringify(checkmarxObject); +} diff --git a/plugins/filters/extractCheckmarxFindings/reference.md b/plugins/filters/extractCheckmarxFindings/reference.md new file mode 100644 index 000000000..9c52249fc --- /dev/null +++ b/plugins/filters/extractCheckmarxFindings/reference.md @@ -0,0 +1,19 @@ + + +## extractCheckmarxFindings +Extract security findings from Checkmarx PR comments + +**Returns**: Object - Findings +Findings.sast: { count: null, severity: '' }, +Findings.sca: { count: null, severity: '' }, +Findings.kics: { count: null, severity: '' }, +**License**: MIT + +| Param | Type | Description | +| --- | --- | --- | +| PR | Object | the gitStream's PR context variable | + +**Example** +```js +{{ pr | extractCheckmarxFindings }} +``` From defeb55f13af9e83e7809ba766dbe7a09d34fd1b Mon Sep 17 00:00:00 2001 From: Yishai Beeri Date: Tue, 17 Feb 2026 09:37:56 +0200 Subject: [PATCH 2/2] docs: add Checkmarx integration documentation Add integration page, automation examples (label scan results, review alerts), and downloadable CM files. Register the plugin in the filter function plugins list and add a card to the integrations overview. Co-Authored-By: Claude --- .../label-checkmarx-scan-results/README.md | 45 +++++++++++++++++++ .../review-checkmarx-alerts/README.md | 44 ++++++++++++++++++ .../checkmarx/label_checkmarx_scan_results.cm | 28 ++++++++++++ .../checkmarx/review_checkmarx_alerts.cm | 23 ++++++++++ docs/filter-function-plugins.md | 2 + docs/integrations/README.md | 6 +++ docs/integrations/checkmarx.md | 19 ++++++++ 7 files changed, 167 insertions(+) create mode 100644 docs/automations/integrations/checkmarx/label-checkmarx-scan-results/README.md create mode 100644 docs/automations/integrations/checkmarx/review-checkmarx-alerts/README.md create mode 100644 docs/downloads/automation-library/integrations/checkmarx/label_checkmarx_scan_results.cm create mode 100644 docs/downloads/automation-library/integrations/checkmarx/review_checkmarx_alerts.cm create mode 100644 docs/integrations/checkmarx.md diff --git a/docs/automations/integrations/checkmarx/label-checkmarx-scan-results/README.md b/docs/automations/integrations/checkmarx/label-checkmarx-scan-results/README.md new file mode 100644 index 000000000..629474d25 --- /dev/null +++ b/docs/automations/integrations/checkmarx/label-checkmarx-scan-results/README.md @@ -0,0 +1,45 @@ +--- +title: Automation - Auto-Label Checkmarx Scan Results +description: Automatically apply labels to PRs that indicate the result of Checkmarx scans. +category: [security, checkmarx] +--- +# Auto-Label Checkmarx Scan Results + + + +Automatically apply labels to PRs that indicate the result of Checkmarx scans. + +!!! warning "Required gitStream Plugin" + This example requires you to [install the `extractCheckmarxFindings` plugin](/filter-function-plugins/#extractcheckmarxfindings). + + [Learn more about gitStream plugins](/plugins/). + +
+!!! info "Configuration Description" + Conditions (all must be true): + + * Checkmarx detects one or more new issues with the code in the PR. + + Automation Actions: + + * Apply a label that indicates which scan type identified the issue (SAST, SCA, or IaC). + +
+
+!!! example "Auto-Label Checkmarx Scan Results" + ```yaml+jinja + --8<-- "docs/downloads/automation-library/integrations/checkmarx/label_checkmarx_scan_results.cm" + ``` +
+ + [:octicons-download-24: Download this example as a CM file.](/downloads/automation-library/integrations/checkmarx/label_checkmarx_scan_results.cm){ .md-button } + +
+
+ + +## Additional Resources + +--8<-- "docs/snippets/general.md" + +--8<-- "docs/snippets/automation-footer.md" diff --git a/docs/automations/integrations/checkmarx/review-checkmarx-alerts/README.md b/docs/automations/integrations/checkmarx/review-checkmarx-alerts/README.md new file mode 100644 index 000000000..08e98fa91 --- /dev/null +++ b/docs/automations/integrations/checkmarx/review-checkmarx-alerts/README.md @@ -0,0 +1,44 @@ +--- +title: Automation - Review Checkmarx Security Alerts +description: Automatically require review from your SecOps team for Checkmarx security violations in pull requests. +category: [security, checkmarx] +--- +# Require Security Review for Checkmarx Alerts + +Automatically require review from your SecOps team for Checkmarx security violations in pull requests. + +!!! warning "Required gitStream Plugin" + This example requires you to [install the `extractCheckmarxFindings` plugin](/filter-function-plugins/#extractcheckmarxfindings). + + [Learn more about gitStream plugins](/plugins/). + +
+!!! info "Configuration Description" + Conditions (all must be true): + + * The PR contains a SAST finding, SCA vulnerability, or IaC issue flagged as Critical or High. + + Automation Actions: + + * Require review from your organization's security team. + * Post a comment explaining the requirement. + +
+
+!!! example "Review Checkmarx Security Alerts" + ```yaml+jinja + --8<-- "docs/downloads/automation-library/integrations/checkmarx/review_checkmarx_alerts.cm" + ``` +
+ + [:octicons-download-24: Download this example as a CM file.](/downloads/automation-library/integrations/checkmarx/review_checkmarx_alerts.cm){ .md-button } + +
+
+ + +## Additional Resources + +--8<-- "docs/snippets/general.md" + +--8<-- "docs/snippets/automation-footer.md" diff --git a/docs/downloads/automation-library/integrations/checkmarx/label_checkmarx_scan_results.cm b/docs/downloads/automation-library/integrations/checkmarx/label_checkmarx_scan_results.cm new file mode 100644 index 000000000..41090c1db --- /dev/null +++ b/docs/downloads/automation-library/integrations/checkmarx/label_checkmarx_scan_results.cm @@ -0,0 +1,28 @@ +# -*- mode: yaml -*- + +manifest: + version: 1.0 + +automations: + {% for item in reports %} + label_checkmarx_{{ item.name }}: + if: + - {{ item.count > 0 }} + run: + - action: add-label@v1 + args: + label: 'checkmarx:{{ item.name }}' + {% endfor %} + +checkmarx: {{ pr | extractCheckmarxFindings }} + +reports: + - name: sast-findings + count: {{ checkmarx.sast.count }} + - name: sca-findings + count: {{ checkmarx.sca.count }} + - name: iac-findings + count: {{ checkmarx.kics.count }} + +colors: + red: 'b60205' diff --git a/docs/downloads/automation-library/integrations/checkmarx/review_checkmarx_alerts.cm b/docs/downloads/automation-library/integrations/checkmarx/review_checkmarx_alerts.cm new file mode 100644 index 000000000..b4f53e403 --- /dev/null +++ b/docs/downloads/automation-library/integrations/checkmarx/review_checkmarx_alerts.cm @@ -0,0 +1,23 @@ +# -*- mode: yaml -*- + +manifest: + version: 1.0 +automations: + review_checkmarx_alerts: + if: + - {{ has.sast_alert or has.sca_alert or has.iac_alert }} + run: + - action: require-reviewers@v1 + args: + reviewers: [my-organization/security-team] + - action: add-comment@v1 + args: + comment: | + This PR requires additional review because Checkmarx identified security issues that need attention. + +checkmarx: {{ pr | extractCheckmarxFindings }} + +has: + sast_alert: {{ checkmarx.sast.severity.critical > 0 or checkmarx.sast.severity.high > 0 }} + sca_alert: {{ checkmarx.sca.severity.critical > 0 or checkmarx.sca.severity.high > 0 }} + iac_alert: {{ checkmarx.kics.severity.critical > 0 or checkmarx.kics.severity.high > 0 }} diff --git a/docs/filter-function-plugins.md b/docs/filter-function-plugins.md index 4b0d0d1ee..ac409f2d4 100644 --- a/docs/filter-function-plugins.md +++ b/docs/filter-function-plugins.md @@ -26,6 +26,8 @@ JavaScript plugins that enable custom filter functions for gitStream. To learn h --8<-- "plugins/filters/extractSnykVersionBump/README.md" +--8<-- "plugins/filters/extractCheckmarxFindings/README.md" + --8<-- "plugins/filters/extractOrcaFindings/README.md" --8<-- "plugins/filters/generateDescription/README.md" diff --git a/docs/integrations/README.md b/docs/integrations/README.md index a08d86a43..ede340a7e 100644 --- a/docs/integrations/README.md +++ b/docs/integrations/README.md @@ -95,6 +95,12 @@ visible: false
+
+
+[:material-shield-search: Checkmarx](/integrations/checkmarx/) +
+
+
![Orca Security](../downloads/images/Orca-Mark-Black.png#only-light) ![LinearB](../downloads/images/Orca-Mark-White.png#only-dark) Orca diff --git a/docs/integrations/checkmarx.md b/docs/integrations/checkmarx.md new file mode 100644 index 000000000..bc3bb4578 --- /dev/null +++ b/docs/integrations/checkmarx.md @@ -0,0 +1,19 @@ +--- +title: Integrate gitStream with Checkmarx +description: Implement workflow automations for Checkmarx. +--- +# Integrate gitStream with Checkmarx + +## Auto-Label Checkmarx Scan Results +--8<-- "docs/automations/integrations/checkmarx/label-checkmarx-scan-results/README.md:example" + +## Require Security Review for Checkmarx Alerts +--8<-- "docs/automations/integrations/checkmarx/review-checkmarx-alerts/README.md:example" + + + +## Additional Resources + +--8<-- "docs/snippets/general.md" + +--8<-- "docs/snippets/automation-footer.md"