aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/es/StickyFacetBuilder.java4
-rw-r--r--server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java32
-rw-r--r--server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java34
-rw-r--r--server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java53
-rw-r--r--server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java68
-rw-r--r--server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java54
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java108
7 files changed, 314 insertions, 39 deletions
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/StickyFacetBuilder.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/StickyFacetBuilder.java
index 9ba5e34a0f5..4fa26148c89 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/es/StickyFacetBuilder.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/es/StickyFacetBuilder.java
@@ -43,7 +43,7 @@ import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
public class StickyFacetBuilder {
private static final int FACET_DEFAULT_MIN_DOC_COUNT = 1;
- private static final int FACET_DEFAULT_SIZE = 10;
+ public static final int FACET_DEFAULT_SIZE = 10;
private static final BucketOrder FACET_DEFAULT_ORDER = BucketOrder.count(false);
/** In some cases the user selects >15 items for one facet. In that case, we want to calculate the doc count for all of them (not just the first 15 items, which would be the
* default for the TermsAggregation). */
@@ -67,7 +67,7 @@ public class StickyFacetBuilder {
}
public AggregationBuilder buildStickyFacet(String fieldName, String facetName, Object... selected) {
- return buildStickyFacet(fieldName, facetName, FACET_DEFAULT_SIZE, t -> t, selected);
+ return buildStickyFacet(fieldName, facetName, FACET_DEFAULT_SIZE, t -> t, selected);
}
public AggregationBuilder buildStickyFacet(String fieldName, String facetName, int size, Object... selected) {
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java
index f2c25324126..fa61b365c6b 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java
@@ -77,10 +77,13 @@ import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
+import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
+import static org.sonar.api.rules.RuleType.VULNERABILITY;
import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES;
import static org.sonar.server.es.EsUtils.optimizeScrollRequest;
import static org.sonar.server.es.EsUtils.scrollIds;
import static org.sonar.server.es.IndexType.FIELD_INDEX_TYPE;
+import static org.sonar.server.es.StickyFacetBuilder.FACET_DEFAULT_SIZE;
import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.ENGLISH_HTML_ANALYZER;
import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SEARCH_GRAMS_ANALYZER;
import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SEARCH_WORDS_ANALYZER;
@@ -281,22 +284,30 @@ public class RuleIndex {
if (isNotEmpty(query.getCwe())) {
filters.put(FIELD_RULE_CWE,
- QueryBuilders.termsQuery(FIELD_RULE_CWE, query.getCwe()));
+ boolQuery()
+ .must(QueryBuilders.termsQuery(FIELD_RULE_CWE, query.getCwe()))
+ .must(QueryBuilders.termsQuery(FIELD_RULE_TYPE, VULNERABILITY.name(), SECURITY_HOTSPOT.name())));
}
if (isNotEmpty(query.getOwaspTop10())) {
filters.put(FIELD_RULE_OWASP_TOP_10,
- QueryBuilders.termsQuery(FIELD_RULE_OWASP_TOP_10, query.getOwaspTop10()));
+ boolQuery()
+ .must(QueryBuilders.termsQuery(FIELD_RULE_OWASP_TOP_10, query.getOwaspTop10()))
+ .must(QueryBuilders.termsQuery(FIELD_RULE_TYPE, VULNERABILITY.name(), SECURITY_HOTSPOT.name())));
}
if (isNotEmpty(query.getSansTop25())) {
filters.put(FIELD_RULE_SANS_TOP_25,
- QueryBuilders.termsQuery(FIELD_RULE_SANS_TOP_25, query.getSansTop25()));
+ boolQuery()
+ .must(QueryBuilders.termsQuery(FIELD_RULE_SANS_TOP_25, query.getSansTop25()))
+ .must(QueryBuilders.termsQuery(FIELD_RULE_TYPE, VULNERABILITY.name(), SECURITY_HOTSPOT.name())));
}
if (isNotEmpty(query.getSonarsourceSecurity())) {
filters.put(FIELD_RULE_SONARSOURCE_SECURITY,
- QueryBuilders.termsQuery(FIELD_RULE_SONARSOURCE_SECURITY, query.getSonarsourceSecurity()));
+ boolQuery()
+ .must(QueryBuilders.termsQuery(FIELD_RULE_SONARSOURCE_SECURITY, query.getSonarsourceSecurity()))
+ .must(QueryBuilders.termsQuery(FIELD_RULE_TYPE, VULNERABILITY.name(), SECURITY_HOTSPOT.name())));
}
if (StringUtils.isNotEmpty(query.getKey())) {
@@ -484,30 +495,43 @@ public class RuleIndex {
addDefaultSecurityFacets(query, options, aggregations, stickyFacetBuilder);
}
+ private static Function<TermsAggregationBuilder, AggregationBuilder> filterSecurityCategories() {
+ return termsAggregation -> AggregationBuilders.filter(
+ "filter_by_rule_types_" + termsAggregation.getName(),
+ termsQuery(FIELD_RULE_TYPE,
+ VULNERABILITY.name(),
+ SECURITY_HOTSPOT.name()))
+ .subAggregation(termsAggregation);
+ }
+
private static void addDefaultSecurityFacets(RuleQuery query, SearchOptions options, Map<String, AggregationBuilder> aggregations,
StickyFacetBuilder stickyFacetBuilder) {
if (options.getFacets().contains(FACET_CWE)) {
Collection<String> categories = query.getCwe();
aggregations.put(FACET_CWE,
stickyFacetBuilder.buildStickyFacet(FIELD_RULE_CWE, FACET_CWE,
+ FACET_DEFAULT_SIZE, filterSecurityCategories(),
(categories == null) ? (new String[0]) : categories.toArray()));
}
if (options.getFacets().contains(FACET_OWASP_TOP_10)) {
Collection<String> categories = query.getOwaspTop10();
aggregations.put(FACET_OWASP_TOP_10,
stickyFacetBuilder.buildStickyFacet(FIELD_RULE_OWASP_TOP_10, FACET_OWASP_TOP_10,
+ FACET_DEFAULT_SIZE, filterSecurityCategories(),
(categories == null) ? (new String[0]) : categories.toArray()));
}
if (options.getFacets().contains(FACET_SANS_TOP_25)) {
Collection<String> categories = query.getSansTop25();
aggregations.put(FACET_SANS_TOP_25,
stickyFacetBuilder.buildStickyFacet(FIELD_RULE_SANS_TOP_25, FACET_SANS_TOP_25,
+ FACET_DEFAULT_SIZE, filterSecurityCategories(),
(categories == null) ? (new String[0]) : categories.toArray()));
}
if (options.getFacets().contains(FACET_SONARSOURCE_SECURITY)) {
Collection<String> categories = query.getSonarsourceSecurity();
aggregations.put(FACET_SONARSOURCE_SECURITY,
stickyFacetBuilder.buildStickyFacet(FIELD_RULE_SONARSOURCE_SECURITY, FACET_SONARSOURCE_SECURITY,
+ FACET_DEFAULT_SIZE, filterSecurityCategories(),
(categories == null) ? (new String[0]) : categories.toArray()));
}
}
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
index 87f92a06403..2dc3371373c 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
@@ -31,6 +31,7 @@ import org.junit.rules.ExpectedException;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
@@ -59,6 +60,7 @@ import static org.sonar.api.rule.Severity.MAJOR;
import static org.sonar.api.rule.Severity.MINOR;
import static org.sonar.api.rules.RuleType.BUG;
import static org.sonar.api.rules.RuleType.CODE_SMELL;
+import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
import static org.sonar.api.rules.RuleType.VULNERABILITY;
import static org.sonar.db.rule.RuleTesting.setCreatedAt;
import static org.sonar.db.rule.RuleTesting.setIsExternal;
@@ -455,10 +457,10 @@ public class RuleIndexTest {
}
@Test
- public void search_by_security_cwe() {
- RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("cwe:543", "cwe:123", "owaspTop10:a1")));
- RuleDefinitionDto rule2 = createRule(setSecurityStandards(of("cwe:543", "owaspTop10:a1")));
- createRule(setSecurityStandards(of("owaspTop10:a1")));
+ public void search_by_security_cwe_return_vulnerabilities_and_hotspots_only() {
+ RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("cwe:543", "cwe:123", "owaspTop10:a1")), r -> r.setType(VULNERABILITY));
+ RuleDefinitionDto rule2 = createRule(setSecurityStandards(of("cwe:543", "owaspTop10:a1")), r -> r.setType(SECURITY_HOTSPOT));
+ createRule(setSecurityStandards(of("owaspTop10:a1")), r -> r.setType(CODE_SMELL));
index();
RuleQuery query = new RuleQuery().setCwe(of("543"));
@@ -467,10 +469,10 @@ public class RuleIndexTest {
}
@Test
- public void search_by_security_owaspTop10() {
- RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:543")));
- RuleDefinitionDto rule2 = createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:543")));
- createRule(setSecurityStandards(of("cwe:543")));
+ public void search_by_security_owaspTop10_return_vulnerabilities_and_hotspots_only() {
+ RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:543")), r -> r.setType(VULNERABILITY));
+ RuleDefinitionDto rule2 = createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:543")), r -> r.setType(SECURITY_HOTSPOT));
+ createRule(setSecurityStandards(of("cwe:543")), r -> r.setType(CODE_SMELL));
index();
RuleQuery query = new RuleQuery().setOwaspTop10(of("a5", "a10"));
@@ -479,10 +481,10 @@ public class RuleIndexTest {
}
@Test
- public void search_by_security_sansTop25() {
- RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:89")));
- RuleDefinitionDto rule2 = createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:829")));
- createRule(setSecurityStandards(of("cwe:306")));
+ public void search_by_security_sansTop25_return_vulnerabilities_and_hotspots_only() {
+ RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:89")), r -> r.setType(VULNERABILITY));
+ RuleDefinitionDto rule2 = createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:829")), r -> r.setType(SECURITY_HOTSPOT));
+ createRule(setSecurityStandards(of("cwe:306")), r -> r.setType(CODE_SMELL));
index();
RuleQuery query = new RuleQuery().setSansTop25(of(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE));
@@ -491,10 +493,10 @@ public class RuleIndexTest {
}
@Test
- public void search_by_security_sonarsource() {
- RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:89")));
- createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:829")));
- RuleDefinitionDto rule3 = createRule(setSecurityStandards(of("cwe:601")));
+ public void search_by_security_sonarsource_return_vulnerabilities_and_hotspots_only() {
+ RuleDefinitionDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:89")), r -> r.setType(VULNERABILITY));
+ createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:829")), r -> r.setType(CODE_SMELL));
+ RuleDefinitionDto rule3 = createRule(setSecurityStandards(of("cwe:601")), r -> r.setType(SECURITY_HOTSPOT));
index();
RuleQuery query = new RuleQuery().setSonarsourceSecurity(of("sql-injection", "open-redirect"));
diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java
index fc652c7b454..db39fc3028e 100644
--- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java
+++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java
@@ -433,17 +433,14 @@ public class IssueIndex {
filters.addFilter(
FIELD_ISSUE_ORGANIZATION_UUID, new SimpleFieldFilterScope(FIELD_ISSUE_ORGANIZATION_UUID),
createTermFilter(FIELD_ISSUE_ORGANIZATION_UUID, query.organizationUuid()));
- filters.addFilter(
- FIELD_ISSUE_OWASP_TOP_10, OWASP_TOP_10.getFilterScope(),
- createTermsFilter(FIELD_ISSUE_OWASP_TOP_10, query.owaspTop10()));
- filters.addFilter(
- FIELD_ISSUE_SANS_TOP_25, SANS_TOP_25.getFilterScope(),
- createTermsFilter(FIELD_ISSUE_SANS_TOP_25, query.sansTop25()));
- filters.addFilter(FIELD_ISSUE_CWE, CWE.getFilterScope(), createTermsFilter(FIELD_ISSUE_CWE, query.cwe()));
+
+ // security category
+ addSecurityCategoryFilter(FIELD_ISSUE_OWASP_TOP_10, OWASP_TOP_10, query.owaspTop10(), filters);
+ addSecurityCategoryFilter(FIELD_ISSUE_SANS_TOP_25, SANS_TOP_25, query.sansTop25(), filters);
+ addSecurityCategoryFilter(FIELD_ISSUE_CWE, CWE, query.cwe(), filters);
+ addSecurityCategoryFilter(FIELD_ISSUE_SQ_SECURITY_CATEGORY, SONARSOURCE_SECURITY, query.sonarsourceSecurity(), filters);
+
addSeverityFilter(query, filters);
- filters.addFilter(
- FIELD_ISSUE_SQ_SECURITY_CATEGORY, SONARSOURCE_SECURITY.getFilterScope(),
- createTermsFilter(FIELD_ISSUE_SQ_SECURITY_CATEGORY, query.sonarsourceSecurity()));
addComponentRelatedFilters(query, filters);
addDatesFilter(filters, query);
@@ -451,6 +448,18 @@ public class IssueIndex {
return filters;
}
+ private static void addSecurityCategoryFilter(String fieldName, Facet facet, Collection<String> values, AllFilters allFilters) {
+ QueryBuilder securityCategoryFilter = createTermsFilter(fieldName, values);
+ if (securityCategoryFilter != null) {
+ allFilters.addFilter(
+ fieldName,
+ facet.getFilterScope(),
+ boolQuery()
+ .must(securityCategoryFilter)
+ .must(termQuery(FIELD_ISSUE_TYPE, VULNERABILITY.name())));
+ }
+ }
+
private static void addSeverityFilter(IssueQuery query, AllFilters allFilters) {
QueryBuilder severityFieldFilter = createTermsFilter(FIELD_ISSUE_SEVERITY, query.severities());
if (severityFieldFilter != null) {
@@ -659,10 +668,12 @@ public class IssueIndex {
addFacetIfNeeded(options, aggregationHelper, esRequest, AUTHOR, query.authors().toArray());
addFacetIfNeeded(options, aggregationHelper, esRequest, TAGS, query.tags().toArray());
addFacetIfNeeded(options, aggregationHelper, esRequest, TYPES, query.types().toArray());
- addFacetIfNeeded(options, aggregationHelper, esRequest, OWASP_TOP_10, query.owaspTop10().toArray());
- addFacetIfNeeded(options, aggregationHelper, esRequest, SANS_TOP_25, query.sansTop25().toArray());
- addFacetIfNeeded(options, aggregationHelper, esRequest, CWE, query.cwe().toArray());
- addFacetIfNeeded(options, aggregationHelper, esRequest, SONARSOURCE_SECURITY, query.sonarsourceSecurity().toArray());
+
+ addSecurityCategoryFacetIfNeeded(PARAM_OWASP_TOP_10, OWASP_TOP_10, options, aggregationHelper, esRequest, query.owaspTop10().toArray());
+ addSecurityCategoryFacetIfNeeded(PARAM_SANS_TOP_25, SANS_TOP_25, options, aggregationHelper, esRequest, query.sansTop25().toArray());
+ addSecurityCategoryFacetIfNeeded(PARAM_CWE, CWE, options, aggregationHelper, esRequest, query.cwe().toArray());
+ addSecurityCategoryFacetIfNeeded(PARAM_SONARSOURCE_SECURITY, SONARSOURCE_SECURITY, options, aggregationHelper, esRequest, query.sonarsourceSecurity().toArray());
+
addSeverityFacetIfNeeded(options, aggregationHelper, esRequest);
addResolutionFacetIfNeeded(options, query, aggregationHelper, esRequest);
addAssigneesFacetIfNeeded(options, query, aggregationHelper, esRequest);
@@ -685,6 +696,20 @@ public class IssueIndex {
esRequest.addAggregation(topAggregation);
}
+ private static void addSecurityCategoryFacetIfNeeded(String param, Facet facet, SearchOptions options, TopAggregationHelper aggregationHelper, SearchRequestBuilder esRequest,
+ Object[] selectedValues) {
+ if (!options.getFacets().contains(param)) {
+ return;
+ }
+
+ AggregationBuilder aggregation = aggregationHelper.buildTermTopAggregation(
+ facet.getName(), facet.getTopAggregationDef(), facet.getNumberOfTerms(),
+ filter -> filter.must(termQuery(FIELD_ISSUE_TYPE, VULNERABILITY.name())),
+ t -> aggregationHelper.getSubAggregationHelper().buildSelectedItemsAggregation(facet.getName(), facet.getTopAggregationDef(), selectedValues)
+ .ifPresent(t::subAggregation));
+ esRequest.addAggregation(aggregation);
+ }
+
private static void addSeverityFacetIfNeeded(SearchOptions options, TopAggregationHelper aggregationHelper, SearchRequestBuilder esRequest) {
if (!options.getFacets().contains(PARAM_SEVERITIES)) {
return;
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java
index b735f379a4f..2fe031c9355 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java
@@ -24,8 +24,9 @@ import org.elasticsearch.action.search.SearchResponse;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
import org.sonar.api.impl.utils.TestSystem2;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
@@ -36,6 +37,7 @@ import org.sonar.server.es.SearchOptions;
import org.sonar.server.permission.index.IndexPermissions;
import org.sonar.server.permission.index.PermissionIndexerTester;
import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
+import org.sonar.server.security.SecurityStandards.SQCategory;
import org.sonar.server.tester.UserSessionRule;
import static java.util.Arrays.asList;
@@ -170,6 +172,70 @@ public class IssueIndexFacetsTest {
}
@Test
+ public void facets_on_cwe() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setCwe(asList("20", "564", "89", "943")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setCwe(asList("943")),
+ newDoc("I3", file));
+
+ assertThatFacetHasOnly(IssueQuery.builder(), "cwe",
+ entry("943", 2L),
+ entry("20", 1L),
+ entry("564", 1L),
+ entry("89", 1L));
+ }
+
+ @Test
+ public void facets_on_owaspTop10() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setOwaspTop10(asList("a1", "a2")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setOwaspTop10(singletonList("a3")),
+ newDoc("I3", file));
+
+ assertThatFacetHasOnly(IssueQuery.builder(), "owaspTop10",
+ entry("a1", 1L),
+ entry("a2", 1L),
+ entry("a3", 1L));
+ }
+
+ @Test
+ public void facets_on_sansTop25() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setSansTop25(asList("porous-defenses", "risky-resource", "insecure-interaction")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setSansTop25(singletonList("porous-defenses")),
+ newDoc("I3", file));
+
+ assertThatFacetHasOnly(IssueQuery.builder(), "sansTop25",
+ entry("insecure-interaction", 1L),
+ entry("porous-defenses", 2L),
+ entry("risky-resource", 1L));
+ }
+
+ @Test
+ public void facets_on_sonarSourceSecurity() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setSonarSourceSecurityCategory(SQCategory.BUFFER_OVERFLOW),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setSonarSourceSecurityCategory(SQCategory.DOS),
+ newDoc("I3", file));
+
+ assertThatFacetHasOnly(IssueQuery.builder(), "sonarsourceSecurity",
+ entry("buffer-overflow", 1L),
+ entry("dos", 1L));
+ }
+
+ @Test
public void facets_on_severities() {
ComponentDto project = newPrivateProjectDto(newOrganizationDto());
ComponentDto file = newFileDto(project, null);
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java
index 3359730b847..6b61d3d86c4 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java
@@ -32,6 +32,7 @@ import org.junit.rules.ExpectedException;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
@@ -42,6 +43,7 @@ import org.sonar.server.es.SearchOptions;
import org.sonar.server.permission.index.IndexPermissions;
import org.sonar.server.permission.index.PermissionIndexerTester;
import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
+import org.sonar.server.security.SecurityStandards.SQCategory;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.view.index.ViewDoc;
import org.sonar.server.view.index.ViewIndexer;
@@ -740,6 +742,58 @@ public class IssueIndexFiltersTest {
assertThatSearchReturnsEmpty(query);
}
+ @Test
+ public void filter_by_cwe() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setCwe(asList("20", "564", "89", "943")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setCwe(asList("943")),
+ newDoc("I3", file));
+
+ assertThatSearchReturnsOnly(IssueQuery.builder().cwe(asList("20")), "I1");
+ }
+
+ @Test
+ public void filter_by_owaspTop10() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setOwaspTop10(asList("a1", "a2")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setCwe(singletonList("a3")),
+ newDoc("I3", file));
+
+ assertThatSearchReturnsOnly(IssueQuery.builder().owaspTop10(asList("a1")), "I1");
+ }
+
+ @Test
+ public void filter_by_sansTop25() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setSansTop25(asList("porous-defenses", "risky-resource", "insecure-interaction")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setSansTop25(singletonList("porous-defenses")),
+ newDoc("I3", file));
+
+ assertThatSearchReturnsOnly(IssueQuery.builder().sansTop25(asList("risky-resource")), "I1");
+ }
+
+ @Test
+ public void filter_by_sonarSecurity() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setSonarSourceSecurityCategory(SQCategory.BUFFER_OVERFLOW),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setSonarSourceSecurityCategory(SQCategory.DOS),
+ newDoc("I3", file));
+
+ assertThatSearchReturnsOnly(IssueQuery.builder().sonarsourceSecurity(singletonList("buffer-overflow")), "I1");
+ }
+
private void verifyOrganizationFilter(String organizationUuid, String... expectedIssueKeys) {
IssueQuery.Builder query = IssueQuery.builder().organizationUuid(organizationUuid);
assertThatSearchReturnsOnly(query, expectedIssueKeys);
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
index fac01ee626a..066ed5b0c1e 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
@@ -824,6 +824,110 @@ public class SearchActionTest {
}
@Test
+ public void only_vulnerabilities_are_returned_by_cwe() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ Consumer<RuleDefinitionDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ RuleDefinitionDto issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
+ indexPermissions();
+ indexIssues();
+
+ SearchWsResponse result = ws.newRequest()
+ .setParam("cwe", "20")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
+ @Test
+ public void only_vulnerabilities_are_returned_by_owasp() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ Consumer<RuleDefinitionDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ RuleDefinitionDto issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
+ indexPermissions();
+ indexIssues();
+
+ SearchWsResponse result = ws.newRequest()
+ .setParam("owaspTop10", "a1")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
+ @Test
+ public void only_vulnerabilities_are_returned_by_sansTop25() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ Consumer<RuleDefinitionDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:266", "cwe:732", "owaspTop10:a5"))
+ .setSystemTags(Sets.newHashSet("cert", "cwe", "owasp-a5", "sans-top25-porous"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("cert", "cwe", "owasp-a5", "sans-top25-porous"));
+ RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ RuleDefinitionDto issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
+ indexPermissions();
+ indexIssues();
+
+ SearchWsResponse result = ws.newRequest()
+ .setParam("sansTop25", "porous-defenses")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
+ @Test
+ public void only_vulnerabilities_are_returned_by_sonarsource_security() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ Consumer<RuleDefinitionDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:89", "cwe:943", "owaspTop10:a1"))
+ .setSystemTags(Sets.newHashSet("cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ RuleDefinitionDto issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
+ indexPermissions();
+ indexIssues();
+
+ SearchWsResponse result = ws.newRequest()
+ .setParam("sonarsourceSecurity", "sql-injection")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
+ @Test
public void security_hotspots_are_not_returned_by_default() {
ComponentDto project = db.components().insertPublicProject();
ComponentDto file = db.components().insertComponent(newFileDto(project));
@@ -875,8 +979,8 @@ public class SearchActionTest {
RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
RuleDefinitionDto issueRule = db.rules().insertIssueRule(ruleConsumer);
- IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer);
- IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer);
+ IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
indexPermissions();
indexIssues();