diff options
author | Jacek <jacek.poreda@sonarsource.com> | 2020-08-10 14:45:45 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2020-08-26 20:06:44 +0000 |
commit | 56826fb52dbddbe6166f7a1e80065bddc7fd254a (patch) | |
tree | 1e92566183197c407eda09f6a3b9b9af273add2e /server/sonar-webserver-es/src | |
parent | 8cba7b5098395a6c39e616570a687b167e618153 (diff) | |
download | sonarqube-56826fb52dbddbe6166f7a1e80065bddc7fd254a.tar.gz sonarqube-56826fb52dbddbe6166f7a1e80065bddc7fd254a.zip |
SONAR-12459 Security Category filters vulnerability issues only
Diffstat (limited to 'server/sonar-webserver-es/src')
3 files changed, 160 insertions, 15 deletions
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); |