From 20cc332ffff7701ca9a4ac73186fa2adb62bee72 Mon Sep 17 00:00:00 2001
From: Dimitris Kavvathas
Date: Fri, 22 Jul 2022 10:24:21 +0200
Subject: [PATCH] SONAR-17061 Add PCI DSS parameter and facet in
'api/issues/search' API endpoint
---
.../org/sonar/server/issue/SearchRequest.java | 22 ++
.../sonar/server/issue/SearchRequestTest.java | 6 +-
.../sonar/server/issue/index/IssueIndex.java | 55 +++-
.../server/issue/index/IssueQueryFactory.java | 6 +-
.../issue/index/IssueIndexDebtTest.java | 36 +--
.../issue/index/IssueIndexFacetsTest.java | 69 ++---
.../issue/index/IssueIndexFiltersTest.java | 56 +----
.../IssueIndexProjectStatisticsTest.java | 31 +--
.../IssueIndexSecurityCategoriesTest.java | 140 +++++++++++
.../index/IssueIndexSecurityHotspotsTest.java | 49 +---
.../index/IssueIndexSecurityReportsTest.java | 34 +--
.../issue/index/IssueIndexSortTest.java | 56 +----
.../server/issue/index/IssueIndexTest.java | 59 +----
.../issue/index/IssueIndexTestCommon.java | 89 +++++++
.../sonar/server/issue/ws/SearchAction.java | 22 +-
.../server/issue/ws/SearchActionTest.java | 238 +++++++++++++++++-
16 files changed, 607 insertions(+), 361 deletions(-)
create mode 100644 server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityCategoriesTest.java
create mode 100644 server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTestCommon.java
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java
index bc1273d762e..108e8577661 100644
--- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java
+++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java
@@ -61,6 +61,8 @@ public class SearchRequest {
private List statuses;
private List tags;
private Set types;
+ private List pciDss32;
+ private List pciDss40;
private List owaspTop10;
private List owaspTop10For2021;
private List sansTop25;
@@ -368,6 +370,26 @@ public class SearchRequest {
return this;
}
+ @CheckForNull
+ public List getPciDss32() {
+ return pciDss32;
+ }
+
+ public SearchRequest setPciDss32(@Nullable List pciDss32) {
+ this.pciDss32 = pciDss32;
+ return this;
+ }
+
+ @CheckForNull
+ public List getPciDss40() {
+ return pciDss40;
+ }
+
+ public SearchRequest setPciDss40(@Nullable List pciDss40) {
+ this.pciDss40 = pciDss40;
+ return this;
+ }
+
@CheckForNull
public List getOwaspTop10() {
return owaspTop10;
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java
index 61136ff96e6..774c12d6092 100644
--- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java
+++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java
@@ -49,7 +49,9 @@ public class SearchRequestTest {
.setSort("CREATION_DATE")
.setAsc(true)
.setInNewCodePeriod(true)
- .setOwaspTop10For2021(asList("a2", "a3"));
+ .setOwaspTop10For2021(asList("a2", "a3"))
+ .setPciDss32(asList("1", "4"))
+ .setPciDss40(asList("3", "5"));
assertThat(underTest.getIssues()).containsOnlyOnce("anIssueKey");
assertThat(underTest.getSeverities()).containsExactly("MAJOR", "MINOR");
@@ -71,6 +73,8 @@ public class SearchRequestTest {
assertThat(underTest.getAsc()).isTrue();
assertThat(underTest.getInNewCodePeriod()).isTrue();
assertThat(underTest.getOwaspTop10For2021()).containsExactly("a2", "a3");
+ assertThat(underTest.getPciDss32()).containsExactly("1", "4");
+ assertThat(underTest.getPciDss40()).containsExactly("3", "5");
}
@Test
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 d9c53eed857..2ed15da00f5 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
@@ -455,8 +455,8 @@ public class IssueIndex {
filters.addFilter(FIELD_ISSUE_STATUS, STATUSES.getFilterScope(), createTermsFilter(FIELD_ISSUE_STATUS, query.statuses()));
// security category
- addSecurityCategoryFilter(FIELD_ISSUE_PCI_DSS_32, PCI_DSS_32, query.pciDss32(), filters);
- addSecurityCategoryFilter(FIELD_ISSUE_PCI_DSS_40, PCI_DSS_40, query.pciDss40(), filters);
+ addPciDssSecurityCategoryFilter(FIELD_ISSUE_PCI_DSS_32, PCI_DSS_32, query.pciDss32(), filters);
+ addPciDssSecurityCategoryFilter(FIELD_ISSUE_PCI_DSS_40, PCI_DSS_40, query.pciDss40(), 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);
@@ -485,6 +485,49 @@ public class IssueIndex {
}
}
+ /**
+ * Builds the Elasticsearch boolean query to filter the PCI DSS categories.
+ *
+ * The PCI DSS security report handles all the subcategories as one level. This means that subcategory 1.1 doesn't include the issues from 1.1.1.
+ * Taking this into account, the search filter follows the same logic and uses prefix matching for top-level categories and exact matching for subcategories
+ *
+ * Example
+ * List of PCI DSS categories in issues: {1.5.8, 1.5.9, 1.6.7}
+ *
+ * - Search: {1}, returns {1.5.8, 1.5.9, 1.6.7}
+ * - Search: {1.5.8}, returns {1.5.8}
+ * - Search: {1.5}, returns {}
+ *
+ *
+ *
+ * @param fieldName The PCI DSS version, e.g. pciDss-3.2
+ * @param facet The facet used for the filter
+ * @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 values, AllFilters allFilters) {
+ if (values.isEmpty()) {
+ return;
+ }
+
+ BoolQueryBuilder boolQueryBuilder = boolQuery()
+ // ensures that at least one "should" query is matched. Without it, "should" queries are optional, when a "must" is also present.
+ .minimumShouldMatch(1)
+ // 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);
+
+ allFilters.addFilter(
+ fieldName,
+ facet.getFilterScope(),
+ boolQueryBuilder);
+ }
+
+ private static QueryBuilder choosePciDssQuery(String fieldName, String value) {
+ return value.contains(".") ? createTermFilter(fieldName, value) : createPrefixFilter(fieldName, value + ".");
+ }
+
private static void addSeverityFilter(IssueQuery query, AllFilters allFilters) {
QueryBuilder severityFieldFilter = createTermsFilter(FIELD_ISSUE_SEVERITY, query.severities());
if (severityFieldFilter != null) {
@@ -615,6 +658,10 @@ public class IssueIndex {
return value == null ? null : termQuery(field, value);
}
+ private static QueryBuilder createPrefixFilter(String field, String value) {
+ return prefixQuery(field, value);
+ }
+
private void configureSorting(IssueQuery query, SearchSourceBuilder esRequest) {
createSortBuilders(query).forEach(esRequest::sort);
}
@@ -715,6 +762,8 @@ public class IssueIndex {
addFacetIfNeeded(options, aggregationHelper, esRequest, TAGS, query.tags().toArray());
addFacetIfNeeded(options, aggregationHelper, esRequest, TYPES, query.types().toArray());
+ addSecurityCategoryFacetIfNeeded(PARAM_PCI_DSS_32, PCI_DSS_32, options, aggregationHelper, esRequest, query.pciDss32().toArray());
+ addSecurityCategoryFacetIfNeeded(PARAM_PCI_DSS_40, PCI_DSS_40, options, aggregationHelper, esRequest, query.pciDss40().toArray());
addSecurityCategoryFacetIfNeeded(PARAM_OWASP_TOP_10, OWASP_TOP_10, options, aggregationHelper, esRequest, query.owaspTop10().toArray());
addSecurityCategoryFacetIfNeeded(PARAM_OWASP_TOP_10_2021, OWASP_TOP_10_2021, options, aggregationHelper, esRequest, query.owaspTop10For2021().toArray());
addSecurityCategoryFacetIfNeeded(PARAM_SANS_TOP_25, SANS_TOP_25, options, aggregationHelper, esRequest, query.sansTop25().toArray());
@@ -1003,7 +1052,7 @@ public class IssueIndex {
requestBuilder.source(sourceBuilder);
SearchResponse response = client.search(requestBuilder);
return response.getAggregations().asList().stream()
- .map(x -> (ParsedFilter) x)
+ .map(ParsedFilter.class::cast)
.flatMap(projectBucket -> ((ParsedStringTerms) projectBucket.getAggregations().get("branchUuid")).getBuckets().stream()
.flatMap(branchBucket -> {
long count = ((ParsedValueCount) branchBucket.getAggregations().get(AGG_COUNT)).getValue();
diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java
index 989936ff93b..ef43b30c23a 100644
--- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java
+++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java
@@ -133,6 +133,8 @@ public class IssueQueryFactory {
.languages(request.getLanguages())
.tags(request.getTags())
.types(request.getTypes())
+ .pciDss32(request.getPciDss32())
+ .pciDss40(request.getPciDss40())
.owaspTop10(request.getOwaspTop10())
.owaspTop10For2021(request.getOwaspTop10For2021())
.sansTop25(request.getSansTop25())
@@ -199,8 +201,8 @@ public class IssueQueryFactory {
if (!QUALIFIERS_WITHOUT_LEAK_PERIOD.contains(component.qualifier()) && request.getPullRequest() == null) {
Optional snapshot = getLastAnalysis(dbSession, component);
if (!snapshot.isEmpty() && isLastAnalysisFromReAnalyzedReferenceBranch(dbSession, snapshot.get())) {
- builder.newCodeOnReference(true);
- return;
+ builder.newCodeOnReference(true);
+ return;
}
// if last analysis has no period date, then no issue should be considered new.
Date createdAfterFromSnapshot = findCreatedAfterFromComponentUuid(snapshot);
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java
index 0a595df01e9..94225742656 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexDebtTest.java
@@ -20,54 +20,25 @@
package org.sonar.server.issue.index;
import java.util.Map;
-import java.util.TimeZone;
-import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
-import org.sonar.server.es.EsTester;
import org.sonar.server.es.Facets;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.issue.IssueDocTesting;
import org.sonar.server.issue.index.IssueQuery.Builder;
-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.tester.UserSessionRule;
-import static java.util.Arrays.asList;
-import static java.util.Arrays.stream;
import static java.util.Collections.singletonList;
-import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.Mockito.mock;
import static org.sonar.api.issue.Issue.STATUS_CLOSED;
import static org.sonar.api.issue.Issue.STATUS_OPEN;
-import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT;
-public class IssueIndexDebtTest {
-
- private final System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(TimeZone.getTimeZone("GMT-01:00"));
-
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
- @Rule
- public DbTester db = DbTester.create(system2);
-
- private final AsyncIssueIndexing asyncIssueIndexing = mock(AsyncIssueIndexing.class);
- private final IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), asyncIssueIndexing);
- private final PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
- private final IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexDebtTest extends IssueIndexTestCommon {
@Test
public void facets_on_projects() {
@@ -248,11 +219,6 @@ public class IssueIndexDebtTest {
return new SearchOptions().addFacets("createdAt");
}
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
-
private Facets search(String additionalFacet) {
return new Facets(underTest.search(newQueryBuilder().build(), new SearchOptions().addFacets(singletonList(additionalFacet))), system2.getDefaultTimeZone().toZoneId());
}
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 ac1062dde0a..20d86b48c40 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
@@ -23,30 +23,17 @@ import java.time.ZoneId;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
-import java.util.TimeZone;
import org.elasticsearch.action.search.SearchResponse;
-import org.junit.Rule;
import org.junit.Test;
-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.rule.RuleDto;
-import org.sonar.server.es.EsTester;
import org.sonar.server.es.Facets;
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;
-import static java.util.Arrays.stream;
import static java.util.Collections.singletonList;
-import static java.util.TimeZone.getTimeZone;
-import static java.util.stream.Collectors.toList;
import static java.util.stream.IntStream.rangeClosed;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
@@ -59,7 +46,6 @@ import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
import static org.sonar.api.issue.Issue.STATUS_OPEN;
import static org.sonar.api.issue.Issue.STATUS_REOPENED;
import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
-import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.rule.Severity.BLOCKER;
import static org.sonar.api.rule.Severity.CRITICAL;
import static org.sonar.api.rule.Severity.INFO;
@@ -67,6 +53,8 @@ import static org.sonar.api.rule.Severity.MAJOR;
import static org.sonar.api.rule.Severity.MINOR;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2017;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2021;
+import static org.sonar.api.server.rule.RulesDefinition.PciDssVersion.V3_2;
+import static org.sonar.api.server.rule.RulesDefinition.PciDssVersion.V4_0;
import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonar.db.component.ComponentTesting.newDirectory;
import static org.sonar.db.component.ComponentTesting.newFileDto;
@@ -74,21 +62,7 @@ import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
-public class IssueIndexFacetsTest {
-
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
- private final TimeZone defaultTimezone = getTimeZone("GMT-01:00");
- private System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(defaultTimezone);
- @Rule
- public DbTester db = DbTester.create(system2);
-
- private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), null);
- private PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
-
- private IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexFacetsTest extends IssueIndexTestCommon {
@Test
public void facet_on_projectUuids() {
@@ -187,6 +161,38 @@ public class IssueIndexFacetsTest {
entry("89", 1L));
}
+ @Test
+ public void facets_on_pciDss32() {
+ ComponentDto project = newPrivateProjectDto();
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setPciDss32(asList("1", "2")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setPciDss32(singletonList("3")),
+ newDoc("I3", file));
+
+ assertThatFacetHasOnly(IssueQuery.builder(), V3_2.prefix(),
+ entry("1", 1L),
+ entry("2", 1L),
+ entry("3", 1L));
+ }
+
+ @Test
+ public void facets_on_pciDss40() {
+ ComponentDto project = newPrivateProjectDto();
+ ComponentDto file = newFileDto(project, null);
+
+ indexIssues(
+ newDoc("I1", file).setType(RuleType.VULNERABILITY).setPciDss40(asList("1", "2")),
+ newDoc("I2", file).setType(RuleType.VULNERABILITY).setPciDss40(singletonList("3")),
+ newDoc("I3", file));
+
+ assertThatFacetHasOnly(IssueQuery.builder(), V4_0.prefix(),
+ entry("1", 1L),
+ entry("2", 1L),
+ entry("3", 1L));
+ }
+
@Test
public void facets_on_owaspTop10() {
ComponentDto project = newPrivateProjectDto();
@@ -637,11 +643,6 @@ public class IssueIndexFacetsTest {
return new SearchOptions().addFacets("createdAt");
}
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
-
@SafeVarargs
private final void assertThatFacetHasExactly(IssueQuery.Builder query, String facet, Map.Entry... expectedEntries) {
SearchResponse result = underTest.search(query.build(), new SearchOptions().addFacets(singletonList(facet)));
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 a41d651ba9a..8312ff90cf4 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
@@ -20,43 +20,26 @@
package org.sonar.server.issue.index;
import com.google.common.collect.ImmutableMap;
-import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Set;
-import java.util.stream.Collectors;
import org.assertj.core.api.Fail;
-import org.elasticsearch.search.SearchHit;
-import org.junit.Rule;
import org.junit.Test;
-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;
import org.sonar.db.rule.RuleDto;
-import org.sonar.server.es.EsTester;
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;
import static java.util.Arrays.asList;
-import static java.util.Arrays.stream;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
-import static java.util.TimeZone.getTimeZone;
-import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.sonar.api.resources.Qualifiers.APP;
-import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.utils.DateUtils.addDays;
import static org.sonar.api.utils.DateUtils.parseDate;
import static org.sonar.api.utils.DateUtils.parseDateTime;
@@ -66,20 +49,7 @@ import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
import static org.sonar.db.rule.RuleTesting.newRule;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
-public class IssueIndexFiltersTest {
-
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
- private final System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(getTimeZone("GMT-01:00"));
- @Rule
- public DbTester db = DbTester.create(system2);
-
- private final IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), null);
- private final ViewIndexer viewIndexer = new ViewIndexer(db.getDbClient(), es.client());
- private final PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
- private final IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexFiltersTest extends IssueIndexTestCommon {
@Test
public void filter_by_keys() {
@@ -844,31 +814,7 @@ public class IssueIndexFiltersTest {
assertThatSearchReturnsOnly(IssueQuery.builder().sonarsourceSecurity(singletonList("buffer-overflow")), "I1");
}
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
-
private void indexView(String viewUuid, List projects) {
viewIndexer.index(new ViewDoc().setUuid(viewUuid).setProjects(projects));
}
-
- /**
- * Execute the search request and return the document ids of results.
- */
- private List searchAndReturnKeys(IssueQuery.Builder query) {
- return Arrays.stream(underTest.search(query.build(), new SearchOptions()).getHits().getHits())
- .map(SearchHit::getId)
- .collect(Collectors.toList());
- }
-
- private void assertThatSearchReturnsOnly(IssueQuery.Builder query, String... expectedIssueKeys) {
- List keys = searchAndReturnKeys(query);
- assertThat(keys).containsExactlyInAnyOrder(expectedIssueKeys);
- }
-
- private void assertThatSearchReturnsEmpty(IssueQuery.Builder query) {
- List keys = searchAndReturnKeys(query);
- assertThat(keys).isEmpty();
- }
}
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexProjectStatisticsTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexProjectStatisticsTest.java
index 07279338865..59739bf78be 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexProjectStatisticsTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexProjectStatisticsTest.java
@@ -21,44 +21,22 @@ package org.sonar.server.issue.index;
import java.util.Date;
import java.util.List;
-import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.issue.Issue;
-import org.sonar.api.utils.System2;
import org.sonar.db.component.ComponentDto;
-import org.sonar.server.es.EsTester;
-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.tester.UserSessionRule;
import static java.util.Arrays.asList;
-import static java.util.Arrays.stream;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
-import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Mockito.mock;
-import static org.sonar.api.resources.Qualifiers.PROJECT;
+import static org.sonar.db.component.ComponentTesting.newBranchComponent;
import static org.sonar.db.component.ComponentTesting.newBranchDto;
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
-import static org.sonar.db.component.ComponentTesting.newBranchComponent;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
-public class IssueIndexProjectStatisticsTest {
-
- private System2 system2 = mock(System2.class);
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
-
- private IssueIndexer issueIndexer = new IssueIndexer(es.client(), null, new IssueIteratorFactory(null), null);
- private PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
-
- private IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexProjectStatisticsTest extends IssueIndexTestCommon {
@Test
public void searchProjectStatistics_returns_empty_list_if_no_input() {
@@ -249,9 +227,4 @@ public class IssueIndexProjectStatisticsTest {
tuple(2L, branch.uuid(), from + 2L),
tuple(1L, project.uuid(), from + 1L));
}
-
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
}
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityCategoriesTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityCategoriesTest.java
new file mode 100644
index 00000000000..4477c766de2
--- /dev/null
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityCategoriesTest.java
@@ -0,0 +1,140 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.issue.index;
+
+import java.util.List;
+import org.junit.Test;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.RuleType;
+import org.sonar.db.component.ComponentDto;
+
+import static java.util.Arrays.asList;
+import static java.util.Arrays.stream;
+import static java.util.stream.Collectors.toList;
+import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
+import static org.sonar.server.issue.IssueDocTesting.newDoc;
+
+public class IssueIndexSecurityCategoriesTest extends IssueIndexTestCommon {
+
+ @Test
+ public void searchSinglePciDss32Category() {
+ ComponentDto project = newPrivateProjectDto();
+
+ indexIssues(
+ newDoc("openvul1", project).setPciDss32(asList("1.2.0", "3.4.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
+ .setSeverity(Severity.MAJOR),
+ newDoc("openvul2", project).setPciDss32(asList("3.3.2", "1.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR)
+ );
+
+ assertThatSearchReturnsOnly(queryPciDss32("1"), "openvul1", "openvul2");
+ assertThatSearchReturnsOnly(queryPciDss32("1.2.0"), "openvul1");
+ assertThatSearchReturnsEmpty(queryPciDss32("1.2"));
+ }
+
+ @Test
+ public void searchMultiplePciDss32Categories() {
+ ComponentDto project = newPrivateProjectDto();
+
+ indexIssues(
+ newDoc("openvul1", project).setPciDss32(asList("1.2.0", "3.4.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
+ .setSeverity(Severity.MAJOR),
+ newDoc("openvul2", project).setPciDss32(asList("3.3.2", "2.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR),
+ newDoc("openvul3", project).setPciDss32(asList("4.1", "5.4")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR)
+ );
+
+ assertThatSearchReturnsOnly(queryPciDss32("1", "4"), "openvul1", "openvul3");
+ assertThatSearchReturnsOnly(queryPciDss32("1.2.0", "5.4"), "openvul1", "openvul3");
+ assertThatSearchReturnsEmpty(queryPciDss32("6", "7", "8", "9", "10", "11", "12"));
+ }
+
+ @Test
+ public void searchSinglePciDss40Category() {
+ ComponentDto project = newPrivateProjectDto();
+
+ indexIssues(
+ newDoc("openvul1", project).setPciDss40(asList("1.2.0", "3.4.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
+ .setSeverity(Severity.MAJOR),
+ newDoc("openvul2", project).setPciDss40(asList("3.3.2", "1.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR)
+ );
+
+ assertThatSearchReturnsOnly(queryPciDss40("1"), "openvul1", "openvul2");
+ assertThatSearchReturnsOnly(queryPciDss40("1.2.0"), "openvul1");
+ assertThatSearchReturnsEmpty(queryPciDss40("1.2"));
+ }
+
+ @Test
+ public void searchMultiplePciDss40Categories() {
+ ComponentDto project = newPrivateProjectDto();
+
+ indexIssues(
+ newDoc("openvul1", project).setPciDss40(asList("1.2.0", "3.4.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
+ .setSeverity(Severity.MAJOR),
+ newDoc("openvul2", project).setPciDss40(asList("3.3.2", "2.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR),
+ newDoc("openvul3", project).setPciDss40(asList("4.1", "5.4")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR)
+ );
+
+ assertThatSearchReturnsOnly(queryPciDss40("1", "4"), "openvul1", "openvul3");
+ assertThatSearchReturnsOnly(queryPciDss40("1.2.0", "5.4"), "openvul1", "openvul3");
+ assertThatSearchReturnsEmpty(queryPciDss40("6", "7", "8", "9", "10", "11", "12"));
+ }
+
+ @Test
+ public void searchMixedPciDssCategories() {
+ ComponentDto project = newPrivateProjectDto();
+
+ indexIssues(
+ newDoc("openvul1", project).setPciDss40(asList("1.2.0", "3.4.5")).setPciDss32(List.of("2.1")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN)
+ .setSeverity(Severity.MAJOR),
+ newDoc("openvul2", project).setPciDss40(asList("3.3.2", "2.5")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR),
+ newDoc("openvul3", project).setPciDss32(asList("4.1", "5.4")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED)
+ .setSeverity(Severity.MINOR)
+ );
+
+ assertThatSearchReturnsOnly(queryPciDss40("1", "4"), "openvul1");
+ assertThatSearchReturnsOnly(queryPciDss40("1.2.0", "5.4"), "openvul1");
+ assertThatSearchReturnsEmpty(queryPciDss40("6", "7", "8", "9", "10", "11", "12"));
+
+ assertThatSearchReturnsOnly(queryPciDss32("3", "2.1"), "openvul1");
+ assertThatSearchReturnsOnly(queryPciDss32("1", "2"), "openvul1");
+ assertThatSearchReturnsOnly(queryPciDss32("4", "3"), "openvul3");
+ assertThatSearchReturnsEmpty(queryPciDss32("1", "3", "6", "7", "8", "9", "10", "11", "12"));
+
+ }
+
+ private IssueQuery.Builder queryPciDss32(String... values) {
+ return IssueQuery.builder()
+ .pciDss32(stream(values).collect(toList()))
+ .types(List.of("CODE_SMELL", "BUG", "VULNERABILITY"));
+ }
+
+ private IssueQuery.Builder queryPciDss40(String... values) {
+ return IssueQuery.builder()
+ .pciDss40(stream(values).collect(toList()))
+ .types(List.of("CODE_SMELL", "BUG", "VULNERABILITY"));
+ }
+}
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityHotspotsTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityHotspotsTest.java
index ee9d8d94c80..951397edc6d 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityHotspotsTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityHotspotsTest.java
@@ -19,31 +19,18 @@
*/
package org.sonar.server.issue.index;
-import java.util.Arrays;
-import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.search.SearchHit;
-import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.rule.Severity;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.server.es.EsTester;
import org.sonar.server.es.Facets;
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.tester.UserSessionRule;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.Collections.singletonList;
-import static java.util.TimeZone.getTimeZone;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
@@ -58,20 +45,7 @@ import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
-public class IssueIndexSecurityHotspotsTest {
-
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
- private System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(getTimeZone("GMT-01:00"));
- @Rule
- public DbTester db = DbTester.create(system2);
-
- private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), null);
- private PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
-
- private IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexSecurityHotspotsTest extends IssueIndexTestCommon {
@Test
public void filter_by_security_hotspots_type() {
@@ -129,11 +103,6 @@ public class IssueIndexSecurityHotspotsTest {
assertThatFacetHasOnly(IssueQuery.builder().types(singletonList(SECURITY_HOTSPOT.name())), "severities");
}
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
-
@SafeVarargs
private final void assertThatFacetHasOnly(IssueQuery.Builder query, String facet, Map.Entry... expectedEntries) {
SearchResponse result = underTest.search(query.build(), new SearchOptions().addFacets(singletonList(facet)));
@@ -142,20 +111,4 @@ public class IssueIndexSecurityHotspotsTest {
assertThat(facets.get(facet)).containsOnly(expectedEntries);
}
- private void assertThatSearchReturnsOnly(IssueQuery.Builder query, String... expectedIssueKeys) {
- List keys = searchAndReturnKeys(query);
- assertThat(keys).containsExactlyInAnyOrder(expectedIssueKeys);
- }
-
- private void assertThatSearchReturnsEmpty(IssueQuery.Builder query) {
- List keys = searchAndReturnKeys(query);
- assertThat(keys).isEmpty();
- }
-
- private List searchAndReturnKeys(IssueQuery.Builder query) {
- return Arrays.stream(underTest.search(query.build(), new SearchOptions()).getHits().getHits())
- .map(SearchHit::getId)
- .collect(Collectors.toList());
- }
-
}
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java
index 82bf992f1b8..8a7952c6e1c 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java
@@ -23,34 +23,21 @@ import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.stream.Collectors;
-import org.junit.Rule;
import org.junit.Test;
-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.server.rule.RulesDefinition;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.server.es.EsTester;
-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.tester.UserSessionRule;
import org.sonar.server.view.index.ViewDoc;
-import org.sonar.server.view.index.ViewIndexer;
import static java.lang.Integer.parseInt;
import static java.util.Arrays.asList;
-import static java.util.Arrays.stream;
import static java.util.Collections.singletonList;
import static java.util.Comparator.comparing;
-import static java.util.TimeZone.getTimeZone;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2017;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2021;
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
@@ -60,21 +47,7 @@ import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_POROUS_DEF
import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_RISKY_RESOURCE;
import static org.sonar.server.security.SecurityStandards.UNKNOWN_STANDARD;
-public class IssueIndexSecurityReportsTest {
-
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
- private System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(getTimeZone("GMT-01:00"));
- @Rule
- public DbTester db = DbTester.create(system2);
-
- private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), null);
- private ViewIndexer viewIndexer = new ViewIndexer(db.getDbClient(), es.client());
- private PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
-
- private IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexSecurityReportsTest extends IssueIndexTestCommon {
@Test
public void getOwaspTop10Report_dont_count_vulnerabilities_from_other_projects() {
@@ -675,11 +648,6 @@ public class IssueIndexSecurityReportsTest {
return statistics.getChildren().stream().filter(stat -> stat.getCategory().equals(cweId)).findAny().orElse(null);
}
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
-
private void indexView(String viewUuid, List projects) {
viewIndexer.index(new ViewDoc().setUuid(viewUuid).setProjects(projects));
}
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSortTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSortTest.java
index 200a0010f3e..3fb1906468b 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSortTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSortTest.java
@@ -19,52 +19,19 @@
*/
package org.sonar.server.issue.index;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.search.SearchHit;
-import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.server.es.EsTester;
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.tester.UserSessionRule;
-
-import static java.util.Arrays.asList;
-import static java.util.Arrays.stream;
-import static java.util.TimeZone.getTimeZone;
-import static java.util.stream.Collectors.toList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.sonar.api.resources.Qualifiers.PROJECT;
+
import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
-public class IssueIndexSortTest {
-
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
- private final System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(getTimeZone("GMT-01:00"));
- @Rule
- public DbTester db = DbTester.create(system2);
-
- private final AsyncIssueIndexing asyncIssueIndexing = mock(AsyncIssueIndexing.class);
- private final IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), asyncIssueIndexing);
- private final PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
- private final IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexSortTest extends IssueIndexTestCommon {
@Test
public void sort_by_status() {
@@ -209,23 +176,4 @@ public class IssueIndexSortTest {
assertThatSearchReturnsOnly(IssueQuery.builder(), "F3_1", "F1_2", "F1_1", "F1_3", "F2_1", "F2_2", "F2_3", "F3_2");
}
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
-
- /**
- * Execute the search request and return the document ids of results.
- */
- private List searchAndReturnKeys(IssueQuery.Builder query) {
- return Arrays.stream(underTest.search(query.build(), new SearchOptions()).getHits().getHits())
- .map(SearchHit::getId)
- .collect(Collectors.toList());
- }
-
- private void assertThatSearchReturnsOnly(IssueQuery.Builder query, String... expectedIssueKeys) {
- List keys = searchAndReturnKeys(query);
- assertThat(keys).containsExactlyInAnyOrder(expectedIssueKeys);
- }
-
}
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
index 3b887d76704..e62a4b63528 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
@@ -22,46 +22,29 @@ package org.sonar.server.issue.index;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.lucene.search.TotalHits;
import org.apache.lucene.search.TotalHits.Relation;
import org.assertj.core.groups.Tuple;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
-import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.issue.Issue;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
-import org.sonar.server.es.EsTester;
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.rule.index.RuleIndexer;
-import org.sonar.server.tester.UserSessionRule;
import static com.google.common.collect.ImmutableSortedSet.of;
import static java.util.Arrays.asList;
-import static java.util.Arrays.stream;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
-import static java.util.TimeZone.getTimeZone;
-import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Mockito.mock;
import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
-import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.rules.RuleType.BUG;
import static org.sonar.api.rules.RuleType.CODE_SMELL;
import static org.sonar.api.rules.RuleType.VULNERABILITY;
@@ -71,22 +54,7 @@ import static org.sonar.db.user.GroupTesting.newGroupDto;
import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.issue.IssueDocTesting.newDoc;
-public class IssueIndexTest {
-
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
- private final System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(getTimeZone("GMT-01:00"));
- @Rule
- public DbTester db = DbTester.create(system2);
-
- private final AsyncIssueIndexing asyncIssueIndexing = mock(AsyncIssueIndexing.class);
- private final IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), asyncIssueIndexing);
- private final RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
- private final PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
-
- private final IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+public class IssueIndexTest extends IssueIndexTestCommon {
@Test
public void paging() {
@@ -387,32 +355,7 @@ public class IssueIndexTest {
return IssueQuery.builder().projectUuids(singletonList(projectUuid)).resolved(false).build();
}
- private void indexIssues(IssueDoc... issues) {
- issueIndexer.index(asList(issues).iterator());
- authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
- }
-
private void indexIssue(IssueDoc issue) {
issueIndexer.index(Iterators.singletonIterator(issue));
}
-
- /**
- * Execute the search request and return the document ids of results.
- */
- private List searchAndReturnKeys(IssueQuery.Builder query) {
- return Arrays.stream(underTest.search(query.build(), new SearchOptions()).getHits().getHits())
- .map(SearchHit::getId)
- .collect(Collectors.toList());
- }
-
- private void assertThatSearchReturnsOnly(IssueQuery.Builder query, String... expectedIssueKeys) {
- List keys = searchAndReturnKeys(query);
- assertThat(keys).containsExactlyInAnyOrder(expectedIssueKeys);
- }
-
- private void assertThatSearchReturnsEmpty(IssueQuery.Builder query) {
- List keys = searchAndReturnKeys(query);
- assertThat(keys).isEmpty();
- }
-
}
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTestCommon.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTestCommon.java
new file mode 100644
index 00000000000..ca097cc2e21
--- /dev/null
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexTestCommon.java
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.issue.index;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.elasticsearch.search.SearchHit;
+import org.junit.Rule;
+import org.sonar.api.impl.utils.TestSystem2;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.server.es.EsTester;
+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.rule.index.RuleIndexer;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.view.index.ViewIndexer;
+
+import static java.util.Arrays.asList;
+import static java.util.Arrays.stream;
+import static java.util.TimeZone.getTimeZone;
+import static java.util.stream.Collectors.toList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonar.api.resources.Qualifiers.PROJECT;
+
+public class IssueIndexTestCommon {
+
+ @Rule
+ public EsTester es = EsTester.create();
+ @Rule
+ public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ protected final System2 system2 = new TestSystem2().setNow(1_500_000_000_000L).setDefaultTimeZone(getTimeZone("GMT-01:00"));
+ @Rule
+ public DbTester db = DbTester.create(system2);
+
+ private final AsyncIssueIndexing asyncIssueIndexing = mock(AsyncIssueIndexing.class);
+ protected final IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()), asyncIssueIndexing);
+ protected final RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
+ protected final PermissionIndexerTester authorizationIndexer = new PermissionIndexerTester(es, issueIndexer);
+ protected final ViewIndexer viewIndexer = new ViewIndexer(db.getDbClient(), es.client());
+
+ protected final IssueIndex underTest = new IssueIndex(es.client(), system2, userSessionRule, new WebAuthorizationTypeSupport(userSessionRule));
+
+ /**
+ * Execute the search request and return the document ids of results.
+ */
+ protected List searchAndReturnKeys(IssueQuery.Builder query) {
+ return Arrays.stream(underTest.search(query.build(), new SearchOptions()).getHits().getHits())
+ .map(SearchHit::getId)
+ .collect(Collectors.toList());
+ }
+
+ protected void assertThatSearchReturnsOnly(IssueQuery.Builder query, String... expectedIssueKeys) {
+ List keys = searchAndReturnKeys(query);
+ assertThat(keys).containsExactlyInAnyOrder(expectedIssueKeys);
+ }
+
+ protected void assertThatSearchReturnsEmpty(IssueQuery.Builder query) {
+ List keys = searchAndReturnKeys(query);
+ assertThat(keys).isEmpty();
+ }
+
+ protected void indexIssues(IssueDoc... issues) {
+ issueIndexer.index(asList(issues).iterator());
+ authorizationIndexer.allow(stream(issues).map(issue -> new IndexPermissions(issue.projectUuid(), PROJECT).allowAnyone()).collect(toList()));
+ }
+
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java
index 462affd3087..9a825efd39a 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java
@@ -112,6 +112,8 @@ 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_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;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PCI_DSS_40;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS;
@@ -147,6 +149,8 @@ public class SearchAction implements IssuesWsAction {
PARAM_LANGUAGES,
PARAM_TAGS,
PARAM_TYPES,
+ PARAM_PCI_DSS_32,
+ PARAM_PCI_DSS_40,
PARAM_OWASP_TOP_10,
PARAM_OWASP_TOP_10_2021,
PARAM_SANS_TOP_25,
@@ -189,6 +193,8 @@ public class SearchAction implements IssuesWsAction {
+ "
When issue indexation is in progress returns 503 service unavailable HTTP code.")
.setSince("3.6")
.setChangelog(
+ new Change("9.6", "Added facets 'pciDss-3.2' and 'pciDss-4.0"),
+ new Change("9.6", "Added parameters 'pciDss-3.2' and 'pciDss-4.0"),
new Change("9.6", "Response field 'ruleDescriptionContextKey' added"),
new Change("9.6", "New possible value for 'additionalFields' parameter: 'ruleDescriptionContextKey'"),
new Change("9.6", "Facet 'moduleUuids' is dropped."),
@@ -261,6 +267,14 @@ public class SearchAction implements IssuesWsAction {
.setSince("5.5")
.setPossibleValues(ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS)
.setExampleValue(format("%s,%s", RuleType.CODE_SMELL, RuleType.BUG));
+ action.createParam(PARAM_PCI_DSS_32)
+ .setDescription("Comma-separated list of PCI DSS v3.2 categories.")
+ .setSince("9.6")
+ .setExampleValue("4,6.5.8,10.1");
+ action.createParam(PARAM_PCI_DSS_40)
+ .setDescription("Comma-separated list of PCI DSS v4.0 categories.")
+ .setSince("9.6")
+ .setExampleValue("4,6.5.8,10.1");
action.createParam(PARAM_OWASP_TOP_10)
.setDescription("Comma-separated list of OWASP Top 10 2017 lowercase categories.")
.setSince("7.3")
@@ -466,6 +480,8 @@ public class SearchAction implements IssuesWsAction {
setTypesFacet(facets);
+ addMandatoryValuesToFacet(facets, PARAM_PCI_DSS_32, request.getPciDss32());
+ addMandatoryValuesToFacet(facets, PARAM_PCI_DSS_40, request.getPciDss40());
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());
@@ -485,9 +501,7 @@ public class SearchAction implements IssuesWsAction {
Map buckets = facets.get(facetName);
if (buckets != null && mandatoryValues != null) {
for (String mandatoryValue : mandatoryValues) {
- if (!buckets.containsKey(mandatoryValue)) {
- buckets.put(mandatoryValue, 0L);
- }
+ buckets.putIfAbsent(mandatoryValue, 0L);
}
}
}
@@ -542,6 +556,8 @@ public class SearchAction implements IssuesWsAction {
.setStatuses(request.paramAsStrings(PARAM_STATUSES))
.setTags(request.paramAsStrings(PARAM_TAGS))
.setTypes(allRuleTypesExceptHotspotsIfEmpty(request.paramAsStrings(PARAM_TYPES)))
+ .setPciDss32(request.paramAsStrings(PARAM_PCI_DSS_32))
+ .setPciDss40(request.paramAsStrings(PARAM_PCI_DSS_40))
.setOwaspTop10(request.paramAsStrings(PARAM_OWASP_TOP_10))
.setOwaspTop10For2021(request.paramAsStrings(PARAM_OWASP_TOP_10_2021))
.setSansTop25(request.paramAsStrings(PARAM_SANS_TOP_25))
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 0d1d86a81e2..73573a7d074 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
@@ -214,8 +214,7 @@ public class SearchActionTest {
.getIssuesList()
.get(0)
.getActions()
- .getActionsList()
- ).isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY, ACTION_ASSIGN));
+ .getActionsList()).isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY, ACTION_ASSIGN));
response = ws.newRequest()
.setParam(PARAM_ADDITIONAL_FIELDS, "actions")
@@ -227,8 +226,7 @@ public class SearchActionTest {
.getIssuesList()
.get(0)
.getActions()
- .getActionsList()
- ).isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY));
+ .getActionsList()).isEqualTo(asList(ACTION_SET_TAGS, COMMENT_KEY));
}
@Test
@@ -1048,6 +1046,234 @@ public class SearchActionTest {
.containsExactly("82fd47d4-b650-4037-80bc-7b112bd4eac3", "82fd47d4-b650-4037-80bc-7b112bd4eac1", "82fd47d4-b650-4037-80bc-7b112bd4eac2");
}
+ @Test
+ public void only_vulnerabilities_are_returned_by_pciDss32() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ Consumer ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-3.2:6.5.3", "pciDss-3.2:10.1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer 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("pciDss-3.2", "10")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-3.2", "10.1")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
+ @Test
+ public void multiple_categories_pciDss32() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+
+ // Rule 1
+ Consumer ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-3.2:6.5.3", "pciDss-3.2:10.1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer 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));
+
+ // Rule 2
+ ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("pciDss-4.0:6.5.3", "pciDss-3.2:1.1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto4 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+
+ // Rule 3
+ ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("pciDss-4.0:6.5.3", "pciDss-3.2:2.3", "pciDss-3.2:10.1.2"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto5 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto6 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+
+ indexPermissionsAndIssues();
+
+ SearchWsResponse result = ws.newRequest()
+ .setParam("pciDss-3.2", "1,10")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey(), issueDto5.getKey(), issueDto6.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-3.2", "1")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto3.getKey(), issueDto4.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-3.2", "1,10,4")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey(), issueDto5.getKey(), issueDto6.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-3.2", "4")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList()).isEmpty();
+
+ result = ws.newRequest()
+ .setParam("pciDss-3.2", "4,7,12")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList()).isEmpty();
+
+ result = ws.newRequest()
+ .setParam("pciDss-3.2", "10.1")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
+ @Test
+ public void only_vulnerabilities_are_returned_by_pciDss40() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ Consumer ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-4.0:6.5.3", "pciDss-4.0:10.1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer 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("pciDss-4.0", "10,6,5")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-4.0", "10.1,6.5,5.5")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+ }
+
+ @Test
+ public void multiple_categories_pciDss40() {
+ ComponentDto project = db.components().insertPublicProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+
+ // Rule 1
+ Consumer ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("cwe:20", "owaspTop10:a1", "pciDss-4.0:6.5.3", "pciDss-4.0:10.1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ Consumer 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));
+
+ // Rule 2
+ ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("pciDss-4.0:6.5.3", "pciDss-4.0:1.1"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto4 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+
+ // Rule 3
+ ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+ .setSecurityStandards(Sets.newHashSet("pciDss-3.2:6.5.3", "pciDss-4.0:2.3"))
+ .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "owasp-a1", "sans-top25-insecure", "sql"));
+ hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+ db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+ issueRule = db.rules().insertIssueRule(ruleConsumer);
+ IssueDto issueDto5 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+ IssueDto issueDto6 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+
+ indexPermissionsAndIssues();
+
+ SearchWsResponse result = ws.newRequest()
+ .setParam("pciDss-4.0", "1,10")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-4.0", "1")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto3.getKey(), issueDto4.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-4.0", "1,10,4")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList())
+ .extracting(Issue::getKey)
+ .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey(), issueDto3.getKey(), issueDto4.getKey());
+
+ result = ws.newRequest()
+ .setParam("pciDss-4.0", "4")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList()).isEmpty();
+
+ result = ws.newRequest()
+ .setParam("pciDss-4.0", "4,7,12")
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(result.getIssuesList()).isEmpty();
+ }
+
@Test
public void only_vulnerabilities_are_returned_by_cwe() {
ComponentDto project = db.components().insertPublicProject();
@@ -1457,8 +1683,8 @@ public class SearchActionTest {
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", "owaspTop10", "owaspTop10-2021", "sansTop25",
- "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod");
+ "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", "statuses", "tags", "types", "pciDss-3.2", "pciDss-4.0", "owaspTop10",
+ "owaspTop10-2021", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod");
WebService.Param branch = def.param(PARAM_BRANCH);
assertThat(branch.isInternal()).isFalse();
--
2.39.5