private List<String> pciDss32;
private List<String> pciDss40;
private List<String> owaspTop10;
+ private List<String> owaspAsvs40;
private List<String> owaspTop10For2021;
private List<String> sansTop25;
private List<String> sonarsourceSecurity;
return this;
}
+ @CheckForNull
+ public List<String> getOwaspAsvs40() {
+ return owaspAsvs40;
+ }
+
+ public SearchRequest setOwaspAsvs40(@Nullable List<String> owaspAsvs40) {
+ this.owaspAsvs40 = owaspAsvs40;
+ return this;
+ }
+
@CheckForNull
public List<String> getOwaspTop10() {
return owaspTop10;
.setAsc(true)
.setInNewCodePeriod(true)
.setOwaspTop10For2021(asList("a2", "a3"))
+ .setOwaspAsvs40(asList("1.1.1", "4.2.2"))
.setPciDss32(asList("1", "4"))
.setPciDss40(asList("3", "5"));
assertThat(underTest.getAsc()).isTrue();
assertThat(underTest.getInNewCodePeriod()).isTrue();
assertThat(underTest.getOwaspTop10For2021()).containsExactly("a2", "a3");
+ assertThat(underTest.getOwaspAsvs40()).containsExactly("1.1.1", "4.2.2");
assertThat(underTest.getPciDss32()).containsExactly("1", "4");
assertThat(underTest.getPciDss40()).containsExactly("3", "5");
}
filters.addFilter(FIELD_ISSUE_STATUS, STATUSES.getFilterScope(), createTermsFilter(FIELD_ISSUE_STATUS, query.statuses()));
// security category
- addPciDssSecurityCategoryFilter(FIELD_ISSUE_PCI_DSS_32, PCI_DSS_32, query.pciDss32(), filters);
- addPciDssSecurityCategoryFilter(FIELD_ISSUE_PCI_DSS_40, PCI_DSS_40, query.pciDss40(), filters);
+ addSecurityCategoryPrefixFilter(FIELD_ISSUE_PCI_DSS_32, PCI_DSS_32, query.pciDss32(), filters);
+ addSecurityCategoryPrefixFilter(FIELD_ISSUE_PCI_DSS_40, PCI_DSS_40, query.pciDss40(), filters);
+ addSecurityCategoryPrefixFilter(FIELD_ISSUE_OWASP_ASVS_40, OWASP_ASVS_40, query.owaspAsvs40(), filters);
addSecurityCategoryFilter(FIELD_ISSUE_OWASP_TOP_10, OWASP_TOP_10, query.owaspTop10(), filters);
addSecurityCategoryFilter(FIELD_ISSUE_OWASP_TOP_10_2021, OWASP_TOP_10_2021, query.owaspTop10For2021(), filters);
addSecurityCategoryFilter(FIELD_ISSUE_SANS_TOP_25, SANS_TOP_25, query.sansTop25(), filters);
* @param values The PCI DSS categories to search for
* @param allFilters Object that holds all the filters for the Elastic search call
*/
- private static void addPciDssSecurityCategoryFilter(String fieldName, Facet facet, Collection<String> values, AllFilters allFilters) {
+ private static void addSecurityCategoryPrefixFilter(String fieldName, Facet facet, Collection<String> values, AllFilters allFilters) {
if (values.isEmpty()) {
return;
}
// the field type must be vulnerability or security hotspot
.must(termsQuery(FIELD_ISSUE_TYPE, VULNERABILITY.name(), SECURITY_HOTSPOT.name()));
// for top level categories a prefix query is added, while for subcategories a term query is used for exact matching
- values.stream().map(v -> choosePciDssQuery(fieldName, v)).forEach(boolQueryBuilder::should);
+ values.stream().map(v -> choosePrefixQuery(fieldName, v)).forEach(boolQueryBuilder::should);
allFilters.addFilter(
fieldName,
boolQueryBuilder);
}
- private static QueryBuilder choosePciDssQuery(String fieldName, String value) {
+ private static QueryBuilder choosePrefixQuery(String fieldName, String value) {
return value.contains(".") ? createTermFilter(fieldName, value) : createPrefixFilter(fieldName, value + ".");
}
private static RequestFiltersComputer newFilterComputer(SearchOptions options, AllFilters allFilters) {
Collection<String> facetNames = options.getFacets();
Set<TopAggregationDefinition<?>> facets = Stream.concat(
- Stream.of(EFFORT_TOP_AGGREGATION),
- facetNames.stream()
- .map(FACETS_BY_NAME::get)
- .filter(Objects::nonNull)
- .map(Facet::getTopAggregationDef))
+ Stream.of(EFFORT_TOP_AGGREGATION),
+ facetNames.stream()
+ .map(FACETS_BY_NAME::get)
+ .filter(Objects::nonNull)
+ .map(Facet::getTopAggregationDef))
.collect(MoreCollectors.toSet(facetNames.size()));
return new RequestFiltersComputer(allFilters, facets);
RESOLUTIONS.getName(), RESOLUTIONS.getTopAggregationDef(), RESOLUTIONS.getNumberOfTerms(),
NO_EXTRA_FILTER,
t ->
- // add aggregation of type "missing" to return count of unresolved issues in the facet
- t.subAggregation(
- addEffortAggregationIfNeeded(query, AggregationBuilders
- .missing(RESOLUTIONS.getName() + FACET_SUFFIX_MISSING)
- .field(RESOLUTIONS.getFieldName()))));
+ // add aggregation of type "missing" to return count of unresolved issues in the facet
+ t.subAggregation(
+ addEffortAggregationIfNeeded(query, AggregationBuilders
+ .missing(RESOLUTIONS.getName() + FACET_SUFFIX_MISSING)
+ .field(RESOLUTIONS.getFieldName()))));
esRequest.aggregation(aggregation);
}
ASSIGNED_TO_ME.getNumberOfTerms(),
NO_EXTRA_FILTER,
t ->
- // add sub-aggregation to return issue count for current user
- aggregationHelper.getSubAggregationHelper()
- .buildSelectedItemsAggregation(ASSIGNED_TO_ME.getName(), ASSIGNED_TO_ME.getTopAggregationDef(), new String[] {uuid})
- .ifPresent(t::subAggregation));
+ // add sub-aggregation to return issue count for current user
+ aggregationHelper.getSubAggregationHelper()
+ .buildSelectedItemsAggregation(ASSIGNED_TO_ME.getName(), ASSIGNED_TO_ME.getTopAggregationDef(), new String[] {uuid})
+ .ifPresent(t::subAggregation));
esRequest.aggregation(aggregation);
}
}
.types(request.getTypes())
.pciDss32(request.getPciDss32())
.pciDss40(request.getPciDss40())
+ .owaspAsvs40(request.getOwaspAsvs40())
.owaspTop10(request.getOwaspTop10())
.owaspTop10For2021(request.getOwaspTop10For2021())
.sansTop25(request.getSansTop25())
import org.elasticsearch.action.search.SearchResponse;
import org.junit.Test;
import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.rule.RulesDefinition.OwaspAsvsVersion;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.es.Facets;
entry("3", 1L));
}
+ @Test
+ public void facets_on_owaspAsvs40() {
+ ComponentDto project = newPrivateProjectDto();
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(asList("1", "2")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setOwaspAsvs40(singletonList("3")),
+ newDoc("I3", file));
+
+ assertThatFacetHasOnly(IssueQuery.builder(), OwaspAsvsVersion.V4_0.prefix(),
+ entry("1", 1L),
+ entry("2", 1L),
+ entry("3", 1L));
+ }
+
@Test
public void facets_on_owaspTop10() {
ComponentDto project = newPrivateProjectDto();
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
- .createdBefore(parseDateTime("2014-09-21T00:00:00+0100")).build(),
+ .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
+ .createdBefore(parseDateTime("2014-09-21T00:00:00+0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
- .createdBefore(parseDateTime("2015-01-19T00:00:00+0100")).build(),
+ .createdAfter(parseDateTime("2014-09-01T00:00:00+0100"))
+ .createdBefore(parseDateTime("2015-01-19T00:00:00+0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2011-01-01T00:00:00+0100"))
- .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
+ .createdAfter(parseDateTime("2011-01-01T00:00:00+0100"))
+ .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions options = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdAfter(parseDateTime("2014-09-01T00:00:00-0100"))
- .createdBefore(parseDateTime("2014-09-02T00:00:00-0100")).build(),
+ .createdAfter(parseDateTime("2014-09-01T00:00:00-0100"))
+ .createdBefore(parseDateTime("2014-09-02T00:00:00-0100")).build(),
options);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
SearchOptions searchOptions = fixtureForCreatedAtFacet();
SearchResponse result = underTest.search(IssueQuery.builder()
- .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
+ .createdBefore(parseDateTime("2016-01-01T00:00:00+0100")).build(),
searchOptions);
Map<String, Long> createdAt = new Facets(result, system2.getDefaultTimeZone().toZoneId()).get("createdAt");
assertThat(createdAt).containsOnly(
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_LANGUAGES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ON_COMPONENT_ONLY;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_ASVS_40;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10_2021;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PCI_DSS_32;
PARAM_TYPES,
PARAM_PCI_DSS_32,
PARAM_PCI_DSS_40,
+ PARAM_OWASP_ASVS_40,
PARAM_OWASP_TOP_10,
PARAM_OWASP_TOP_10_2021,
PARAM_SANS_TOP_25,
.setDescription("Comma-separated list of PCI DSS v4.0 categories.")
.setSince("9.6")
.setExampleValue("4,6.5.8,10.1");
+ action.createParam(PARAM_OWASP_ASVS_40)
+ .setDescription("Comma-separated list of OWASP ASVS v4.0 categories.")
+ .setSince("9.7")
+ .setExampleValue("6,10.1.1");
action.createParam(PARAM_OWASP_TOP_10)
.setDescription("Comma-separated list of OWASP Top 10 2017 lowercase categories.")
.setSince("7.3")
addMandatoryValuesToFacet(facets, PARAM_PCI_DSS_32, request.getPciDss32());
addMandatoryValuesToFacet(facets, PARAM_PCI_DSS_40, request.getPciDss40());
+ addMandatoryValuesToFacet(facets, PARAM_OWASP_ASVS_40, request.getOwaspAsvs40());
addMandatoryValuesToFacet(facets, PARAM_OWASP_TOP_10, request.getOwaspTop10());
addMandatoryValuesToFacet(facets, PARAM_OWASP_TOP_10_2021, request.getOwaspTop10For2021());
addMandatoryValuesToFacet(facets, PARAM_SANS_TOP_25, request.getSansTop25());
.setTypes(allRuleTypesExceptHotspotsIfEmpty(request.paramAsStrings(PARAM_TYPES)))
.setPciDss32(request.paramAsStrings(PARAM_PCI_DSS_32))
.setPciDss40(request.paramAsStrings(PARAM_PCI_DSS_40))
+ .setOwaspAsvs40(request.paramAsStrings(PARAM_OWASP_ASVS_40))
.setOwaspTop10(request.paramAsStrings(PARAM_OWASP_TOP_10))
.setOwaspTop10For2021(request.paramAsStrings(PARAM_OWASP_TOP_10_2021))
.setSansTop25(request.paramAsStrings(PARAM_SANS_TOP_25))
.containsExactly("82fd47d4-b650-4037-80bc-7b112bd4eac3", "82fd47d4-b650-4037-80bc-7b112bd4eac1", "82fd47d4-b650-4037-80bc-7b112bd4eac2");
}
+ @Test
+ public void only_vulnerabilities_are_returned_by_owaspAsvs40() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-3.2:6.5.3", "owaspAsvs-4.0:12.3.1"))
+ .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"));
+ RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ RuleDto 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));
+ indexPermissionsAndIssues();
+
+ SearchWsResponse result = ws.newRequest()
+ .setParam("owaspAsvs-4.0", "12.3.1")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+
+ result = ws.newRequest()
+ .setParam("owaspAsvs-4.0", "12")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
@Test
public void only_vulnerabilities_are_returned_by_pciDss32() {
ComponentDto project = db.components().insertPublicProject();
assertThat(def.params()).extracting("key").containsExactlyInAnyOrder(
"additionalFields", "asc", "assigned", "assignees", "author", "componentKeys", "branch", "pullRequest", "createdAfter", "createdAt",
"createdBefore", "createdInLast", "directories", "facets", "files", "issues", "scopes", "languages", "onComponentOnly",
- "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", "statuses", "tags", "types", "pciDss-3.2", "pciDss-4.0", "owaspTop10",
+ "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", "statuses", "tags", "types", "pciDss-3.2", "pciDss-4.0", "owaspAsvs-4.0", "owaspTop10",
"owaspTop10-2021", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod");
WebService.Param branch = def.param(PARAM_BRANCH);