diff options
author | Michal Duda <michal.duda@sonarsource.com> | 2019-04-18 09:44:16 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-05-07 09:54:21 +0200 |
commit | c240fefe791c667718c14c6eb9c389f1bc7f39b2 (patch) | |
tree | fac7cc9984e6afcbbf62d105d0fda4aa3583b241 | |
parent | c63d184ee33dc15ce744751aeaf323b016f179c1 (diff) | |
download | sonarqube-c240fefe791c667718c14c6eb9c389f1bc7f39b2.tar.gz sonarqube-c240fefe791c667718c14c6eb9c389f1bc7f39b2.zip |
SONAR-11983 new "sonarsource" security report
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"; |