From 25f06f9c25d722f5897b0ad98e581701d6a6df8f Mon Sep 17 00:00:00 2001 From: Asok Shanmugam Date: Fri, 10 Apr 2026 16:05:56 -0700 Subject: [PATCH 1/2] Add Cognium scorecard reader Adds CogniumReader, its unit test, and a two-row test fixture for the Cognium SAST tool (https://cognium.dev / https://github.com/cogniumhq/cognium). Cognium emits results via: cognium scan --format owasp-benchmark --output results.csv The CSV format uses a single comment/header line followed by one row per positive detection: # test name,category,CWE,real vulnerability BenchmarkTest00001,cmdi,78,true CogniumReader reads the CWE directly from column 2, so no category-to-CWE lookup table is needed. The reader is registered in Reader.allReaders() and verified by CogniumReaderTest. Co-Authored-By: Claude Sonnet 4.6 --- .../benchmarkutils/score/parsers/Reader.java | 2 + .../score/parsers/csv/CogniumReader.java | 93 +++++++++++++++++++ .../score/parsers/csv/CogniumReaderTest.java | 61 ++++++++++++ .../resources/testfiles/Benchmark_Cognium.csv | 3 + 4 files changed, 159 insertions(+) create mode 100644 plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java create mode 100644 plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReaderTest.java create mode 100644 plugin/src/test/resources/testfiles/Benchmark_Cognium.csv diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java index fd38ccbf..61ba7825 100644 --- a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java @@ -28,6 +28,7 @@ import org.owasp.benchmarkutils.score.BenchmarkScore; import org.owasp.benchmarkutils.score.ResultFile; import org.owasp.benchmarkutils.score.TestSuiteResults; +import org.owasp.benchmarkutils.score.parsers.csv.CogniumReader; import org.owasp.benchmarkutils.score.parsers.csv.SemgrepCSVReader; import org.owasp.benchmarkutils.score.parsers.csv.WhiteHatDynamicReader; import org.owasp.benchmarkutils.score.parsers.sarif.BanditReader; @@ -67,6 +68,7 @@ public static List allReaders() { new CheckmarxIASTReader(), new CheckmarxReader(), new CodeQLReader(), + new CogniumReader(), new ContrastAssessReader(), new ContrastScanReader(), new CoverityReader(), diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java new file mode 100644 index 00000000..ae0e43f0 --- /dev/null +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java @@ -0,0 +1,93 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details + * + * @author Cognium Labs + * @created 2026 + */ +package org.owasp.benchmarkutils.score.parsers.csv; + +import java.util.List; +import org.owasp.benchmarkutils.score.BenchmarkScore; +import org.owasp.benchmarkutils.score.ResultFile; +import org.owasp.benchmarkutils.score.TestCaseResult; +import org.owasp.benchmarkutils.score.TestSuiteResults; +import org.owasp.benchmarkutils.score.parsers.Reader; + +/** + * Reader for Cognium results generated via: + * + *

cognium scan <path> --format owasp-benchmark --output results.csv
+ * + *

The output format is a CSV with one row per detected finding: + * + *

+ * # test name,category,CWE,real vulnerability
+ * BenchmarkTest00001,cmdi,78,true
+ * BenchmarkTest00003,sqli,89,true
+ * 
+ * + *

Only positive detections are emitted; test cases not present are treated as negatives by the + * scorecard generator. + */ +public class CogniumReader extends Reader { + + @Override + public boolean canRead(ResultFile resultFile) { + return resultFile.filename().endsWith(".csv") + && resultFile.line(0).startsWith("# test name,category,CWE"); + } + + @Override + public TestSuiteResults parse(ResultFile resultFile) throws Exception { + TestSuiteResults tr = + new TestSuiteResults("Cognium", false, TestSuiteResults.ToolType.SAST); + + List rows = resultFile.contentAsRows(); + + // Row 0 is the header comment; data starts at row 1 + for (int i = 1; i < rows.size(); i++) { + String row = rows.get(i).trim(); + if (row.isEmpty()) { + continue; + } + + String[] parts = row.split(",", -1); + if (parts.length < 4) { + continue; + } + + String testName = parts[0].trim(); + if (!testName.startsWith(BenchmarkScore.TESTCASENAME)) { + continue; + } + + int cwe; + try { + cwe = Integer.parseInt(parts[2].trim()); + } catch (NumberFormatException e) { + System.out.println( + "WARNING: Cognium results file contained invalid CWE on row " + i + ": " + row); + continue; + } + + TestCaseResult tcr = new TestCaseResult(); + tcr.setNumber(testNumber(testName)); + tcr.setCWE(cwe); + tcr.setCategory(parts[1].trim()); + tr.put(tcr); + } + + return tr; + } +} diff --git a/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReaderTest.java b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReaderTest.java new file mode 100644 index 00000000..f17303d2 --- /dev/null +++ b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReaderTest.java @@ -0,0 +1,61 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * @author Cognium Labs + * @created 2026 + */ +package org.owasp.benchmarkutils.score.parsers.csv; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.benchmarkutils.score.BenchmarkScore; +import org.owasp.benchmarkutils.score.CweNumber; +import org.owasp.benchmarkutils.score.ResultFile; +import org.owasp.benchmarkutils.score.TestHelper; +import org.owasp.benchmarkutils.score.TestSuiteResults; +import org.owasp.benchmarkutils.score.parsers.ReaderTestBase; + +public class CogniumReaderTest extends ReaderTestBase { + + private ResultFile resultFile; + + @BeforeEach + void setUp() { + resultFile = TestHelper.resultFileOf("testfiles/Benchmark_Cognium.csv"); + BenchmarkScore.TESTCASENAME = "BenchmarkTest"; + } + + @Test + public void onlyCogniumReaderReportsCanReadAsTrue() { + assertOnlyMatcherClassIs(this.resultFile, CogniumReader.class); + } + + @Test + void readerHandlesGivenResultFile() throws Exception { + CogniumReader reader = new CogniumReader(); + TestSuiteResults result = reader.parse(resultFile); + + assertEquals(TestSuiteResults.ToolType.SAST, result.getToolType()); + assertFalse(result.isCommercial()); + assertEquals("Cognium", result.getToolName()); + + assertEquals(2, result.getTotalResults()); + + assertEquals(CweNumber.COMMAND_INJECTION, result.get(1).get(0).getCWE()); + assertEquals(CweNumber.XSS, result.get(2).get(0).getCWE()); + } +} diff --git a/plugin/src/test/resources/testfiles/Benchmark_Cognium.csv b/plugin/src/test/resources/testfiles/Benchmark_Cognium.csv new file mode 100644 index 00000000..d253843e --- /dev/null +++ b/plugin/src/test/resources/testfiles/Benchmark_Cognium.csv @@ -0,0 +1,3 @@ +# test name,category,CWE,real vulnerability +BenchmarkTest00001,cmdi,78,true +BenchmarkTest00002,xss,79,true From 1f2c51fd6c06c09545213c0ac53540b5da008f55 Mon Sep 17 00:00:00 2001 From: Asok Shanmugam Date: Fri, 10 Apr 2026 16:25:23 -0700 Subject: [PATCH 2/2] Add Cognium SARIF reader Replaces the earlier CSV-based approach with a proper SARIF reader. Cognium already outputs standard SARIF via --format sarif, so no new output format is needed in the tool itself. CogniumReader extends SarifReader with CweSourceType.CUSTOM, providing a static ruleId-to-CWE mapping for the 13 security sink types Cognium detects. Non-security findings (reliability, performance, etc.) have no mapping entry and are silently skipped by the base class. To generate results: cognium scan BenchmarkJava/src/ --format sarif --output Cognium.sarif Co-Authored-By: Claude Sonnet 4.6 --- .../benchmarkutils/score/parsers/Reader.java | 2 +- .../score/parsers/csv/CogniumReader.java | 93 ------------------- .../score/parsers/sarif/CogniumReader.java | 59 ++++++++++++ .../{csv => sarif}/CogniumReaderTest.java | 11 ++- .../resources/testfiles/Benchmark_Cognium.csv | 3 - .../testfiles/Benchmark_Cognium.sarif | 61 ++++++++++++ 6 files changed, 127 insertions(+), 102 deletions(-) delete mode 100644 plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java create mode 100644 plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/sarif/CogniumReader.java rename plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/{csv => sarif}/CogniumReaderTest.java (86%) delete mode 100644 plugin/src/test/resources/testfiles/Benchmark_Cognium.csv create mode 100644 plugin/src/test/resources/testfiles/Benchmark_Cognium.sarif diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java index 61ba7825..b5a5c947 100644 --- a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java @@ -28,10 +28,10 @@ import org.owasp.benchmarkutils.score.BenchmarkScore; import org.owasp.benchmarkutils.score.ResultFile; import org.owasp.benchmarkutils.score.TestSuiteResults; -import org.owasp.benchmarkutils.score.parsers.csv.CogniumReader; import org.owasp.benchmarkutils.score.parsers.csv.SemgrepCSVReader; import org.owasp.benchmarkutils.score.parsers.csv.WhiteHatDynamicReader; import org.owasp.benchmarkutils.score.parsers.sarif.BanditReader; +import org.owasp.benchmarkutils.score.parsers.sarif.CogniumReader; import org.owasp.benchmarkutils.score.parsers.sarif.CodeQLReader; import org.owasp.benchmarkutils.score.parsers.sarif.ContrastScanReader; import org.owasp.benchmarkutils.score.parsers.sarif.DatadogSastReader; diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java deleted file mode 100644 index ae0e43f0..00000000 --- a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReader.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * OWASP Benchmark Project - * - *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For - * details, please see https://owasp.org/www-project-benchmark/. - * - *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Foundation, version 2. - * - *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details - * - * @author Cognium Labs - * @created 2026 - */ -package org.owasp.benchmarkutils.score.parsers.csv; - -import java.util.List; -import org.owasp.benchmarkutils.score.BenchmarkScore; -import org.owasp.benchmarkutils.score.ResultFile; -import org.owasp.benchmarkutils.score.TestCaseResult; -import org.owasp.benchmarkutils.score.TestSuiteResults; -import org.owasp.benchmarkutils.score.parsers.Reader; - -/** - * Reader for Cognium results generated via: - * - *

cognium scan <path> --format owasp-benchmark --output results.csv
- * - *

The output format is a CSV with one row per detected finding: - * - *

- * # test name,category,CWE,real vulnerability
- * BenchmarkTest00001,cmdi,78,true
- * BenchmarkTest00003,sqli,89,true
- * 
- * - *

Only positive detections are emitted; test cases not present are treated as negatives by the - * scorecard generator. - */ -public class CogniumReader extends Reader { - - @Override - public boolean canRead(ResultFile resultFile) { - return resultFile.filename().endsWith(".csv") - && resultFile.line(0).startsWith("# test name,category,CWE"); - } - - @Override - public TestSuiteResults parse(ResultFile resultFile) throws Exception { - TestSuiteResults tr = - new TestSuiteResults("Cognium", false, TestSuiteResults.ToolType.SAST); - - List rows = resultFile.contentAsRows(); - - // Row 0 is the header comment; data starts at row 1 - for (int i = 1; i < rows.size(); i++) { - String row = rows.get(i).trim(); - if (row.isEmpty()) { - continue; - } - - String[] parts = row.split(",", -1); - if (parts.length < 4) { - continue; - } - - String testName = parts[0].trim(); - if (!testName.startsWith(BenchmarkScore.TESTCASENAME)) { - continue; - } - - int cwe; - try { - cwe = Integer.parseInt(parts[2].trim()); - } catch (NumberFormatException e) { - System.out.println( - "WARNING: Cognium results file contained invalid CWE on row " + i + ": " + row); - continue; - } - - TestCaseResult tcr = new TestCaseResult(); - tcr.setNumber(testNumber(testName)); - tcr.setCWE(cwe); - tcr.setCategory(parts[1].trim()); - tr.put(tcr); - } - - return tr; - } -} diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/sarif/CogniumReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/sarif/CogniumReader.java new file mode 100644 index 00000000..accbbe59 --- /dev/null +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/sarif/CogniumReader.java @@ -0,0 +1,59 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details + * + * @author Cognium Labs + * @created 2026 + */ +package org.owasp.benchmarkutils.score.parsers.sarif; + +import java.util.HashMap; +import java.util.Map; +import org.json.JSONObject; +import org.owasp.benchmarkutils.score.CweNumber; + +/** + * Reader for Cognium SARIF results generated via: + * + *

cognium scan <path> --format sarif --output results.sarif
+ * + *

Cognium embeds the CWE in each result's {@code properties.cwe} field (e.g. {@code "CWE-79"}) + * rather than in the rules section, so CWE resolution uses a static ruleId-to-CWE mapping. + * Non-security findings (reliability, performance, etc.) have no entry in the map and are silently + * skipped by the base class. + */ +public class CogniumReader extends SarifReader { + + public CogniumReader() { + super("cognium", false, CweSourceType.CUSTOM); + } + + @Override + public Map customRuleCweMappings(JSONObject tool) { + Map mappings = new HashMap<>(); + mappings.put("sql_injection", CweNumber.SQL_INJECTION); + mappings.put("command_injection", CweNumber.COMMAND_INJECTION); + mappings.put("path_traversal", CweNumber.PATH_TRAVERSAL); + mappings.put("xss", CweNumber.XSS); + mappings.put("ldap_injection", CweNumber.LDAP_INJECTION); + mappings.put("xpath_injection", CweNumber.XPATH_INJECTION); + mappings.put("weak_random", CweNumber.WEAK_RANDOM); + mappings.put("weak_hash", CweNumber.WEAK_HASH_ALGO); + mappings.put("weak_crypto", CweNumber.WEAK_CRYPTO_ALGO); + mappings.put("insecure_cookie", CweNumber.INSECURE_COOKIE); + mappings.put("trust_boundary", CweNumber.TRUST_BOUNDARY_VIOLATION); + mappings.put("xxe", CweNumber.XXE); + mappings.put("deserialization", CweNumber.INSECURE_DESERIALIZATION); + return mappings; + } +} diff --git a/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReaderTest.java b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/sarif/CogniumReaderTest.java similarity index 86% rename from plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReaderTest.java rename to plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/sarif/CogniumReaderTest.java index f17303d2..ec1b626c 100644 --- a/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/csv/CogniumReaderTest.java +++ b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/sarif/CogniumReaderTest.java @@ -15,7 +15,7 @@ * @author Cognium Labs * @created 2026 */ -package org.owasp.benchmarkutils.score.parsers.csv; +package org.owasp.benchmarkutils.score.parsers.sarif; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -35,7 +35,7 @@ public class CogniumReaderTest extends ReaderTestBase { @BeforeEach void setUp() { - resultFile = TestHelper.resultFileOf("testfiles/Benchmark_Cognium.csv"); + resultFile = TestHelper.resultFileOf("testfiles/Benchmark_Cognium.sarif"); BenchmarkScore.TESTCASENAME = "BenchmarkTest"; } @@ -51,11 +51,12 @@ void readerHandlesGivenResultFile() throws Exception { assertEquals(TestSuiteResults.ToolType.SAST, result.getToolType()); assertFalse(result.isCommercial()); - assertEquals("Cognium", result.getToolName()); + assertEquals("cognium", result.getToolName()); + assertEquals("1.4.2", result.getToolVersion()); assertEquals(2, result.getTotalResults()); - assertEquals(CweNumber.COMMAND_INJECTION, result.get(1).get(0).getCWE()); - assertEquals(CweNumber.XSS, result.get(2).get(0).getCWE()); + assertEquals(CweNumber.XSS, result.get(1).get(0).getCWE()); + assertEquals(CweNumber.SQL_INJECTION, result.get(2).get(0).getCWE()); } } diff --git a/plugin/src/test/resources/testfiles/Benchmark_Cognium.csv b/plugin/src/test/resources/testfiles/Benchmark_Cognium.csv deleted file mode 100644 index d253843e..00000000 --- a/plugin/src/test/resources/testfiles/Benchmark_Cognium.csv +++ /dev/null @@ -1,3 +0,0 @@ -# test name,category,CWE,real vulnerability -BenchmarkTest00001,cmdi,78,true -BenchmarkTest00002,xss,79,true diff --git a/plugin/src/test/resources/testfiles/Benchmark_Cognium.sarif b/plugin/src/test/resources/testfiles/Benchmark_Cognium.sarif new file mode 100644 index 00000000..28ab9302 --- /dev/null +++ b/plugin/src/test/resources/testfiles/Benchmark_Cognium.sarif @@ -0,0 +1,61 @@ +{ + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "cognium", + "version": "1.4.2", + "informationUri": "https://cognium.dev", + "rules": [ + { + "id": "xss", + "name": "xss", + "shortDescription": { "text": "xss" }, + "defaultConfiguration": { "level": "error" }, + "properties": { "security-severity": "7.0" } + }, + { + "id": "sql_injection", + "name": "sql_injection", + "shortDescription": { "text": "sql_injection" }, + "defaultConfiguration": { "level": "error" }, + "properties": { "security-severity": "9.0" } + } + ] + } + }, + "results": [ + { + "ruleId": "xss", + "level": "error", + "message": { "text": "xss vulnerability: tainted data flows from line 41 to line 86" }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { "uri": "BenchmarkTest00001.java" }, + "region": { "startLine": 86 } + } + } + ], + "properties": { "cwe": "CWE-79", "severity": "high" } + }, + { + "ruleId": "sql_injection", + "level": "error", + "message": { "text": "sql_injection vulnerability: tainted data flows from line 38 to line 55" }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { "uri": "BenchmarkTest00002.java" }, + "region": { "startLine": 55 } + } + } + ], + "properties": { "cwe": "CWE-89", "severity": "critical" } + } + ] + } + ] +}