return searchWithDistribution(request, version.label(), level);
}
+ public List<SecurityStandardCategoryStatistics> getOwaspAsvsReportGroupedByLevel(String projectUuid, boolean isViewOrApp, RulesDefinition.OwaspAsvsVersion version, int level) {
+ SearchSourceBuilder request = prepareNonClosedVulnerabilitiesAndHotspotSearch(projectUuid, isViewOrApp);
+ request.aggregation(
+ newSecurityReportSubAggregations(
+ AggregationBuilders.filter(
+ "l" + level,
+ boolQuery().filter(termsQuery(version.prefix(), SecurityStandards.OWASP_ASVS_REQUIREMENTS_BY_LEVEL.get(version).get(level)))),
+ version.prefix()));
+ return searchWithLevelDistribution(request, version.label(), Integer.toString(level));
+ }
+
public List<SecurityStandardCategoryStatistics> getOwaspTop10Report(String projectUuid, boolean isViewOrApp, boolean includeCwe, OwaspTop10Version version) {
SearchSourceBuilder request = prepareNonClosedVulnerabilitiesAndHotspotSearch(projectUuid, isViewOrApp);
IntStream.rangeClosed(1, 10).mapToObj(i -> "a" + i)
return search(request, includeCwe, version.label());
}
+ private List<SecurityStandardCategoryStatistics> searchWithLevelDistribution(SearchSourceBuilder sourceBuilder, String version, @Nullable String level) {
+ return getSearchResponse(sourceBuilder)
+ .getAggregations().asList().stream()
+ .map(c -> processSecurityReportIssueSearchResultsWithLevelDistribution((ParsedFilter) c, version, level))
+ .collect(MoreCollectors.toList());
+ }
+
private List<SecurityStandardCategoryStatistics> searchWithDistribution(SearchSourceBuilder sourceBuilder, String version, @Nullable Integer level) {
- SearchRequest request = EsClient.prepareSearch(TYPE_ISSUE.getMainType())
- .source(sourceBuilder);
- SearchResponse response = client.search(request);
- return response.getAggregations().asList().stream()
+ return getSearchResponse(sourceBuilder)
+ .getAggregations().asList().stream()
.map(c -> processSecurityReportIssueSearchResultsWithDistribution((ParsedFilter) c, version, level))
.collect(MoreCollectors.toList());
}
private List<SecurityStandardCategoryStatistics> search(SearchSourceBuilder sourceBuilder, boolean includeDistribution, @Nullable String version) {
- SearchRequest request = EsClient.prepareSearch(TYPE_ISSUE.getMainType())
- .source(sourceBuilder);
- SearchResponse response = client.search(request);
- return response.getAggregations().asList().stream()
+ return getSearchResponse(sourceBuilder)
+ .getAggregations().asList().stream()
.map(c -> processSecurityReportIssueSearchResults((ParsedFilter) c, includeDistribution, version))
.collect(MoreCollectors.toList());
}
+ private SearchResponse getSearchResponse(SearchSourceBuilder sourceBuilder) {
+ SearchRequest request = EsClient.prepareSearch(TYPE_ISSUE.getMainType())
+ .source(sourceBuilder);
+ return client.search(request);
+ }
+
private static SecurityStandardCategoryStatistics processSecurityReportIssueSearchResultsWithDistribution(ParsedFilter categoryFilter, String version, @Nullable Integer level) {
var list = ((ParsedStringTerms) categoryFilter.getAggregations().get(AGG_DISTRIBUTION)).getBuckets();
List<SecurityStandardCategoryStatistics> children = list.stream()
return processSecurityReportCategorySearchResults(categoryFilter, categoryFilter.getName(), children, version);
}
+ private static SecurityStandardCategoryStatistics processSecurityReportIssueSearchResultsWithLevelDistribution(ParsedFilter categoryFilter, String version, String level) {
+ var list = ((ParsedStringTerms) categoryFilter.getAggregations().get(AGG_DISTRIBUTION)).getBuckets();
+ List<SecurityStandardCategoryStatistics> children = list.stream()
+ .filter(categoryBucket -> OWASP_ASVS_40_REQUIREMENTS_BY_LEVEL.get(Integer.parseInt(level)).contains(categoryBucket.getKeyAsString()))
+ .map(categoryBucket -> processSecurityReportCategorySearchResults(categoryBucket, categoryBucket.getKeyAsString(), null, null))
+ .collect(toList());
+
+ return processSecurityReportCategorySearchResults(categoryFilter, categoryFilter.getName(), children, version);
+ }
+
private static SecurityStandardCategoryStatistics processSecurityReportIssueSearchResults(ParsedFilter categoryBucket, boolean includeDistribution, String version) {
List<SecurityStandardCategoryStatistics> children = new ArrayList<>();
if (includeDistribution) {
*/
package org.sonar.server.issue.index;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.stream.Collectors;
+import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
assertThat(owaspAsvsReport.get(0).getChildren()).isEmpty();
assertThat(owaspAsvsReport.get(1).getChildren()).hasSize(2);
- assertThat(owaspAsvsReport.get(2).getChildren()).hasSize(3);
+ assertThat(owaspAsvsReport.get(2).getChildren()).hasSize(4);
assertThat(owaspAsvsReport.get(3).getChildren()).isEmpty();
assertThat(owaspAsvsReport.get(4).getChildren()).isEmpty();
- assertThat(owaspAsvsReport.get(5).getChildren()).hasSize(1);
+ assertThat(owaspAsvsReport.get(5).getChildren()).hasSize(2);
assertThat(owaspAsvsReport.get(6).getChildren()).hasSize(1);
assertThat(owaspAsvsReport.get(7).getChildren()).hasSize(1);
assertThat(owaspAsvsReport.get(8).getChildren()).isEmpty();
assertThat(owaspAsvsReport.get(13).getChildren()).isEmpty();
}
+ @Test
+ public void getOwaspAsvs40ReportGroupedByLevel_aggregation() {
+ List<SecurityStandardCategoryStatistics> owaspAsvsReportGroupedByLevel = indexIssuesAndAssertOwaspAsvsReportGroupedByLevel();
+
+ assertThat(owaspAsvsReportGroupedByLevel)
+ .isNotEmpty();
+
+ assertThat(owaspAsvsReportGroupedByLevel.get(0).getChildren()).hasSize(3);
+ assertThat(owaspAsvsReportGroupedByLevel.get(1).getChildren()).hasSize(7);
+ assertThat(owaspAsvsReportGroupedByLevel.get(2).getChildren()).hasSize(11);
+ }
+
@Test
public void getOwaspTop10Report_aggregation_with_cwe() {
List<SecurityStandardCategoryStatistics> owaspTop10Report = indexIssuesAndAssertOwaspReport(true);
}
private List<SecurityStandardCategoryStatistics> indexIssuesAndAssertOwaspAsvsReport() {
- ComponentDto project = newPrivateProjectDto();
- indexIssues(
- newDoc("openvul1", project).setOwaspAsvs40(asList("2.1.1", "3.4.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
- .setSeverity(Severity.MAJOR),
- newDoc("openvul2", project).setOwaspAsvs40(asList("3.2.2", "6.2.1")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
- .setSeverity(Severity.MINOR),
- newDoc("openvul3", project).setOwaspAsvs40(asList("10.3.1", "6.2.1")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
- .setSeverity(Severity.MINOR),
- newDoc("notowaspasvsvul", project).setOwaspAsvs40(singletonList(UNKNOWN_STANDARD)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.CRITICAL),
- newDoc("toreviewhotspot1", project).setOwaspAsvs40(asList("2.1.2", "3.2.2")).setType(RuleType.SECURITY_HOTSPOT)
- .setStatus(Issue.STATUS_TO_REVIEW),
- newDoc("toreviewhotspot2", project).setOwaspAsvs40(asList("3.4.5", "7.1.1")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW),
- newDoc("reviewedHotspot", project).setOwaspAsvs40(asList("3.1.1", "8.3.4")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED)
- .setResolution(Issue.RESOLUTION_FIXED),
- newDoc("notowaspasvshotspot", project).setOwaspAsvs40(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW));
+ ComponentDto project = getProjectWithOwaspAsvsIssuesIndexed();
- List<SecurityStandardCategoryStatistics> owaspAsvsReport = underTest.getOwaspAsvsReport(project.uuid(), false, OwaspAsvsVersion.V4_0, 1).stream()
+ List<SecurityStandardCategoryStatistics> owaspAsvsReport = underTest.getOwaspAsvsReport(project.uuid(), false, OwaspAsvsVersion.V4_0, 3).stream()
.sorted(comparing(s -> parseInt(s.getCategory())))
.collect(toList());
assertThat(owaspAsvsReport)
return owaspAsvsReport;
}
+ private List<SecurityStandardCategoryStatistics> indexIssuesAndAssertOwaspAsvsReportGroupedByLevel() {
+ ComponentDto project = getProjectWithOwaspAsvsIssuesIndexed();
+
+ List<SecurityStandardCategoryStatistics> owaspAsvsReportGroupedByLevel = new ArrayList<>();
+ owaspAsvsReportGroupedByLevel.addAll(underTest.getOwaspAsvsReportGroupedByLevel(project.uuid(), false, OwaspAsvsVersion.V4_0, 1).stream()
+ .sorted(comparing(s -> parseInt(s.getCategory())))
+ .collect(toList()));
+ owaspAsvsReportGroupedByLevel.addAll(underTest.getOwaspAsvsReportGroupedByLevel(project.uuid(), false, OwaspAsvsVersion.V4_0, 2).stream()
+ .sorted(comparing(s -> parseInt(s.getCategory())))
+ .collect(toList()));
+ owaspAsvsReportGroupedByLevel.addAll(underTest.getOwaspAsvsReportGroupedByLevel(project.uuid(), false, OwaspAsvsVersion.V4_0, 3).stream()
+ .sorted(comparing(s -> parseInt(s.getCategory())))
+ .collect(toList()));
+
+ assertThat(owaspAsvsReportGroupedByLevel)
+ .extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities,
+ SecurityStandardCategoryStatistics::getVulnerabilityRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots,
+ SecurityStandardCategoryStatistics::getReviewedSecurityHotspots, SecurityStandardCategoryStatistics::getSecurityReviewRating)
+ .containsExactlyInAnyOrder(
+ tuple("l1", 1L /* openvul2 */, OptionalInt.of(2), 1L /* toreviewhotspot2 */, 0L, 5),
+ tuple("l2", 2L /* openvul1, openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 2L /* toreviewhotspot1, toreviewhotspot2 */, 1L /* reviewedHotspot */, 4),
+ tuple("l3", 3L /* openvul1,openvul2,openvul3 */, OptionalInt.of(3)/* MAJOR = C */, 2L/* toreviewhotspot1,toreviewhotspot2 */, 1L /* reviewedHotspot */, 4));
+
+ return owaspAsvsReportGroupedByLevel;
+ }
+
+ @NotNull
+ private ComponentDto getProjectWithOwaspAsvsIssuesIndexed() {
+ ComponentDto project = newPrivateProjectDto();
+ indexIssues(
+ newDoc("openvul1", project).setOwaspAsvs40(asList("2.4.1", "3.2.4")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
+ .setSeverity(Severity.MAJOR),
+ newDoc("openvul2", project).setOwaspAsvs40(asList("3.4.5", "6.2.1")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR),
+ newDoc("openvul3", project).setOwaspAsvs40(asList("10.2.4", "6.2.8")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR),
+ newDoc("notowaspasvsvul", project).setOwaspAsvs40(singletonList(UNKNOWN_STANDARD)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.CRITICAL),
+ newDoc("toreviewhotspot1", project).setOwaspAsvs40(asList("2.2.5", "3.2.4")).setType(RuleType.SECURITY_HOTSPOT)
+ .setStatus(Issue.STATUS_TO_REVIEW),
+ newDoc("toreviewhotspot2", project).setOwaspAsvs40(asList("3.6.1", "7.1.1")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW),
+ newDoc("reviewedHotspot", project).setOwaspAsvs40(asList("3.3.3", "8.3.7")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED)
+ .setResolution(Issue.RESOLUTION_FIXED),
+ newDoc("notowaspasvshotspot", project).setOwaspAsvs40(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW));
+ return project;
+ }
+
private List<SecurityStandardCategoryStatistics> indexIssuesAndAssertOwasp2021Report(boolean includeCwe) {
ComponentDto project = newPrivateProjectDto();
indexIssues(