aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-webapi
diff options
context:
space:
mode:
authorantoine.vinot <antoine.vinot@sonarsource.com>2024-09-04 14:31:58 +0200
committersonartech <sonartech@sonarsource.com>2024-09-12 20:02:54 +0000
commit574637dc96a0655344a0623fa1aae861fe073a86 (patch)
treed6a3b299b9c243c8a4a1182ecc73cb07650a47fa /server/sonar-webserver-webapi
parent1d44e3b465b8df3ad3a0c63d17b2b24ef529fd79 (diff)
downloadsonarqube-574637dc96a0655344a0623fa1aae861fe073a86.tar.gz
sonarqube-574637dc96a0655344a0623fa1aae861fe073a86.zip
SONAR-22914 Create and update APIs for CVEs
Diffstat (limited to 'server/sonar-webserver-webapi')
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionDependenciesIT.java117
-rw-r--r--server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/SearchActionDependenciesIT.java129
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsResponseFormatter.java1
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java2
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java3
5 files changed, 251 insertions, 1 deletions
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionDependenciesIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionDependenciesIT.java
new file mode 100644
index 00000000000..87b282c9e16
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionDependenciesIT.java
@@ -0,0 +1,117 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.hotspot.ws;
+
+import java.util.Arrays;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.api.impl.utils.TestSystem2;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ProjectData;
+import org.sonar.db.dependency.CveDto;
+import org.sonar.db.dependency.IssuesDependencyDto;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.component.TestComponentFinder;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.issue.TextRangeResponseFormatter;
+import org.sonar.server.issue.index.AsyncIssueIndexing;
+import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.issue.index.IssueIndexSyncProgressChecker;
+import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.issue.index.IssueIteratorFactory;
+import org.sonar.server.permission.index.PermissionIndexerTester;
+import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.Hotspots.SearchWsResponse;
+import org.sonarqube.ws.Hotspots.SearchWsResponse.Hotspot;
+
+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.db.component.ComponentTesting.newFileDto;
+
+class SearchActionDependenciesIT {
+
+ @RegisterExtension
+ private final UserSessionRule userSession = UserSessionRule.standalone();
+ @RegisterExtension
+ private final DbTester db = DbTester.create();
+ @RegisterExtension
+ private final EsTester es = EsTester.create();
+
+ private final TestSystem2 system2 = new TestSystem2();
+ private final DbClient dbClient = db.getDbClient();
+ private final IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
+ private final IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient), mock(AsyncIssueIndexing.class));
+ private final PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
+ private final HotspotWsResponseFormatter responseFormatter = new HotspotWsResponseFormatter(new TextRangeResponseFormatter());
+ private final IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = mock(IssueIndexSyncProgressChecker.class);
+ private final ComponentFinder componentFinder = TestComponentFinder.from(db);
+ private final SearchAction underTest = new SearchAction(dbClient, userSession, issueIndex,
+ issueIndexSyncProgressChecker, responseFormatter, system2, componentFinder);
+ private final WsActionTester ws = new WsActionTester(underTest);
+
+ private RuleDto rule;
+ private ProjectData projectData;
+ private ComponentDto project;
+ private ComponentDto projectFile;
+
+ @BeforeEach
+ void setup() {
+ rule = db.rules().insertHotspotRule();
+ projectData = db.components().insertPublicProject();
+ project = projectData.getMainBranchComponent();
+ projectFile = db.components().insertComponent(newFileDto(project));
+ }
+
+ @Test
+ void search_whenAttachedToCve_shouldReturnsCveId() {
+ insertHotspotWithCve("1");
+ insertHotspotWithCve("2");
+ allowAnyoneOnProjects(projectData.getProjectDto());
+ issueIndexer.indexAllIssues();
+
+ SearchWsResponse searchWsResponse = ws.newRequest().setParam("project", project.getKey()).executeProtobuf(SearchWsResponse.class);
+
+ assertThat(searchWsResponse.getHotspotsList())
+ .extracting(Hotspot::getKey, Hotspot::getCveId).containsExactlyInAnyOrder(tuple("hotspot_key_1", "CVE-1"), tuple("hotspot_key_2", "CVE-2"));
+ }
+
+ private void insertHotspotWithCve(String suffix) {
+ IssueDto issueDto = db.issues().insertHotspot(rule, project, projectFile, issue -> issue.setKee("hotspot_key_"+suffix));
+ var cveDto = new CveDto("cve_uuid_"+suffix, "CVE-"+suffix, "Some CVE description "+suffix, 1.0, 2.0, 3.0, 4L, 5L, 6L, 7L);
+ db.getDbClient().cveDao().insert(db.getSession(), cveDto);
+ db.issues().insertIssuesDependency(new IssuesDependencyDto(issueDto.getKee(), cveDto.uuid()));
+ }
+
+ private void allowAnyoneOnProjects(ProjectDto... projects) {
+ userSession.registerProjects(projects);
+ Arrays.stream(projects).forEach(permissionIndexer::allowOnlyAnyone);
+ }
+
+}
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/SearchActionDependenciesIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/SearchActionDependenciesIT.java
new file mode 100644
index 00000000000..f7bf2db5d24
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/SearchActionDependenciesIT.java
@@ -0,0 +1,129 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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.ws;
+
+import java.time.Clock;
+import java.util.Arrays;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.utils.Durations;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ProjectData;
+import org.sonar.db.dependency.CveDto;
+import org.sonar.db.dependency.IssuesDependencyDto;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.common.avatar.AvatarResolverImpl;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.issue.IssueFieldsSetter;
+import org.sonar.server.issue.TextRangeResponseFormatter;
+import org.sonar.server.issue.TransitionService;
+import org.sonar.server.issue.index.AsyncIssueIndexing;
+import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.issue.index.IssueIndexSyncProgressChecker;
+import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.issue.index.IssueIteratorFactory;
+import org.sonar.server.issue.index.IssueQueryFactory;
+import org.sonar.server.issue.workflow.FunctionExecutor;
+import org.sonar.server.issue.workflow.IssueWorkflow;
+import org.sonar.server.permission.index.PermissionIndexerTester;
+import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.Issues.Issue;
+import org.sonarqube.ws.Issues.SearchWsResponse;
+
+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.db.component.ComponentTesting.newFileDto;
+
+class SearchActionDependenciesIT {
+
+ @RegisterExtension
+ private final UserSessionRule userSession = UserSessionRule.standalone();
+ @RegisterExtension
+ private final DbTester db = DbTester.create();
+ @RegisterExtension
+ private final EsTester es = EsTester.create();
+
+ private final DbClient dbClient = db.getDbClient();
+ private final IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
+ private final IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient), mock(AsyncIssueIndexing.class));
+ private final IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
+ private final IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
+ private final IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
+ private final SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
+ private final Languages languages = new Languages();
+ private final UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
+ private final SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
+ private final PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
+
+ private final IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = new IssueIndexSyncProgressChecker(db.getDbClient());
+
+ private final WsActionTester ws = new WsActionTester(
+ new SearchAction(userSession, issueIndex, issueQueryFactory, issueIndexSyncProgressChecker, searchResponseLoader, searchResponseFormat,
+ System2.INSTANCE, dbClient));
+
+ private RuleDto rule;
+ private ProjectData projectData;
+ private ComponentDto project;
+ private ComponentDto projectFile;
+
+ @BeforeEach
+ void setup() {
+ rule = db.rules().insertIssueRule();
+ projectData = db.components().insertPublicProject();
+ project = projectData.getMainBranchComponent();
+ projectFile = db.components().insertComponent(newFileDto(project));
+ }
+
+ @Test
+ void search_whenAttachedToCve_shouldReturnsCveId() {
+ insertIssueWithCve("1");
+ insertIssueWithCve("2");
+ allowAnyoneOnProjects(projectData.getProjectDto());
+ issueIndexer.indexAllIssues();
+
+ SearchWsResponse searchWsResponse = ws.newRequest().executeProtobuf(SearchWsResponse.class);
+
+ assertThat(searchWsResponse.getIssuesList())
+ .extracting(Issue::getKey, Issue::getCveId).containsExactlyInAnyOrder(tuple("issue_key_1", "CVE-1"), tuple("issue_key_2", "CVE-2"));
+ }
+
+ private void insertIssueWithCve(String suffix) {
+ IssueDto issueDto = db.issues().insertIssue(rule, project, projectFile, issue -> issue.setKee("issue_key_"+suffix));
+ var cveDto = new CveDto("cve_uuid_"+suffix, "CVE-"+suffix, "Some CVE description "+suffix, 1.0, 2.0, 3.0, 4L, 5L, 6L, 7L);
+ db.getDbClient().cveDao().insert(db.getSession(), cveDto);
+ db.issues().insertIssuesDependency(new IssuesDependencyDto(issueDto.getKee(), cveDto.uuid()));
+ }
+
+ private void allowAnyoneOnProjects(ProjectDto... projects) {
+ userSession.registerProjects(projects);
+ Arrays.stream(projects).forEach(permissionIndexer::allowOnlyAnyone);
+ }
+
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsResponseFormatter.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsResponseFormatter.java
index 90ab338bb21..16afe8303c8 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsResponseFormatter.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsResponseFormatter.java
@@ -113,6 +113,7 @@ public class HotspotWsResponseFormatter {
builder.setCreationDate(formatDateTime(hotspot.getIssueCreationDate()));
builder.setUpdateDate(formatDateTime(hotspot.getIssueUpdateDate()));
completeHotspotLocations(hotspot, builder, searchResponseData);
+ ofNullable(hotspot.getCveId()).ifPresent(builder::setCveId);
hotspotsList.add(builder.build());
}
return hotspotsList;
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java
index 318ff72b1f6..e309eed6fae 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java
@@ -230,6 +230,8 @@ public class SearchResponseFormat {
issueBuilder.setScope(UNIT_TEST_FILE.equals(component.qualifier()) ? IssueScope.TEST.name() : IssueScope.MAIN.name());
issueBuilder.setPrioritizedRule(dto.isPrioritizedRule());
+
+ Optional.ofNullable(dto.getCveId()).ifPresent(issueBuilder::setCveId);
}
private static void addAdditionalFieldsToIssueBuilder(Collection<SearchAdditionalField> fields, SearchResponseData data, IssueDto dto, Issue.Builder issueBuilder) {
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java
index 94455620be7..47706fd3e39 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseLoader.java
@@ -126,7 +126,8 @@ public class SearchResponseLoader {
.toList();
return issueKeys.stream()
- .map(new KeyToIssueFunction(unorderedIssues)).filter(Objects::nonNull)
+ .map(new KeyToIssueFunction(unorderedIssues))
+ .filter(Objects::nonNull)
.toList();
}