From fff67e1ec17bd17caf17a03ca6a5fd82f8043948 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Tue, 9 Feb 2021 15:53:44 -0600 Subject: [PATCH] SONAR-14361 WS 'hotspot/search' returns no issue if the 'sinceLeakPeriod' filter is used --- .../sonar/server/hotspot/ws/SearchAction.java | 36 ++++++++++---- .../server/hotspot/ws/SearchActionTest.java | 47 +++++++++++++++++++ 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java index 02a09e068b9..39237997739 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java @@ -50,7 +50,9 @@ import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.SnapshotDto; import org.sonar.db.issue.IssueDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.server.es.SearchOptions; import org.sonar.server.exceptions.NotFoundException; @@ -79,6 +81,7 @@ import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.DateUtils.longToDate; import static org.sonar.api.utils.Paging.forPageIndex; import static org.sonar.core.util.stream.MoreCollectors.toList; +import static org.sonar.core.util.stream.MoreCollectors.toSet; import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_INSECURE_INTERACTION; import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_POROUS_DEFENSES; @@ -320,8 +323,15 @@ public class SearchAction implements HotspotsWsAction { String projectUuid = firstNonNull(project.getMainBranchProjectUuid(), project.uuid()); if (Qualifiers.APP.equals(project.qualifier())) { builder.viewUuids(singletonList(projectUuid)); + addCreatedAfterByProjects(builder, dbSession, wsRequest, project); } else { builder.projectUuids(singletonList(projectUuid)); + if (wsRequest.isSinceLeakPeriod() && !wsRequest.getPullRequest().isPresent()) { + Date sinceDate = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, project.uuid()) + .map(s -> longToDate(s.getPeriodDate())) + .orElseGet(() -> new Date(system2.now())); + builder.createdAfter(sinceDate, false); + } } if (project.getMainBranchProjectUuid() == null) { @@ -330,13 +340,6 @@ public class SearchAction implements HotspotsWsAction { builder.branchUuid(project.uuid()); builder.mainBranch(false); } - - if (wsRequest.isSinceLeakPeriod() && !wsRequest.getPullRequest().isPresent()) { - Date sinceDate = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, project.uuid()) - .map(s -> longToDate(s.getPeriodDate())) - .orElseGet(() -> new Date(system2.now())); - builder.createdAfter(sinceDate, false); - } } if (!wsRequest.getHotspotKeys().isEmpty()) { @@ -366,9 +369,24 @@ public class SearchAction implements HotspotsWsAction { return issueIndex.search(query, searchOptions); } + private void addCreatedAfterByProjects(IssueQuery.Builder builder, DbSession dbSession, WsRequest wsRequest, ComponentDto application) { + if (!wsRequest.isSinceLeakPeriod() || wsRequest.getPullRequest().isPresent()) { + return; + } + + Set projectUuids = dbClient.applicationProjectsDao().selectProjects(dbSession, application.uuid()).stream() + .map(ProjectDto::getUuid) + .collect(Collectors.toSet()); + long now = system2.now(); + Map leakByProjects = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids).stream() + .collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> + new IssueQuery.PeriodStart(longToDate(s.getPeriodDate() == null ? now : s.getPeriodDate()), false))); + + builder.createdAfterByProjectUuids(leakByProjects); + } + private void loadComponents(DbSession dbSession, SearchResponseData searchResponseData) { - Set componentKeys = searchResponseData.getOrderedHotspots() - .stream() + Set componentKeys = searchResponseData.getOrderedHotspots().stream() .flatMap(hotspot -> Stream.of(hotspot.getComponentKey(), hotspot.getProjectKey())) .collect(Collectors.toSet()); if (!componentKeys.isEmpty()) { diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/SearchActionTest.java index 9c4258ccb43..198fdbc078d 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/SearchActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/SearchActionTest.java @@ -51,6 +51,7 @@ import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.issue.IssueDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.db.rule.RuleTesting; import org.sonar.server.es.EsTester; @@ -1499,6 +1500,52 @@ public class SearchActionTest { assertThat(responseOnLeak.getHotspotsList()).hasSize(3); } + @Test + public void returns_issues_when_sinceLeakPeriod_is_true_and_is_application() { + long referenceDate = 800_996_999_332L; + + system2.setNow(referenceDate + 10_000); + ComponentDto application = dbTester.components().insertPublicApplication(); + ComponentDto project = dbTester.components().insertPublicProject(); + ComponentDto project2 = dbTester.components().insertPublicProject(); + + dbTester.components().addApplicationProject(application, project); + dbTester.components().addApplicationProject(application, project2); + + dbTester.components().insertComponent(ComponentTesting.newProjectCopy(project, application)); + dbTester.components().insertComponent(ComponentTesting.newProjectCopy(project2, application)); + + indexViews(); + + userSessionRule.registerComponents(application, project, project2); + indexPermissions(); + ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); + dbTester.components().insertSnapshot(project, t -> t.setPeriodDate(referenceDate).setLast(true)); + RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT); + IssueDto afterRef = dbTester.issues().insertHotspot(rule, project, file, t -> t.setIssueCreationTime(referenceDate + 1000)); + IssueDto atRef = dbTester.issues().insertHotspot(rule, project, file, t -> t.setType(SECURITY_HOTSPOT).setIssueCreationTime(referenceDate)); + IssueDto beforeRef = dbTester.issues().insertHotspot(rule, project, file, t -> t.setIssueCreationTime(referenceDate - 1000)); + + ComponentDto file2 = dbTester.components().insertComponent(newFileDto(project2)); + IssueDto project2Issue = dbTester.issues().insertHotspot(rule, project2, file2, t -> t.setIssueCreationTime(referenceDate - 1000)); + + indexIssues(); + + SearchWsResponse responseAll = newRequest(application) + .executeProtobuf(SearchWsResponse.class); + assertThat(responseAll.getHotspotsList()) + .extracting(SearchWsResponse.Hotspot::getKey) + .containsExactlyInAnyOrder(afterRef.getKey(), atRef.getKey(), beforeRef.getKey(), project2Issue.getKey()); + + SearchWsResponse responseOnLeak = newRequest(application, + t -> t.setParam("sinceLeakPeriod", "true")) + .executeProtobuf(SearchWsResponse.class); + assertThat(responseOnLeak.getHotspotsList()) + .extracting(SearchWsResponse.Hotspot::getKey) + .containsExactlyInAnyOrder(afterRef.getKey()); + + } + @Test public void verify_response_example() { ComponentDto project = dbTester.components().insertPublicProject(componentDto -> componentDto -- 2.39.5