aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKlaudio Sinani <klaudio.sinani@sonarsource.com>2022-11-10 17:58:30 +0100
committersonartech <sonartech@sonarsource.com>2022-11-15 20:02:59 +0000
commit8f9eb2135150b0a77aea302e17afa4ba238560ce (patch)
tree1412fb1e771c35d6bf149f54b3083ef3d18cd787
parent53f94935f393750ba08a7e1fa00742acadbadafb (diff)
downloadsonarqube-8f9eb2135150b0a77aea302e17afa4ba238560ce.tar.gz
sonarqube-8f9eb2135150b0a77aea302e17afa4ba238560ce.zip
SONAR-17560 Introduce SARIF version validation
-rw-r--r--sonar-core/src/main/java/org/sonar/core/sarif/Sarif210.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializerImpl.java6
-rw-r--r--sonar-core/src/main/java/org/sonar/core/sarif/SarifVersionValidator.java50
-rw-r--r--sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java16
-rw-r--r--sonar-core/src/test/java/org/sonar/core/sarif/SarifVersionValidatorTest.java89
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/sarif/unsupported-sarif-version-abc.json107
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/SarifIssuesImportSensorTest.java4
7 files changed, 267 insertions, 7 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/sarif/Sarif210.java b/sonar-core/src/main/java/org/sonar/core/sarif/Sarif210.java
index 0df616af2e2..df4247bb567 100644
--- a/sonar-core/src/main/java/org/sonar/core/sarif/Sarif210.java
+++ b/sonar-core/src/main/java/org/sonar/core/sarif/Sarif210.java
@@ -19,13 +19,11 @@
*/
package org.sonar.core.sarif;
-import com.google.common.annotations.VisibleForTesting;
import com.google.gson.annotations.SerializedName;
import java.util.Set;
public class Sarif210 {
- @VisibleForTesting
public static final String SARIF_VERSION = "2.1.0";
@SerializedName("version")
diff --git a/sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializerImpl.java b/sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializerImpl.java
index 3f33419cb87..091953b1c87 100644
--- a/sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializerImpl.java
+++ b/sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializerImpl.java
@@ -60,11 +60,15 @@ public class SarifSerializerImpl implements SarifSerializer {
@Override
public Sarif210 deserialize(Path reportPath) {
try (Reader reader = newBufferedReader(reportPath, UTF_8)) {
- return gson.fromJson(reader, Sarif210.class);
+ Sarif210 sarif = gson.fromJson(reader, Sarif210.class);
+ SarifVersionValidator.validateSarifVersion(sarif.getVersion());
+ return sarif;
} catch (JsonIOException | IOException e) {
throw new IllegalStateException(format(SARIF_REPORT_ERROR, reportPath), e);
} catch (JsonSyntaxException e) {
throw new IllegalStateException(format(SARIF_JSON_SYNTAX_ERROR, reportPath), e);
+ } catch (IllegalStateException e) {
+ throw new IllegalStateException(e.getMessage(), e);
}
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/sarif/SarifVersionValidator.java b/sonar-core/src/main/java/org/sonar/core/sarif/SarifVersionValidator.java
new file mode 100644
index 00000000000..e82e1a4b8e1
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/sarif/SarifVersionValidator.java
@@ -0,0 +1,50 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.core.sarif;
+
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+import static java.lang.String.format;
+import static org.sonar.core.sarif.Sarif210.SARIF_VERSION;
+
+public class SarifVersionValidator {
+ public static final Set<String> SUPPORTED_SARIF_VERSIONS = Set.of(SARIF_VERSION);
+ public static final String UNSUPPORTED_VERSION_MESSAGE_TEMPLATE = "Version [%s] of SARIF is not supported";
+
+ private SarifVersionValidator() {}
+
+ public static void validateSarifVersion(@Nullable String version) {
+ if (!isSupportedSarifVersion(version)) {
+ throw new IllegalStateException(composeUnsupportedVersionMessage(version));
+ }
+ }
+
+ private static boolean isSupportedSarifVersion(@Nullable String version) {
+ return Optional.ofNullable(version)
+ .filter(SUPPORTED_SARIF_VERSIONS::contains)
+ .isPresent();
+ }
+
+ private static String composeUnsupportedVersionMessage(@Nullable String version) {
+ return format(UNSUPPORTED_VERSION_MESSAGE_TEMPLATE, version);
+ }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java b/sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java
index 8350226ce75..fbc0e080ece 100644
--- a/sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java
@@ -28,10 +28,12 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
+import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
+import static org.sonar.core.sarif.SarifVersionValidator.UNSUPPORTED_VERSION_MESSAGE_TEMPLATE;
@RunWith(MockitoJUnitRunner.class)
public class SarifSerializerTest {
@@ -67,7 +69,7 @@ public class SarifSerializerTest {
assertThatThrownBy(() -> serializer.deserialize(sarif))
.isInstanceOf(IllegalStateException.class)
- .hasMessage(String.format("Failed to read SARIF report at '%s'", file));
+ .hasMessage(format("Failed to read SARIF report at '%s'", file));
}
@Test
@@ -77,7 +79,17 @@ public class SarifSerializerTest {
assertThatThrownBy(() -> serializer.deserialize(sarif))
.isInstanceOf(IllegalStateException.class)
- .hasMessage(String.format("Failed to read SARIF report at '%s': invalid JSON syntax", sarif));
+ .hasMessage(format("Failed to read SARIF report at '%s': invalid JSON syntax", sarif));
+ }
+
+ @Test
+ public void deserialize_shouldFail_whenSarifVersionIsNotSupported() throws URISyntaxException {
+ URL sarifResource = requireNonNull(getClass().getResource("unsupported-sarif-version-abc.json"));
+ Path sarif = Paths.get(sarifResource.toURI());
+
+ assertThatThrownBy(() -> serializer.deserialize(sarif))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessage(format(UNSUPPORTED_VERSION_MESSAGE_TEMPLATE, "A.B.C"));
}
private void verifySarif(Sarif210 deserializationResult) {
diff --git a/sonar-core/src/test/java/org/sonar/core/sarif/SarifVersionValidatorTest.java b/sonar-core/src/test/java/org/sonar/core/sarif/SarifVersionValidatorTest.java
new file mode 100644
index 00000000000..4791abeae57
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/sarif/SarifVersionValidatorTest.java
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.core.sarif;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import org.apache.commons.lang.RandomStringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static java.lang.String.format;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.sonar.core.sarif.SarifVersionValidator.SUPPORTED_SARIF_VERSIONS;
+import static org.sonar.core.sarif.SarifVersionValidator.UNSUPPORTED_VERSION_MESSAGE_TEMPLATE;
+
+@RunWith(DataProviderRunner.class)
+public class SarifVersionValidatorTest {
+
+ @Test
+ @UseDataProvider("unsupportedSarifVersions")
+ public void sarif_version_validation_fails_if_version_is_not_supported(String version) {
+ assertThatThrownBy(() -> SarifVersionValidator.validateSarifVersion(version))
+ .isExactlyInstanceOf(IllegalStateException.class)
+ .hasMessage(format(UNSUPPORTED_VERSION_MESSAGE_TEMPLATE, version));
+ }
+
+ @Test
+ @UseDataProvider("supportedSarifVersions")
+ public void sarif_version_validation_succeeds_if_version_is_supported(String version) {
+ assertThatCode(() -> SarifVersionValidator.validateSarifVersion(version))
+ .doesNotThrowAnyException();
+ }
+
+ @DataProvider
+ public static List<String> unsupportedSarifVersions() {
+ List<String> unsupportedVersions = generateRandomUnsupportedSemanticVersions(10);
+ unsupportedVersions.add(null);
+ return unsupportedVersions;
+ }
+
+ @DataProvider
+ public static Set<String> supportedSarifVersions() {
+ return SUPPORTED_SARIF_VERSIONS;
+ }
+
+ private static List<String> generateRandomUnsupportedSemanticVersions(int amount) {
+ return Stream
+ .generate(SarifVersionValidatorTest::generateRandomSemanticVersion)
+ .takeWhile(SarifVersionValidatorTest::isUnsupportedVersion)
+ .limit(amount)
+ .collect(Collectors.toList());
+ }
+
+ private static String generateRandomSemanticVersion() {
+ return IntStream
+ .rangeClosed(1, 3)
+ .mapToObj(x -> RandomStringUtils.randomNumeric(1))
+ .collect(Collectors.joining("."));
+ }
+
+ private static boolean isUnsupportedVersion(String version) {
+ return !SUPPORTED_SARIF_VERSIONS.contains(version);
+ }
+
+}
diff --git a/sonar-core/src/test/resources/org/sonar/core/sarif/unsupported-sarif-version-abc.json b/sonar-core/src/test/resources/org/sonar/core/sarif/unsupported-sarif-version-abc.json
new file mode 100644
index 00000000000..f9962795461
--- /dev/null
+++ b/sonar-core/src/test/resources/org/sonar/core/sarif/unsupported-sarif-version-abc.json
@@ -0,0 +1,107 @@
+{
+ "version": "A.B.C",
+ "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
+ "runs": [
+ {
+ "tool": {
+ "driver": {
+ "name": "SonarQube",
+ "organization": "SonarSource",
+ "semanticVersion": "9.6",
+ "rules": [
+ {
+ "id": "java:S5132",
+ "name": "java:S5132",
+ "shortDescription": {
+ "text": "Make this final static field too."
+ },
+ "fullDescription": {
+ "text": "Make this final static field too."
+ },
+ "help": {
+ "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu."
+ },
+ "properties": {
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ }
+ ]
+ }
+ },
+ "results": [
+ {
+ "ruleId": "java:S5132",
+ "message": {
+ "text": "this is the message"
+ },
+ "locations": [
+ {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "www.google.com",
+ "uriBaseId": "%SRCROOT"
+ },
+ "region": {
+ "startLine": 11,
+ "endLine": 222,
+ "startColumn": 54,
+ "endColumn": 4
+ }
+ }
+ }
+ ],
+ "partialFingerprints": {
+ "primaryLocationLineHash": "thisISTHEHAS"
+ },
+ "codeFlows": [
+ {
+ "threadFlows": [
+ {
+ "locations": [
+ {
+ "location": {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "www.google.com",
+ "uriBaseId": "%SRCROOT"
+ },
+ "region": {
+ "startLine": 11,
+ "endLine": 222,
+ "startColumn": 54,
+ "endColumn": 4
+ }
+ }
+ }
+ },
+ {
+ "location": {
+ "physicalLocation": {
+ "artifactLocation": {
+ "uri": "www.google.com",
+ "uriBaseId": "%SRCROOT"
+ },
+ "region": {
+ "startLine": 22,
+ "endLine": 4323,
+ "startColumn": 545,
+ "endColumn": 4324
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "language": "en-us",
+ "columnKind": "utf16CodeUnits"
+ }
+ ]
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/SarifIssuesImportSensorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/SarifIssuesImportSensorTest.java
index 8d6d10db945..043189f0d6d 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/SarifIssuesImportSensorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/SarifIssuesImportSensorTest.java
@@ -33,8 +33,8 @@ import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.sarif.Sarif210;
import org.sonar.core.sarif.SarifSerializer;
-import static org.mockito.Mockito.doThrow;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -61,7 +61,7 @@ public class SarifIssuesImportSensorTest {
@Rule
public LogTester logTester = new LogTester();
- private SensorContextTester sensorContext = SensorContextTester.create(Path.of("."));
+ private final SensorContextTester sensorContext = SensorContextTester.create(Path.of("."));
@Test
public void execute_single_files() {