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 262dc5f5..462d0ac3 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 @@ -40,6 +40,7 @@ import org.owasp.benchmarkutils.score.parsers.sarif.MendSarifReader; import org.owasp.benchmarkutils.score.parsers.sarif.OpenTaintReader; import org.owasp.benchmarkutils.score.parsers.sarif.PTAIReader; +import org.owasp.benchmarkutils.score.parsers.sarif.PVSStudioReader; import org.owasp.benchmarkutils.score.parsers.sarif.PrecautionReader; import org.owasp.benchmarkutils.score.parsers.sarif.SemgrepSarifReader; import org.owasp.benchmarkutils.score.parsers.sarif.SnykReader; @@ -104,6 +105,7 @@ public static List allReaders() { new PrecautionReader(), new PMDReader(), new PTAIReader(), + new PVSStudioReader(), new QualysWASReader(), new Rapid7Reader(), new ReshiftReader(), diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/sarif/PVSStudioReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/sarif/PVSStudioReader.java new file mode 100644 index 00000000..e0cd5e95 --- /dev/null +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/sarif/PVSStudioReader.java @@ -0,0 +1,48 @@ +/** + * 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 Cyril Yepifanov + * @created 2026 + */ +package org.owasp.benchmarkutils.score.parsers.sarif; + +import org.owasp.benchmarkutils.score.CweNumber; + +public class PVSStudioReader extends SarifReader { + + static final int PVS_CWE_OS_COMMAND_INJECTION = 77; + static final int PVS_CWE_OS_ARGUMENT_INJECTION = 88; + static final int PVS_CWE_HASH_ALGO_NOT_RECOMMENDED = 1240; + static final int PVS_CWE_XPATH_INJECTION = 91; + + static final String TOOL_NAME = "PVS-Studio"; + + public PVSStudioReader() { + super(TOOL_NAME, true, CweSourceType.TAG); + } + + @Override + public int mapCwe(int cwe) { + switch (cwe) { + case PVS_CWE_OS_COMMAND_INJECTION: + case PVS_CWE_OS_ARGUMENT_INJECTION: + return CweNumber.COMMAND_INJECTION; + case PVS_CWE_HASH_ALGO_NOT_RECOMMENDED: + return CweNumber.WEAK_HASH_ALGO; + case PVS_CWE_XPATH_INJECTION: + return CweNumber.XPATH_INJECTION; + } + return cwe; + } +} diff --git a/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/sarif/PVSStudioReaderTest.java b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/sarif/PVSStudioReaderTest.java new file mode 100644 index 00000000..7d3b2a95 --- /dev/null +++ b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/sarif/PVSStudioReaderTest.java @@ -0,0 +1,62 @@ +/** + * 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 Cyril Yepifanov + * @created 2026 + */ +package org.owasp.benchmarkutils.score.parsers.sarif; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +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; + +class PVSStudioReaderTest extends ReaderTestBase { + + private ResultFile resultFile; + + @BeforeEach + void setUp() { + resultFile = TestHelper.resultFileOf("testfiles/Benchmark_PVS-Studio-7.42.sarif"); + BenchmarkScore.TESTCASENAME = "BenchmarkTest"; + } + + @Test + void onlyPVSStudioReaderReportsCanReadAsTrue() { + assertOnlyMatcherClassIs(this.resultFile, PVSStudioReader.class); + } + + @Test + void readerHandlesGivenResultFile() throws Exception { + PVSStudioReader reader = new PVSStudioReader(); + TestSuiteResults result = reader.parse(resultFile); + + assertEquals(TestSuiteResults.ToolType.SAST, result.getToolType()); + assertEquals("PVS-Studio", result.getToolName()); + assertEquals("7.42.105218.307", result.getToolVersion()); + assertTrue(result.isCommercial()); + + assertEquals(2, result.getTotalResults()); + + assertEquals(CweNumber.LDAP_INJECTION, result.get(1).get(0).getCWE()); + assertEquals(CweNumber.WEAK_CRYPTO_ALGO, result.get(2).get(0).getCWE()); + } +} diff --git a/plugin/src/test/resources/testfiles/Benchmark_PVS-Studio-7.42.sarif b/plugin/src/test/resources/testfiles/Benchmark_PVS-Studio-7.42.sarif new file mode 100644 index 00000000..db4bbbbe --- /dev/null +++ b/plugin/src/test/resources/testfiles/Benchmark_PVS-Studio-7.42.sarif @@ -0,0 +1,118 @@ +{ + "version": "2.1.0", + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json", + "runs": [ + { + "invocations": [], + "tool": { + "driver": { + "name": "PVS-Studio", + "semanticVersion": "7.42.105218.307", + "informationUri": "https://pvs-studio.com", + "rules": [ + { + "id": "V5315", + "name": "RuleV5315", + "help": { + "text": "https://pvs-studio.com/en/docs/warnings/v5315/" + }, + "helpUri": "https://pvs-studio.com/en/docs/warnings/v5315/", + "properties": { + "tags": [ + "security", + "external/cwe/cwe-327" + ] + } + }, + { + "id": "V5321", + "name": "RuleV5321", + "help": { + "text": "https://pvs-studio.com/en/docs/warnings/v5321/" + }, + "helpUri": "https://pvs-studio.com/en/docs/warnings/v5321/", + "properties": { + "tags": [ + "security", + "external/cwe/cwe-90" + ] + } + } + ] + } + }, + "results": [ + { + "ruleId": "V5315", + "message": { + "text": "message." + }, + "level": "error", + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java" + }, + "region": { + "startLine": 63, + "endLine": 63 + } + } + } + ] + }, + { + "ruleId": "V5321", + "message": { + "text": "message." + }, + "level": "error", + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java" + }, + "region": { + "startLine": 58, + "endLine": 58 + } + } + } + ], + "relatedLocations": [ + { + "message": { + "text": "message." + }, + "physicalLocation": { + "artifactLocation": { + "uri": "src/main/java/org/owasp/benchmark/testcode/foo.java" + }, + "region": { + "endLine": 44, + "startLine": 44 + } + } + }, + { + "message": { + "text": "message." + }, + "physicalLocation": { + "artifactLocation": { + "uri": "file://src/main/java/org/owasp/benchmark/testcode/bar.java" + }, + "region": { + "endLine": 58, + "startLine": 58 + } + } + } + ] + } + ] + } + ] +}