aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Duda <michal.duda@sonarsource.com>2019-04-18 09:44:16 +0200
committersonartech <sonartech@sonarsource.com>2019-05-07 09:54:21 +0200
commitc240fefe791c667718c14c6eb9c389f1bc7f39b2 (patch)
treefac7cc9984e6afcbbf62d105d0fda4aa3583b241
parentc63d184ee33dc15ce744751aeaf323b016f179c1 (diff)
downloadsonarqube-c240fefe791c667718c14c6eb9c389f1bc7f39b2.tar.gz
sonarqube-c240fefe791c667718c14c6eb9c389f1bc7f39b2.zip
SONAR-11983 new "sonarsource" security report
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/es/MigrationEsClient.java10
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMapping.java43
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77.java2
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMappingTest.java59
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77Test.java2
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueDoc.java9
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java2
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java2
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardHelper.java36
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java23
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/MigrationEsClientImpl.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/securityreport/ws/ShowAction.java67
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java64
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/es/MigrationEsClientImplTest.java34
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/securityreport/ws/ShowActionTest.java72
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityNoCwe.json205
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityWithCwe.json226
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java1
19 files changed, 768 insertions, 115 deletions
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/es/MigrationEsClient.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/es/MigrationEsClient.java
index 33fd72df281..cf2e9a88c70 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/es/MigrationEsClient.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/es/MigrationEsClient.java
@@ -25,4 +25,14 @@ public interface MigrationEsClient {
* This method is re-entrant and does not fail if indexName or otherIndexNames do not exist
*/
void deleteIndexes(String name, String... otherNames);
+
+ /**
+ * Adds a new mapping to an existing elasticsearch index
+ *
+ * @param index name of the index that the mapping is added to
+ * @param type document type in the index
+ * @param mappingName name of the new mapping
+ * @param mappingType type of the new mapping
+ */
+ void addMappingToExistingIndex(String index, String type, String mappingName, String mappingType);
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMapping.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMapping.java
new file mode 100644
index 00000000000..833e007d8b7
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMapping.java
@@ -0,0 +1,43 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.platform.db.migration.version.v77;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.es.MigrationEsClient;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+@SupportsBlueGreen
+public class AddSonarsourceSecurityElasticsearchMapping extends DdlChange {
+
+ private final MigrationEsClient migrationEsClient;
+
+ public AddSonarsourceSecurityElasticsearchMapping(Database db, MigrationEsClient migrationEsClient) {
+ super(db);
+ this.migrationEsClient = migrationEsClient;
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ migrationEsClient.addMappingToExistingIndex("issues", "auth", "sonarsourceSecurity", "keyword");
+ }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77.java
index 92c5e0d9e84..6a338620b6b 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77.java
@@ -38,6 +38,6 @@ public class DbVersion77 implements DbVersion {
.add(2609, "Delete exceeding favorites when there are more than 100 for a user", DeleteFavoritesExceedingOneHundred.class)
.add(2610, "Truncate ES_QUEUE table content", TruncateEsQueue.class)
.add(2611, "Add SNAPSHOTS.BUILD_STRING", AddBuildStringToSnapshot.class)
- ;
+ .add(2612, "Add 'sonarsourceSecurity' mapping to elasticsearch index 'issues'", AddSonarsourceSecurityElasticsearchMapping.class);
}
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMappingTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMappingTest.java
new file mode 100644
index 00000000000..9a863ed93ba
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/AddSonarsourceSecurityElasticsearchMappingTest.java
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.platform.db.migration.version.v77;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.es.MigrationEsClient;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class AddSonarsourceSecurityElasticsearchMappingTest {
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createEmpty();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private MigrationEsClient esClient = mock(MigrationEsClient.class);
+ private AddSonarsourceSecurityElasticsearchMapping underTest = new AddSonarsourceSecurityElasticsearchMapping(db.database(), esClient);
+
+ @Test
+ public void migration_adds_new_issues_mapping() throws SQLException {
+ underTest.execute();
+
+ verify(esClient).addMappingToExistingIndex("issues", "auth", "sonarsourceSecurity", "keyword");
+ }
+
+ public void migration_is_reentrant() throws SQLException {
+ underTest.execute();
+
+ underTest.execute();
+
+ verify(esClient).addMappingToExistingIndex("issues", "auth", "sonarsourceSecurity", "keyword");
+ }
+
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77Test.java
index 001eef0e521..802d22d59a3 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77Test.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v77/DbVersion77Test.java
@@ -36,7 +36,7 @@ public class DbVersion77Test {
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 11);
+ verifyMigrationCount(underTest, 12);
}
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueDoc.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueDoc.java
index 406133e9657..2e0e526d7a2 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueDoc.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueDoc.java
@@ -314,4 +314,13 @@ public class IssueDoc extends BaseDoc {
return this;
}
+ @CheckForNull
+ public Collection<String> getSonarSourceSecurityCategories() {
+ return getNullableField(IssueIndexDefinition.FIELD_ISSUE_SONARSOURCE_SECURITY);
+ }
+
+ public IssueDoc setSonarSourceSecurityCategories(@Nullable Collection<String> c) {
+ setField(IssueIndexDefinition.FIELD_ISSUE_SONARSOURCE_SECURITY, c);
+ return this;
+ }
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
index 04b24d58e79..aafb2941f8e 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
@@ -99,6 +99,7 @@ public class IssueIndexDefinition implements IndexDefinition {
public static final String FIELD_ISSUE_OWASP_TOP_10 = "owaspTop10";
public static final String FIELD_ISSUE_SANS_TOP_25 = "sansTop25";
public static final String FIELD_ISSUE_CWE = "cwe";
+ public static final String FIELD_ISSUE_SONARSOURCE_SECURITY = "sonarsourceSecurity";
private final Configuration config;
private final boolean enableSource;
@@ -159,5 +160,6 @@ public class IssueIndexDefinition implements IndexDefinition {
mapping.keywordFieldBuilder(FIELD_ISSUE_OWASP_TOP_10).disableNorms().build();
mapping.keywordFieldBuilder(FIELD_ISSUE_SANS_TOP_25).disableNorms().build();
mapping.keywordFieldBuilder(FIELD_ISSUE_CWE).disableNorms().build();
+ mapping.keywordFieldBuilder(FIELD_ISSUE_SONARSOURCE_SECURITY).disableNorms().build();
}
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
index 0fd7c543979..022a91f5281 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
@@ -47,6 +47,7 @@ import static org.sonar.server.issue.index.SecurityStandardHelper.getCwe;
import static org.sonar.server.issue.index.SecurityStandardHelper.getOwaspTop10;
import static org.sonar.server.issue.index.SecurityStandardHelper.getSansTop25;
import static org.sonar.server.issue.index.SecurityStandardHelper.getSecurityStandards;
+import static org.sonar.server.issue.index.SecurityStandardHelper.getSonarSourceSecurityCategories;
/**
* Scrolls over table ISSUES and reads documents to populate
@@ -237,6 +238,7 @@ class IssueIteratorForSingleChunk implements IssueIterator {
List<String> cwe = getCwe(standards);
doc.setCwe(cwe);
doc.setSansTop25(getSansTop25(cwe));
+ doc.setSonarSourceSecurityCategories(getSonarSourceSecurityCategories(cwe));
return doc;
}
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardHelper.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardHelper.java
index 77dde6d4674..8c445fb9a8e 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardHelper.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardHelper.java
@@ -47,6 +47,30 @@ public class SecurityStandardHelper {
private static final Set<String> RISKY_CWE = new HashSet<>(asList("120", "22", "494", "829", "676", "131", "134", "190"));
private static final Set<String> POROUS_CWE = new HashSet<>(asList("306", "862", "798", "311", "807", "250", "863", "732", "327", "307", "759"));
+
+ public static final Map<String, List<String>> SONARSOURCE_CWE_MAPPING = ImmutableMap.<String, List<String>>builder()
+ .put("sql-injection", asList("89", "564"))
+ .put("command-injection", asList("78", "77"))
+ .put("path-traversal-injection", singletonList("22"))
+ .put("ldap-injection", singletonList("90"))
+ .put("xpath-injection", singletonList("643"))
+ .put("expression-lang-injection", singletonList("917"))
+ .put("rce", singletonList("94"))
+ .put("dos", singletonList("400"))
+ .put("ssrf", singletonList("918"))
+ .put("csrf", singletonList("352"))
+ .put("xss", asList("79", "80", "81", "82", "83", "84", "85", "86", "87"))
+ .put("log-injection", singletonList("117"))
+ .put("http-response-splitting", singletonList("113"))
+ .put("open-redirect", singletonList("601"))
+ .put("xxe", asList("611", "827"))
+ .put("object-injection", singletonList("470"))
+ .put("weak-cryptography", asList("326", "295", "326", "327", "297", "780", "328", "327"))
+ .put("auth", asList("798", "640", "620", "549", "522", "521", "263", "262", "261", "259", "522", "284"))
+ .put("insecure-conf", asList("102", "489"))
+ .put("file-manipulation", asList("97", "73"))
+ .build();
+
public static final Map<String, Set<String>> SANS_TOP_25_CWE_MAPPING = ImmutableMap.of(
SANS_TOP_25_INSECURE_INTERACTION, INSECURE_CWE,
SANS_TOP_25_RISKY_RESOURCE, RISKY_CWE,
@@ -70,6 +94,14 @@ public class SecurityStandardHelper {
.collect(toList());
}
+ public static List<String> getSonarSourceSecurityCategories(Collection<String> cwe) {
+ return SONARSOURCE_CWE_MAPPING
+ .keySet()
+ .stream()
+ .filter(k -> cwe.stream().anyMatch(SONARSOURCE_CWE_MAPPING.get(k)::contains))
+ .collect(toList());
+ }
+
public static List<String> getOwaspTop10(Collection<String> securityStandards) {
List<String> result = securityStandards.stream()
.filter(s -> s.startsWith(OWASP_TOP10_PREFIX))
@@ -90,6 +122,10 @@ public class SecurityStandardHelper {
return getSansTop25(getCwe(getSecurityStandards(securityStandards)));
}
+ public static List<String> getSonarSourceSecurityCategories(String securityStandards) {
+ return getSonarSourceSecurityCategories(getCwe(getSecurityStandards(securityStandards)));
+ }
+
public static List<String> getOwaspTop10(String securityStandards) {
return getOwaspTop10(getSecurityStandards(securityStandards));
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java b/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java
index 7a5a03fe351..dcb49f8c81a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java
@@ -24,7 +24,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
-import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
@@ -34,7 +33,6 @@ import org.sonar.api.config.Configuration;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.process.ProcessProperties;
import org.sonar.server.es.metadata.EsDbCompatibility;
import org.sonar.server.es.metadata.MetadataIndex;
import org.sonar.server.es.metadata.MetadataIndexDefinition;
@@ -85,26 +83,13 @@ public class IndexCreator implements Startable {
// create indices that do not exist or that have a new definition (different mapping, cluster enabled, ...)
for (BuiltIndex<?> builtIndex : definitions.getIndices().values()) {
Index index = builtIndex.getMainType().getIndex();
- String indexName = index.getName();
boolean exists = client.prepareIndicesExist(index).get().isExists();
- if (exists && !builtIndex.getMainType().equals(metadataMainType) && hasDefinitionChange(builtIndex)) {
- verifyNotBlueGreenDeployment(indexName);
- LOGGER.info("Delete Elasticsearch index {} (structure changed)", indexName);
- deleteIndex(indexName);
- exists = false;
- }
if (!exists) {
createIndex(builtIndex, true);
}
}
}
- private void verifyNotBlueGreenDeployment(String indexToBeDeleted) {
- if (configuration.getBoolean(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey()).orElse(false)) {
- throw new IllegalStateException("Blue/green deployment is not supported. Elasticsearch index [" + indexToBeDeleted + "] changed and needs to be dropped.");
- }
- }
-
@Override
public void stop() {
// nothing to do
@@ -145,14 +130,6 @@ public class IndexCreator implements Startable {
client.nativeClient().admin().indices().prepareDelete(indexName).get();
}
- private boolean hasDefinitionChange(BuiltIndex<?> index) {
- return metadataIndex.getHash(index.getMainType().getIndex())
- .map(hash -> {
- String defHash = IndexDefinitionHash.of(index);
- return !StringUtils.equals(hash, defHash);
- }).orElse(true);
- }
-
private void checkDbCompatibility(Collection<BuiltIndex> definitions) {
List<String> existingIndices = loadExistingIndicesExceptMetadata(definitions);
if (!existingIndices.isEmpty()) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/MigrationEsClientImpl.java b/server/sonar-server/src/main/java/org/sonar/server/es/MigrationEsClientImpl.java
index fb9c425a2cd..44e3fc96c1f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/es/MigrationEsClientImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/MigrationEsClientImpl.java
@@ -28,6 +28,8 @@ import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.server.platform.db.migration.es.MigrationEsClient;
+import static java.lang.String.format;
+
public class MigrationEsClientImpl implements MigrationEsClient {
private final EsClient client;
@@ -45,6 +47,18 @@ public class MigrationEsClientImpl implements MigrationEsClient {
.forEach(this::deleteIndex);
}
+ @Override
+ public void addMappingToExistingIndex(String index, String type, String mappingName, String mappingType) {
+ IndexStats stats = client.nativeClient().admin().indices().prepareStats().get().getIndex(index);
+ if (stats != null) {
+ Loggers.get(getClass()).info("Add mapping [{}] to Elasticsearch index [{}]", mappingName, index);
+ client.nativeClient().admin().indices().preparePutMapping(index)
+ .setType(type)
+ .setSource(mappingName, format("type=%s", mappingType))
+ .get();
+ }
+ }
+
private void deleteIndex(String index) {
Loggers.get(getClass()).info("Drop Elasticsearch index [{}]", index);
client.nativeClient().admin().indices().prepareDelete(index).get();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
index e4dbb57dcd6..47efb7633a8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
@@ -145,6 +145,7 @@ import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_RULE
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SANS_TOP_25;
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SEVERITY;
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE;
+import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SONARSOURCE_SECURITY;
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_STATUS;
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_TAGS;
import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_TYPE;
@@ -852,6 +853,17 @@ public class IssueIndex {
return processSecurityReportSearchResults(request, includeCwe);
}
+ public List<SecurityStandardCategoryStatistics> getSonarSourceReport(String projectUuid, boolean isViewOrApp, boolean includeCwe) {
+ SearchRequestBuilder request = prepareNonClosedVulnerabilitiesAndHotspotSearch(projectUuid, isViewOrApp);
+ SecurityStandardHelper.SONARSOURCE_CWE_MAPPING.keySet().forEach(sansCategory -> {
+ AggregationBuilder sansCategoryAggs = AggregationBuilders
+ .filter(sansCategory, boolQuery()
+ .filter(termQuery(FIELD_ISSUE_SONARSOURCE_SECURITY, sansCategory)));
+ request.addAggregation(addSecurityReportSubAggregations(sansCategoryAggs, includeCwe));
+ });
+ return processSecurityReportSearchResults(request, includeCwe);
+ }
+
public List<SecurityStandardCategoryStatistics> getOwaspTop10Report(String projectUuid, boolean isViewOrApp, boolean includeCwe) {
SearchRequestBuilder request = prepareNonClosedVulnerabilitiesAndHotspotSearch(projectUuid, isViewOrApp);
Stream.concat(IntStream.rangeClosed(1, 10).mapToObj(i -> "a" + i), Stream.of(UNKNOWN_STANDARD)).forEach(owaspCategory -> {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/securityreport/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/securityreport/ws/ShowAction.java
index 2501905e7e7..143da15a107 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/securityreport/ws/ShowAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/securityreport/ws/ShowAction.java
@@ -38,6 +38,7 @@ import org.sonar.db.rule.RuleDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.SecurityStandardCategoryStatistics;
+import org.sonar.server.issue.index.SecurityStandardHelper;
import org.sonar.server.qualityprofile.QPMeasureData;
import org.sonar.server.qualityprofile.QualityProfile;
import org.sonar.server.user.UserSession;
@@ -54,12 +55,15 @@ import static org.sonar.server.issue.index.SecurityStandardHelper.UNKNOWN_STANDA
import static org.sonar.server.issue.index.SecurityStandardHelper.getCwe;
import static org.sonar.server.issue.index.SecurityStandardHelper.getOwaspTop10;
import static org.sonar.server.issue.index.SecurityStandardHelper.getSansTop25;
+import static org.sonar.server.issue.index.SecurityStandardHelper.getSonarSourceSecurityCategories;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SANS_TOP_25;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SONARSOURCE_SECURITY;
public class ShowAction implements SecurityReportsWsAction {
+ private static final String UNSUPPORTED_STANDARD_MSG = "Unsupported standard: '%s'";
private static final String PARAM_PROJECT = "project";
private static final String PARAM_BRANCH = "branch";
private static final String PARAM_INCLUDE_DISTRIBUTION = "includeDistribution";
@@ -96,7 +100,7 @@ public class ShowAction implements SecurityReportsWsAction {
.setExampleValue("branch-2.0");
action.createParam(PARAM_STANDARD)
.setDescription("Security standard")
- .setPossibleValues(PARAM_OWASP_TOP_10, PARAM_SANS_TOP_25)
+ .setPossibleValues(PARAM_OWASP_TOP_10, PARAM_SANS_TOP_25, PARAM_SONARSOURCE_SECURITY)
.setRequired(true);
action.createParam(PARAM_INCLUDE_DISTRIBUTION)
.setDescription("To return CWE distribution")
@@ -142,8 +146,13 @@ public class ShowAction implements SecurityReportsWsAction {
completeStatistics(sansTop25Report, projectDto, standard, includeCwe);
writeResponse(request, response, sansTop25Report);
break;
+ case PARAM_SONARSOURCE_SECURITY:
+ List<SecurityStandardCategoryStatistics> sonarSourceReport = issueIndex.getSonarSourceReport(projectDto.uuid(), isViewOrApp, includeCwe);
+ completeStatistics(sonarSourceReport, projectDto, standard, includeCwe);
+ writeResponse(request, response, sonarSourceReport);
+ break;
default:
- throw new IllegalArgumentException("Unsupported standard: '" + standard + "'");
+ throw new IllegalArgumentException(String.format(UNSUPPORTED_STANDARD_MSG, standard));
}
}
@@ -157,27 +166,30 @@ public class ShowAction implements SecurityReportsWsAction {
List<OrgActiveRuleDto> activeRuleDtos = dbClient.activeRuleDao().selectByTypeAndProfileUuids(dbSession,
asList(RuleType.SECURITY_HOTSPOT.getDbConstant(), RuleType.VULNERABILITY.getDbConstant()),
qualityProfiles.stream()
- .map(QualityProfile::getQpKey)
- .collect(toList()));
+ .map(QualityProfile::getQpKey)
+ .collect(toList()));
Multimap<String, OrgActiveRuleDto> activeRulesByCategory = ArrayListMultimap.create();
activeRuleDtos
.forEach(r -> {
- List<String> cwe = getCwe(r.getSecurityStandards());
- if (includeCwe) {
- cwe.forEach(s -> activeRulesByCategory.put(s, r));
- }
- switch (standard) {
- case PARAM_OWASP_TOP_10:
- getOwaspTop10(r.getSecurityStandards()).forEach(s -> activeRulesByCategory.put(s, r));
- break;
- case PARAM_SANS_TOP_25:
- getSansTop25(cwe).forEach(s -> activeRulesByCategory.put(s, r));
- break;
- default:
- throw new IllegalArgumentException("Unsupported standard: '" + standard + "'");
- }
- });
+ List<String> cwe = getCwe(r.getSecurityStandards());
+ if (includeCwe) {
+ cwe.forEach(s -> activeRulesByCategory.put(s, r));
+ }
+ switch (standard) {
+ case PARAM_OWASP_TOP_10:
+ getOwaspTop10(r.getSecurityStandards()).forEach(s -> activeRulesByCategory.put(s, r));
+ break;
+ case PARAM_SANS_TOP_25:
+ getSansTop25(cwe).forEach(s -> activeRulesByCategory.put(s, r));
+ break;
+ case PARAM_SONARSOURCE_SECURITY:
+ SecurityStandardHelper.getSonarSourceSecurityCategories(cwe).forEach(s -> activeRulesByCategory.put(s, r));
+ break;
+ default:
+ throw new IllegalArgumentException(String.format(UNSUPPORTED_STANDARD_MSG, standard));
+ }
+ });
List<RuleDto> ruleDtos = dbClient.ruleDao().selectByTypeAndLanguages(dbSession,
project.getOrganizationUuid(),
@@ -200,19 +212,22 @@ public class ShowAction implements SecurityReportsWsAction {
case PARAM_SANS_TOP_25:
getSansTop25(cwe).forEach(s -> rulesByCategory.put(s, r));
break;
+ case PARAM_SONARSOURCE_SECURITY:
+ getSonarSourceSecurityCategories(cwe).forEach(s -> rulesByCategory.put(s, r));
+ break;
default:
- throw new IllegalArgumentException("Unsupported standard: '" + standard + "'");
+ throw new IllegalArgumentException(String.format(UNSUPPORTED_STANDARD_MSG, standard));
}
});
input.forEach(c -> {
- c.setTotalRules(rulesByCategory.get(c.getCategory()).size());
- c.setActiveRules(activeRulesByCategory.get(c.getCategory()).size());
- c.getChildren().forEach(child -> {
- child.setTotalRules(rulesByCategory.get(child.getCategory()).size());
- child.setActiveRules(activeRulesByCategory.get(child.getCategory()).size());
- });
+ c.setTotalRules(rulesByCategory.get(c.getCategory()).size());
+ c.setActiveRules(activeRulesByCategory.get(c.getCategory()).size());
+ c.getChildren().forEach(child -> {
+ child.setTotalRules(rulesByCategory.get(child.getCategory()).size());
+ child.setActiveRules(activeRulesByCategory.get(child.getCategory()).size());
});
+ });
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java
index 1575ac315fb..453df3295fe 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.function.Consumer;
import javax.annotation.CheckForNull;
-import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.junit.Rule;
@@ -39,7 +38,6 @@ import org.sonar.server.es.newindex.NewRegularIndex;
import org.sonar.server.es.newindex.SettingsConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
import static org.sonar.server.es.IndexType.main;
import static org.sonar.server.es.newindex.SettingsConfiguration.newBuilder;
@@ -99,61 +97,11 @@ public class IndexCreatorTest {
assertThat(metadataIndex.getInitialized(main(fakersIndex, "faker"))).isFalse();
}
- @Test
- public void recreate_index_on_definition_changes() {
- // v1
- startNewCreator(new FakeIndexDefinition());
-
- IndexMainType fakeIndexType = main(Index.simple("fakes"), "fake");
- String id = "1";
- es.client().prepareIndex(fakeIndexType).setId(id).setSource(new FakeDoc().getFields()).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
- assertThat(es.client().prepareGet(fakeIndexType, id).get().isExists()).isTrue();
-
- // v2
- startNewCreator(new FakeIndexDefinitionV2());
-
- ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappings = mappings();
- MappingMetaData mapping = mappings.get("fakes").get("fake");
- assertThat(countMappingFields(mapping)).isEqualTo(3);
- assertThat(field(mapping, "updatedAt").get("type")).isEqualTo("date");
- assertThat(field(mapping, "newField").get("type")).isEqualTo("integer");
-
- assertThat(es.client().prepareGet(fakeIndexType, id).get().isExists()).isFalse();
- }
-
- @Test
- public void fail_to_recreate_index_on_definition_changes_if_blue_green_deployment() {
- enableBlueGreenDeployment();
-
- // v1
- startNewCreator(new FakeIndexDefinition());
-
- // v2
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Blue/green deployment is not supported. Elasticsearch index [fakes] changed and needs to be dropped.");
-
- startNewCreator(new FakeIndexDefinitionV2());
- }
-
private void enableBlueGreenDeployment() {
settings.setProperty("sonar.blueGreenEnabled", "true");
}
@Test
- public void do_not_recreate_index_on_unchanged_definition() {
- // v1
- startNewCreator(new FakeIndexDefinition());
- IndexMainType fakeIndexType = main(Index.simple("fakes"), "fake");
- String id = "1";
- es.client().prepareIndex(fakeIndexType).setId(id).setSource(new FakeDoc().getFields()).setRefreshPolicy(IMMEDIATE).get();
- assertThat(es.client().prepareGet(fakeIndexType, id).get().isExists()).isTrue();
-
- // v1
- startNewCreator(new FakeIndexDefinition());
- assertThat(es.client().prepareGet(fakeIndexType, id).get().isExists()).isTrue();
- }
-
- @Test
public void delete_existing_indices_if_db_vendor_changed() {
testDeleteOnDbChange(LOG_DB_VENDOR_CHANGED,
c -> c.setHasSameDbVendor(false));
@@ -244,16 +192,4 @@ public class IndexCreatorTest {
.createDateTimeField("updatedAt");
}
}
- private static class FakeIndexDefinitionV2 implements IndexDefinition {
-
- @Override
- public void define(IndexDefinitionContext context) {
- Index index = Index.simple("fakes");
- NewRegularIndex newIndex = context.create(index, SETTINGS_CONFIGURATION);
- newIndex.createTypeMapping(IndexType.main(index, "fake"))
- .keywordFieldBuilder("key").build()
- .createDateTimeField("updatedAt")
- .createIntegerField("newField");
- }
- }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/MigrationEsClientImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/es/MigrationEsClientImplTest.java
index 7443ba1dda1..e46f370c561 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/es/MigrationEsClientImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/es/MigrationEsClientImplTest.java
@@ -20,6 +20,7 @@
package org.sonar.server.es;
import java.util.Iterator;
+import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.internal.MapSettings;
@@ -66,6 +67,39 @@ public class MigrationEsClientImplTest {
.doesNotContain("Drop Elasticsearch index [xxx]");
}
+ @Test
+ public void add_mapping_to_existing_index() {
+ underTest.addMappingToExistingIndex("as", "s", "newMapping", "keyword");
+
+ GetFieldMappingsResponse response = es.client().nativeClient().admin().indices().prepareGetFieldMappings("as")
+ .setTypes("s")
+ .setFields("newMapping")
+ .get();
+ assertThat(response).isNotNull();
+ assertThat(response.mappings()).hasSize(1);
+ assertThat(response.mappings().get("as")).isNotNull();
+ assertThat(response.mappings().get("as").get("s")).isNotNull();
+ assertThat(response.mappings().get("as").get("s").get("newMapping").fullName()).isEqualTo("newMapping");
+ assertThat(logTester.logs(LoggerLevel.INFO))
+ .contains("Add mapping [newMapping] to Elasticsearch index [as]");
+ }
+
+ @Test
+ public void add_mapping_to_non_existing_index() {
+ underTest.addMappingToExistingIndex("yyyy", "s", "newMapping", "keyword");
+
+ GetFieldMappingsResponse response = es.client().nativeClient().admin().indices().prepareGetFieldMappings("as")
+ .setTypes("s")
+ .setFields("newMapping")
+ .get();
+ assertThat(response).isNotNull();
+ assertThat(response.mappings()).hasSize(1);
+ assertThat(response.mappings().get("as")).isNotNull();
+ assertThat(response.mappings().get("as").get("s")).isNotNull();
+ assertThat(response.mappings().get("as").get("s").get("newMapping").fullName()).isEqualTo("");
+ assertThat(logTester.logs(LoggerLevel.INFO)).isEmpty();
+ }
+
private Iterator<String> loadExistingIndices() {
return es.client().nativeClient().admin().indices().prepareGetMappings().get().mappings().keysIt();
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/securityreport/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/securityreport/ws/ShowActionTest.java
index 1649f62336d..b432971c256 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/securityreport/ws/ShowActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/securityreport/ws/ShowActionTest.java
@@ -306,6 +306,78 @@ public class ShowActionTest {
.isSimilarTo(this.getClass().getResource("ShowActionTest/sansWithCwe.json"));
}
+ @Test
+ public void sonarsource_security_without_cwe() {
+ userSessionRule.addProjectPermission(UserRole.USER, project);
+ indexPermissions();
+ ComponentDto file = insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
+ IssueDto issue1 = newIssue(rule1, project, file)
+ .setStatus("OPEN")
+ .setSeverity("MAJOR")
+ .setType(RuleType.VULNERABILITY);
+ IssueDto issue2 = newIssue(rule1, project, file)
+ .setStatus("OPEN")
+ .setSeverity("MAJOR")
+ .setType(RuleType.SECURITY_HOTSPOT);
+ IssueDto issue3 = newIssue(rule1, project, file)
+ .setStatus(Issue.STATUS_RESOLVED)
+ .setResolution(Issue.RESOLUTION_FIXED)
+ .setSeverity("MAJOR")
+ .setType(RuleType.SECURITY_HOTSPOT);
+ IssueDto issue4 = newIssue(rule1, project, file)
+ .setStatus(Issue.STATUS_RESOLVED)
+ .setResolution(Issue.RESOLUTION_WONT_FIX)
+ .setSeverity("MAJOR")
+ .setType(RuleType.SECURITY_HOTSPOT);
+ dbClient.issueDao().insert(session, issue1, issue2, issue3, issue4);
+ session.commit();
+ indexIssues();
+
+ assertJson(ws.newRequest()
+ .setParam("standard", "sonarsourceSecurity")
+ .setParam("project", project.getKey())
+ .setParam("includeDistribution", "false")
+ .execute().getInput())
+ .withStrictArrayOrder()
+ .isSimilarTo(this.getClass().getResource("ShowActionTest/sonarsourceSecurityNoCwe.json"));
+ }
+
+ @Test
+ public void sonarsource_security_with_cwe() {
+ userSessionRule.addProjectPermission(UserRole.USER, project);
+ indexPermissions();
+ ComponentDto file = insertComponent(newFileDto(project, null, "FILE_ID").setDbKey("FILE_KEY"));
+ IssueDto issue1 = newIssue(rule1, project, file)
+ .setStatus("OPEN")
+ .setSeverity("MAJOR")
+ .setType(RuleType.VULNERABILITY);
+ IssueDto issue2 = newIssue(rule1, project, file)
+ .setStatus("OPEN")
+ .setSeverity("MAJOR")
+ .setType(RuleType.SECURITY_HOTSPOT);
+ IssueDto issue3 = newIssue(rule1, project, file)
+ .setStatus(Issue.STATUS_RESOLVED)
+ .setResolution(Issue.RESOLUTION_FIXED)
+ .setSeverity("MAJOR")
+ .setType(RuleType.SECURITY_HOTSPOT);
+ IssueDto issue4 = newIssue(rule1, project, file)
+ .setStatus(Issue.STATUS_RESOLVED)
+ .setResolution(Issue.RESOLUTION_WONT_FIX)
+ .setSeverity("MAJOR")
+ .setType(RuleType.SECURITY_HOTSPOT);
+ dbClient.issueDao().insert(session, issue1, issue2, issue3, issue4);
+ session.commit();
+ indexIssues();
+
+ assertJson(ws.newRequest()
+ .setParam("standard", "sonarsourceSecurity")
+ .setParam("project", project.getKey())
+ .setParam("includeDistribution", "true")
+ .execute().getInput())
+ .withStrictArrayOrder()
+ .isSimilarTo(this.getClass().getResource("ShowActionTest/sonarsourceSecurityWithCwe.json"));
+ }
+
private RuleDefinitionDto newRule(Set tags) {
RuleDefinitionDto rule = RuleTesting.newRule()
.setType(RuleType.SECURITY_HOTSPOT)
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityNoCwe.json b/server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityNoCwe.json
new file mode 100644
index 00000000000..d953503cade
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityNoCwe.json
@@ -0,0 +1,205 @@
+{
+ "categories": [
+ {
+ "category": "ldap-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "object-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "ssrf",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "insecure-conf",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "xxe",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "auth",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "xpath-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "weak-cryptography",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "dos",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "open-redirect",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "log-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "csrf",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "sql-injection",
+ "vulnerabilities": 1,
+ "vulnerabilityRating": 3,
+ "toReviewSecurityHotspots": 1,
+ "openSecurityHotspots": 1,
+ "wontFixSecurityHotspots": 1,
+ "distribution": [],
+ "activeRules": 1,
+ "totalRules": 1
+ },
+ {
+ "category": "file-manipulation",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "expression-lang-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "rce",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "xss",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "path-traversal-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 1,
+ "totalRules": 1
+ },
+ {
+ "category": "command-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "http-response-splitting",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ }
+ ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityWithCwe.json b/server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityWithCwe.json
new file mode 100644
index 00000000000..4ea949d604f
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/securityreport/ws/ShowActionTest/sonarsourceSecurityWithCwe.json
@@ -0,0 +1,226 @@
+{
+ "categories": [
+ {
+ "category": "ldap-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "object-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "ssrf",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "insecure-conf",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "xxe",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "auth",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "xpath-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "weak-cryptography",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "dos",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "open-redirect",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "log-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "csrf",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "sql-injection",
+ "vulnerabilities": 1,
+ "vulnerabilityRating": 3,
+ "toReviewSecurityHotspots": 1,
+ "openSecurityHotspots": 1,
+ "wontFixSecurityHotspots": 1,
+ "distribution": [
+ {
+ "cwe": "89",
+ "vulnerabilities": 1,
+ "vulnerabilityRating": 3,
+ "toReviewSecurityHotspots": 1,
+ "openSecurityHotspots": 1,
+ "wontFixSecurityHotspots": 1,
+ "activeRules": 1,
+ "totalRules": 1
+ },
+ {
+ "cwe": "123",
+ "vulnerabilities": 1,
+ "vulnerabilityRating": 3,
+ "toReviewSecurityHotspots": 1,
+ "openSecurityHotspots": 1,
+ "wontFixSecurityHotspots": 1,
+ "activeRules": 1,
+ "totalRules": 1
+ }
+ ],
+ "activeRules": 1,
+ "totalRules": 1
+ },
+ {
+ "category": "file-manipulation",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "expression-lang-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "rce",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "xss",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "path-traversal-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 1,
+ "totalRules": 1
+ },
+ {
+ "category": "command-injection",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ },
+ {
+ "category": "http-response-splitting",
+ "vulnerabilities": 0,
+ "toReviewSecurityHotspots": 0,
+ "openSecurityHotspots": 0,
+ "wontFixSecurityHotspots": 0,
+ "distribution": [],
+ "activeRules": 0,
+ "totalRules": 0
+ }
+ ]
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java
index 551ee1e4130..4fce187d28d 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java
@@ -85,6 +85,7 @@ public class IssuesWsParameters {
public static final String PARAM_TYPES = "types";
public static final String PARAM_OWASP_TOP_10 = "owaspTop10";
public static final String PARAM_SANS_TOP_25 = "sansTop25";
+ public static final String PARAM_SONARSOURCE_SECURITY = "sonarsourceSecurity";
public static final String PARAM_CWE = "cwe";
public static final String PARAM_ASSIGNED = "assigned";
public static final String PARAM_HIDE_COMMENTS = "hideComments";