12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346 |
- /*
- * SonarQube
- * Copyright (C) 2009-2023 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 com.google.common.collect.ImmutableSet;
- import com.google.common.collect.Sets;
- import com.tngtech.java.junit.dataprovider.DataProvider;
- import com.tngtech.java.junit.dataprovider.DataProviderRunner;
- import com.tngtech.java.junit.dataprovider.UseDataProvider;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Random;
- import java.util.Set;
- import java.util.function.Consumer;
- import java.util.function.Supplier;
- import java.util.stream.Collectors;
- import java.util.stream.IntStream;
- import java.util.stream.Stream;
- import javax.annotation.Nullable;
- import org.assertj.core.groups.Tuple;
- import org.junit.Rule;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.mockito.ArgumentMatcher;
- import org.mockito.Mockito;
- import org.sonar.api.issue.Issue;
- import org.sonar.api.rules.RuleType;
- import org.sonar.api.utils.System2;
- import org.sonar.api.web.UserRole;
- import org.sonar.core.util.UuidFactory;
- import org.sonar.core.util.UuidFactoryFast;
- import org.sonar.db.DbClient;
- import org.sonar.db.DbSession;
- import org.sonar.db.DbTester;
- import org.sonar.db.component.BranchType;
- import org.sonar.db.component.ComponentDto;
- import org.sonar.db.component.ProjectData;
- import org.sonar.db.issue.IssueDto;
- import org.sonar.db.project.ProjectDto;
- import org.sonar.db.protobuf.DbCommons.TextRange;
- import org.sonar.db.protobuf.DbIssues;
- import org.sonar.db.protobuf.DbIssues.Flow;
- import org.sonar.db.protobuf.DbIssues.FlowType;
- import org.sonar.db.rule.RuleDescriptionSectionContextDto;
- import org.sonar.db.rule.RuleDescriptionSectionDto;
- import org.sonar.db.rule.RuleDto;
- import org.sonar.db.rule.RuleTesting;
- import org.sonar.db.user.UserDto;
- import org.sonar.db.user.UserTesting;
- import org.sonar.server.es.EsTester;
- import org.sonar.server.exceptions.ForbiddenException;
- import org.sonar.server.exceptions.NotFoundException;
- import org.sonar.server.common.avatar.AvatarResolver;
- import org.sonar.server.common.avatar.AvatarResolverImpl;
- import org.sonar.server.issue.IssueChangeWSSupport;
- import org.sonar.server.issue.IssueChangeWSSupport.FormattingContext;
- import org.sonar.server.issue.IssueChangeWSSupport.Load;
- import org.sonar.server.issue.TextRangeResponseFormatter;
- import org.sonar.server.issue.ws.UserResponseFormatter;
- import org.sonar.server.security.SecurityStandards;
- import org.sonar.server.security.SecurityStandards.SQCategory;
- import org.sonar.server.tester.UserSessionRule;
- import org.sonar.server.ws.TestRequest;
- import org.sonar.server.ws.WsActionTester;
- import org.sonarqube.ws.Common;
- import org.sonarqube.ws.Common.Changelog.Diff;
- import org.sonarqube.ws.Common.Location;
- import org.sonarqube.ws.Common.User;
- import org.sonarqube.ws.Hotspots;
-
- import static java.util.Collections.emptySet;
- import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
- import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
- import static org.assertj.core.api.Assertions.assertThat;
- import static org.assertj.core.api.Assertions.assertThatThrownBy;
- import static org.assertj.core.api.Assertions.tuple;
- import static org.mockito.ArgumentMatchers.any;
- import static org.mockito.ArgumentMatchers.anySet;
- import static org.mockito.ArgumentMatchers.argThat;
- import static org.mockito.ArgumentMatchers.eq;
- import static org.mockito.Mockito.verify;
- import static org.mockito.Mockito.when;
- import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
- import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
- import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
- import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.INTRODUCTION_SECTION_KEY;
- import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.RESOURCES_SECTION_KEY;
- import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY;
- import static org.sonar.db.component.ComponentTesting.newFileDto;
- import static org.sonar.db.protobuf.DbIssues.MessageFormattingType.CODE;
- import static org.sonar.db.rule.RuleDescriptionSectionDto.DEFAULT_KEY;
- import static org.sonar.db.rule.RuleDto.Format.HTML;
- import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
-
- @RunWith(DataProviderRunner.class)
- public class ShowActionIT {
- private static final Random RANDOM = new Random();
- public static final DbIssues.MessageFormatting MESSAGE_FORMATTING = DbIssues.MessageFormatting.newBuilder().setStart(0).setEnd(4).setType(CODE).build();
-
- @Rule
- public DbTester dbTester = DbTester.create(System2.INSTANCE);
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
-
- private final DbClient dbClient = dbTester.getDbClient();
- private final AvatarResolver avatarResolver = new AvatarResolverImpl();
- private final TextRangeResponseFormatter textRangeFormatter = new TextRangeResponseFormatter();
- private final HotspotWsResponseFormatter responseFormatter = new HotspotWsResponseFormatter(textRangeFormatter);
- private final IssueChangeWSSupport issueChangeSupport = Mockito.mock(IssueChangeWSSupport.class);
- private final HotspotWsSupport hotspotWsSupport = new HotspotWsSupport(dbClient, userSessionRule, System2.INSTANCE);
- private final UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
- private final ShowAction underTest = new ShowAction(dbClient, hotspotWsSupport, responseFormatter, userFormatter, issueChangeSupport);
- private final WsActionTester actionTester = new WsActionTester(underTest);
- private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
-
- @Test
- public void ws_is_public() {
- assertThat(actionTester.getDef().isInternal()).isFalse();
- }
-
- @Test
- public void fails_with_IAE_if_parameter_hotspot_is_missing() {
- TestRequest request = actionTester.newRequest();
-
- assertThatThrownBy(request::execute)
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("The 'hotspot' parameter is missing");
- }
-
- @Test
- public void fails_with_NotFoundException_if_hotspot_does_not_exist() {
- String key = randomAlphabetic(12);
- TestRequest request = actionTester.newRequest()
- .setParam("hotspot", key);
-
- assertThatThrownBy(request::execute)
- .isInstanceOf(NotFoundException.class)
- .hasMessage("Hotspot '%s' does not exist", key);
- }
-
- @Test
- @UseDataProvider("ruleTypesButHotspot")
- public void fails_with_NotFoundException_if_issue_is_not_a_hotspot(RuleType ruleType) {
- ComponentDto mainBranchComponent = dbTester.components().insertPublicProject().getMainBranchComponent();
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(ruleType);
- IssueDto notAHotspot = dbTester.issues().insertIssue(rule, mainBranchComponent, file, i -> i.setType(ruleType));
- TestRequest request = newRequest(notAHotspot);
-
- assertThatThrownBy(request::execute)
- .isInstanceOf(NotFoundException.class)
- .hasMessage("Hotspot '%s' does not exist", notAHotspot.getKey());
- }
-
- @DataProvider
- public static Object[][] ruleTypesButHotspot() {
- return Arrays.stream(RuleType.values())
- .filter(t -> t != SECURITY_HOTSPOT)
- .map(t -> new Object[] {t})
- .toArray(Object[][]::new);
- }
-
- @Test
- public void fails_with_NotFoundException_if_issue_is_hotspot_is_closed() {
- ComponentDto mainBranchComponent = dbTester.components().insertPublicProject().getMainBranchComponent();
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setStatus(Issue.STATUS_CLOSED));
- TestRequest request = newRequest(hotspot);
-
- assertThatThrownBy(request::execute)
- .isInstanceOf(NotFoundException.class)
- .hasMessage("Hotspot '%s' does not exist", hotspot.getKey());
- }
-
- @Test
- public void fails_with_ForbiddenException_if_project_is_private_and_not_allowed() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- TestRequest request = newRequest(hotspot);
-
- assertThatThrownBy(request::execute)
- .isInstanceOf(ForbiddenException.class)
- .hasMessage("Insufficient privileges");
- }
-
- @Test
- public void succeeds_on_hotspot_with_flow() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- ComponentDto anotherFile = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- DbIssues.Locations.Builder locations = DbIssues.Locations.newBuilder()
- .addFlow(Flow.newBuilder()
- .setDescription("FLOW DESCRIPTION")
- .setType(FlowType.DATA)
- .addAllLocation(Arrays.asList(
- DbIssues.Location.newBuilder()
- .setComponentId(file.uuid())
- .setMsg("FLOW MESSAGE")
- .addMsgFormatting(MESSAGE_FORMATTING)
- .setTextRange(textRange(1, 1, 0, 12)).build(),
- DbIssues.Location.newBuilder()
- .setComponentId(anotherFile.uuid())
- .setMsg("ANOTHER FLOW MESSAGE")
- .setTextRange(textRange(1, 1, 0, 12)).build(),
- DbIssues.Location.newBuilder()
- .setMsg("FLOW MESSAGE WITHOUT FILE UUID")
- .setTextRange(textRange(1, 1, 0, 12)).build())))
- .addFlow(Flow.newBuilder()
- .addLocation(DbIssues.Location.newBuilder()
- .setComponentId(file.uuid())
- .setTextRange(TextRange.newBuilder().setStartLine(1).setStartOffset(0).setEndOffset(12).build())
- .build()))
- .addFlow(Flow.newBuilder()
- .setType(FlowType.EXECUTION)
- .addLocation(DbIssues.Location.newBuilder()
- .setComponentId(file.uuid())
- .build()));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- var hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, i -> i.setLocations(locations.build()));
- mockChangelogAndCommentsFormattingContext();
- userSessionRule.registerProjects(projectData.getProjectDto());
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getKey()).isEqualTo(hotspot.getKey());
- assertThat(response.getFlowsCount()).isEqualTo(3);
- assertThat(response.getFlows(0).getDescription()).isEqualTo("FLOW DESCRIPTION");
- assertThat(response.getFlows(0).getType()).isEqualTo(Common.FlowType.DATA);
- assertThat(response.getFlows(0).getLocationsList())
- .extracting(Location::getMsg, Location::getMsgFormattingsList, Location::getComponent)
- .containsExactlyInAnyOrder(
- tuple("FLOW MESSAGE", List.of(Common.MessageFormatting.newBuilder()
- .setStart(0).setEnd(4).setType(Common.MessageFormattingType.CODE).build()), file.getKey()),
- tuple("ANOTHER FLOW MESSAGE", List.of(), anotherFile.getKey()),
- tuple("FLOW MESSAGE WITHOUT FILE UUID", List.of(), file.getKey()));
-
- assertThat(response.getFlows(1).getDescription()).isEmpty();
- assertThat(response.getFlows(1).hasType()).isFalse();
-
- assertThat(response.getFlows(2).getType()).isEqualTo(Common.FlowType.EXECUTION);
- }
-
- @Test
- public void succeeds_on_public_project() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getKey()).isEqualTo(hotspot.getKey());
- }
-
- @Test
- public void succeeds_on_private_project_with_permission() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getKey()).isEqualTo(hotspot.getKey());
- }
-
- @Test
- public void return_canChangeStatus_false_on_public_project_when_anonymous() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto project = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getCanChangeStatus()).isFalse();
- }
-
- @Test
- @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN")
- public void return_canChangeStatus_false_on_public_project_when_authenticated_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.logIn().registerProjects(projectData.getProjectDto());
- if (permission != null) {
- userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
- }
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getCanChangeStatus()).isFalse();
- }
-
- @Test
- @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN")
- public void return_canChangeStatus_true_on_public_project_when_authenticated_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto())
- .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, projectData.getProjectDto());
- if (permission != null) {
- userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
- }
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getCanChangeStatus()).isTrue();
- }
-
- @DataProvider
- public static Object[][] allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN() {
- return new Object[][] {
- {null}, // no permission
- {UserRole.ADMIN},
- {UserRole.SCAN},
- {UserRole.ISSUE_ADMIN}
- };
- }
-
- @Test
- @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER")
- public void return_canChangeStatus_false_on_private_project_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
- userSessionRule
- .registerProjects(projectData.getProjectDto())
- .logIn()
- .addProjectPermission(UserRole.USER, projectData.getProjectDto());
- if (permission != null) {
- userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
- }
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getCanChangeStatus()).isFalse();
- }
-
- @Test
- @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER")
- public void return_canChangeStatus_false_on_private_project_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranch = projectData.getMainBranchComponent();
- userSessionRule
- .registerProjects(projectData.getProjectDto())
- .logIn()
- .addProjectPermission(UserRole.USER, projectData.getProjectDto())
- .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, projectData.getProjectDto());
- if (permission != null) {
- userSessionRule.addProjectPermission(permission, projectData.getProjectDto());
- }
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranch));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranch, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getCanChangeStatus()).isTrue();
- }
-
- @DataProvider
- public static Object[][] allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER() {
- return new Object[][] {
- {null}, // only USER permission
- {UserRole.CODEVIEWER},
- {UserRole.ADMIN},
- {UserRole.SCAN},
- {UserRole.ISSUE_ADMIN}
- };
- }
-
- @Test
- @UseDataProvider("statusAndResolutionCombinations")
- public void returns_status_and_resolution(String status, @Nullable String resolution) {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setStatus(status).setResolution(resolution));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getStatus()).isEqualTo(status);
- if (resolution == null) {
- assertThat(response.hasResolution()).isFalse();
- } else {
- assertThat(response.getResolution()).isEqualTo(resolution);
- }
- }
-
- @DataProvider
- public static Object[][] statusAndResolutionCombinations() {
- return new Object[][] {
- {Issue.STATUS_TO_REVIEW, null},
- {Issue.STATUS_REVIEWED, Issue.RESOLUTION_FIXED},
- {Issue.STATUS_REVIEWED, Issue.RESOLUTION_SAFE}
- };
- }
-
- @Test
- public void dispatch_description_sections_of_advanced_rule_in_relevant_field() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
-
- RuleDescriptionSectionDto introductionSection = generateSectionWithKey(INTRODUCTION_SECTION_KEY);
- RuleDescriptionSectionDto rootCauseSection = generateSectionWithKey(ROOT_CAUSE_SECTION_KEY);
- RuleDescriptionSectionDto assesTheProblemSection = generateSectionWithKey(ASSESS_THE_PROBLEM_SECTION_KEY);
- RuleDescriptionSectionDto resourcesSection = generateSectionWithKey(RESOURCES_SECTION_KEY);
- RuleDescriptionSectionDto howToFixSection = generateSectionWithKey(HOW_TO_FIX_SECTION_KEY);
- RuleDescriptionSectionDto dummySection = generateSectionWithKey("dummySection");
-
- RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
- r -> r.addRuleDescriptionSectionDto(introductionSection)
- .addRuleDescriptionSectionDto(rootCauseSection)
- .addRuleDescriptionSectionDto(assesTheProblemSection)
- .addRuleDescriptionSectionDto(resourcesSection)
- .addRuleDescriptionSectionDto(howToFixSection)
- .addRuleDescriptionSectionDto(dummySection)
- .setDescriptionFormat(HTML));
-
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getRule().getRiskDescription()).isEqualTo(rootCauseSection.getContent());
- assertThat(response.getRule().getVulnerabilityDescription()).isEqualTo(assesTheProblemSection.getContent());
- assertThat(response.getRule().getFixRecommendations()).isEqualTo(howToFixSection.getContent());
- }
-
- @Test
- public void fallbacks_to_default_section_in_case_of_legacy_rule() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
-
- RuleDescriptionSectionDto introductionSection = generateSectionWithKey(DEFAULT_KEY);
-
- RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
- r -> r.addRuleDescriptionSectionDto(introductionSection)
- .setDescriptionFormat(HTML));
-
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getRule().getRiskDescription()).isEqualTo(introductionSection.getContent());
- assertThat(response.getRule().getVulnerabilityDescription()).isEmpty();
- assertThat(response.getRule().getFixRecommendations()).isEmpty();
- }
-
- @Test
- public void ignore_default_section_if_root_cause_provided() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
-
- RuleDescriptionSectionDto introductionSection = generateSectionWithKey(INTRODUCTION_SECTION_KEY);
- RuleDescriptionSectionDto rootCauseSection = generateSectionWithKey(ROOT_CAUSE_SECTION_KEY);
- RuleDescriptionSectionDto assesTheProblemSection = generateSectionWithKey(ASSESS_THE_PROBLEM_SECTION_KEY);
-
- RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
- r -> r.addRuleDescriptionSectionDto(introductionSection)
- .addRuleDescriptionSectionDto(rootCauseSection)
- .addRuleDescriptionSectionDto(assesTheProblemSection)
- .setDescriptionFormat(HTML));
-
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getRule().getRiskDescription()).isEqualTo(rootCauseSection.getContent());
- assertThat(response.getRule().getVulnerabilityDescription()).isEqualTo(assesTheProblemSection.getContent());
- assertThat(response.getRule().getFixRecommendations()).isEmpty();
- }
-
- private RuleDescriptionSectionDto generateSectionWithKey(String assessTheProblemSectionKey) {
- return RuleDescriptionSectionDto.builder()
- .uuid(uuidFactory.create())
- .key(assessTheProblemSectionKey)
- .content(randomAlphabetic(200))
- .build();
- }
-
- @Test
- public void returns_html_description_for_custom_rules() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
-
- String description = "== Title\n<div>line1\nline2</div>";
-
- RuleDescriptionSectionDto sectionDto = RuleDescriptionSectionDto.builder()
- .uuid(uuidFactory.create())
- .key(DEFAULT_KEY)
- .content(description)
- .build();
-
- RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
- r -> r.setTemplateUuid("123")
- .addRuleDescriptionSectionDto(sectionDto)
- .setDescriptionFormat(MARKDOWN));
-
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getRule().getRiskDescription()).isEqualTo("<h2>Title</h2><div>line1<br/>line2</div>");
- }
-
- @Test
- public void handles_null_description_for_custom_rules() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
-
- RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT, r -> r.setTemplateUuid("123"));
-
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getRule().getRiskDescription()).isNullOrEmpty();
- }
-
- @Test
- public void handle_given_description_section_with_3_contexts_return_one_alphabetically() {
- ProjectData projectData = dbTester.components().insertPrivateProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- userSessionRule.logIn().addProjectPermission(UserRole.USER, projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
-
- RuleDescriptionSectionDto vaadinSection = newContextSpecificDescriptionSection("vaadin");
- RuleDescriptionSectionDto gsonSection = newContextSpecificDescriptionSection("gson");
- RuleDescriptionSectionDto springSection = newContextSpecificDescriptionSection("spring");
-
- RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
- r -> r.setTemplateUuid("123")
- .addRuleDescriptionSectionDto(vaadinSection)
- .addRuleDescriptionSectionDto(springSection)
- .addRuleDescriptionSectionDto(gsonSection)
- .setDescriptionFormat(HTML));
-
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getRule().getFixRecommendations()).isEqualTo("gson description");
- }
-
- private RuleDescriptionSectionDto newContextSpecificDescriptionSection(String context) {
- return RuleDescriptionSectionDto.builder()
- .uuid(uuidFactory.create())
- .key(HOW_TO_FIX_SECTION_KEY)
- .content(context + " description")
- .context(RuleDescriptionSectionContextDto.of(context.toLowerCase(), context.toUpperCase()))
- .build();
- }
-
- @Test
- public void returns_hotspot_component_and_rule() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getKey()).isEqualTo(hotspot.getKey());
- verifyComponent(response.getComponent(), file, null, null);
- verifyProject(response.getProject(), projectData.getProjectDto(), null, null);
- verifyRule(response.getRule(), rule);
- assertThat(response.hasTextRange()).isFalse();
- }
-
- @Test
- public void returns_no_textRange_when_locations_have_none() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
- t -> t.setLocations(DbIssues.Locations.newBuilder().build()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.hasTextRange()).isFalse();
- }
-
- @Test
- @UseDataProvider("randomTextRangeValues")
- public void returns_textRange(int startLine, int endLine, int startOffset, int endOffset) {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
- t -> t.setLocations(DbIssues.Locations.newBuilder().setTextRange(textRange(startLine, endLine, startOffset, endOffset)).build()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.hasTextRange()).isTrue();
- Common.TextRange textRange = response.getTextRange();
- assertThat(textRange.getStartLine()).isEqualTo(startLine);
- assertThat(textRange.getEndLine()).isEqualTo(endLine);
- assertThat(textRange.getStartOffset()).isEqualTo(startOffset);
- assertThat(textRange.getEndOffset()).isEqualTo(endOffset);
- }
-
- @Test
- public void returns_no_assignee_when_user_does_not_exist() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(randomAlphabetic(10)));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.hasAssignee()).isFalse();
- }
-
- @Test
- public void returns_assignee_details_when_user_exists() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- UserDto assignee = dbTester.users().insertUser();
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(assignee.getUuid()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getAssignee()).isEqualTo(assignee.getLogin());
- assertThat(response.getUsersList()).hasSize(1);
- User wsAssignee = response.getUsersList().iterator().next();
- assertThat(wsAssignee.getLogin()).isEqualTo(assignee.getLogin());
- assertThat(wsAssignee.getName()).isEqualTo(assignee.getName());
- assertThat(wsAssignee.getActive()).isEqualTo(assignee.isActive());
- assertThat(wsAssignee.getAvatar()).isEqualTo(avatarResolver.create(assignee));
- }
-
- @Test
- public void returns_no_avatar_if_assignee_has_no_email() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- UserDto assignee = dbTester.users().insertUser(t -> t.setEmail(null));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(assignee.getUuid()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList()).hasSize(1);
- assertThat(response.getUsersList().iterator().next().hasAvatar()).isFalse();
- }
-
- @Test
- public void returns_inactive_when_assignee_is_inactive() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- UserDto assignee = dbTester.users().insertUser(t -> t.setActive(false));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAssigneeUuid(assignee.getUuid()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList()).hasSize(1);
- assertThat(response.getUsersList().iterator().next().getActive()).isFalse();
- }
-
- @Test
- public void returns_author_login_when_user_does_not_exist() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- String authorLogin = randomAlphabetic(10);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(authorLogin));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList()).isEmpty();
- assertThat(response.getAuthor()).isEqualTo(authorLogin);
- }
-
- @Test
- public void returns_author_details_when_user_exists() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- UserDto author = dbTester.users().insertUser();
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(author.getLogin()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getAuthor()).isEqualTo(author.getLogin());
- User wsAuthorFromList = response.getUsersList().iterator().next();
- assertThat(wsAuthorFromList.getLogin()).isEqualTo(author.getLogin());
- assertThat(wsAuthorFromList.getName()).isEqualTo(author.getName());
- assertThat(wsAuthorFromList.getActive()).isEqualTo(author.isActive());
- assertThat(wsAuthorFromList.getAvatar()).isEqualTo(avatarResolver.create(author));
- }
-
- @Test
- public void returns_no_avatar_if_author_has_no_email() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- UserDto author = dbTester.users().insertUser(t -> t.setEmail(null));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(author.getLogin()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList()).hasSize(1);
- assertThat(response.getUsersList().iterator().next().hasAvatar()).isFalse();
- }
-
- @Test
- public void returns_inactive_if_author_is_inactive() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- UserDto author = dbTester.users().insertUser(t -> t.setActive(false));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setAuthorLogin(author.getLogin()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList()).hasSize(1);
- assertThat(response.getUsersList().iterator().next().getActive()).isFalse();
- }
-
- @DataProvider
- public static Object[][] randomTextRangeValues() {
- int startLine = RANDOM.nextInt(200);
- int endLine = RANDOM.nextInt(200);
- int startOffset = RANDOM.nextInt(200);
- int endOffset = RANDOM.nextInt(200);
- return new Object[][] {
- {startLine, endLine, startOffset, endOffset}
- };
- }
-
- @Test
- public void returns_textRange_missing_fields() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
- t -> t.setLocations(DbIssues.Locations.newBuilder()
- .setTextRange(TextRange.newBuilder().build())
- .build()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.hasTextRange()).isTrue();
- Common.TextRange textRange = response.getTextRange();
- assertThat(textRange.hasStartLine()).isFalse();
- assertThat(textRange.hasEndLine()).isFalse();
- assertThat(textRange.hasStartOffset()).isFalse();
- assertThat(textRange.hasEndOffset()).isFalse();
- }
-
- @Test
- @UseDataProvider("allSQCategoryAndVulnerabilityProbability")
- public void returns_securityCategory_and_vulnerabilityProbability_of_rule(Set<String> standards,
- SQCategory expected) {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT, t -> t.setSecurityStandards(standards));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
- t -> t.setLocations(DbIssues.Locations.newBuilder()
- .setTextRange(TextRange.newBuilder().build())
- .build()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- Hotspots.Rule wsRule = response.getRule();
- assertThat(wsRule.getSecurityCategory()).isEqualTo(expected.getKey());
- assertThat(wsRule.getVulnerabilityProbability()).isEqualTo(expected.getVulnerability().name());
- }
-
- @DataProvider
- public static Object[][] allSQCategoryAndVulnerabilityProbability() {
- Stream<Object[]> allButOthers = SecurityStandards.CWES_BY_SQ_CATEGORY
- .entrySet()
- .stream()
- .map(t -> new Object[] {
- t.getValue().stream().map(s -> "cwe:" + s).collect(Collectors.toSet()),
- t.getKey()
- });
- Stream<Object[]> others = Stream.of(
- new Object[] {emptySet(), SQCategory.OTHERS},
- new Object[] {ImmutableSet.of("foo", "bar", "acme"), SQCategory.OTHERS});
- return Stream.concat(allButOthers, others)
- .toArray(Object[][]::new);
- }
-
- @Test
- public void returns_project_twice_when_hotspot_on_project() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, mainBranchComponent,
- t -> t.setLocations(DbIssues.Locations.newBuilder()
- .setTextRange(TextRange.newBuilder().build())
- .build()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- verifyProject(response.getProject(), projectData.getProjectDto(), null, null);
- verifyComponent(response.getComponent(), mainBranchComponent, null, null);
- }
-
- @Test
- public void returns_branch_but_no_pullRequest_on_component_and_project_on_non_main_branch() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
- String branchName = randomAlphanumeric(248);
- ComponentDto branch = dbTester.components().insertProjectBranch(mainBranchComponent, b -> b.setKey(branchName));
- userSessionRule.addProjectBranchMapping(mainBranchComponent.uuid(), branch);
- ComponentDto file = dbTester.components().insertComponent(newFileDto(branch, mainBranchComponent.uuid()));
- userSessionRule.registerProjects(projectData.getProjectDto());
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, branch, file,
- t -> t.setLocations(DbIssues.Locations.newBuilder()
- .setTextRange(TextRange.newBuilder().build())
- .build()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- verifyProject(response.getProject(), projectData.getProjectDto(), branchName, null);
- verifyComponent(response.getComponent(), file, branchName, null);
- }
-
- @Test
- public void returns_pullRequest_but_no_branch_on_component_and_project_on_pullRequest() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
- String pullRequestKey = randomAlphanumeric(100);
- ComponentDto pullRequest = dbTester.components().insertProjectBranch(mainBranchComponent,
- t -> t.setBranchType(BranchType.PULL_REQUEST).setKey(pullRequestKey));
- userSessionRule.addProjectBranchMapping(mainBranchComponent.uuid(), pullRequest);
- ComponentDto file = dbTester.components().insertComponent(newFileDto(pullRequest));
- userSessionRule.registerProjects(projectData.getProjectDto());
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, pullRequest, file,
- t -> t.setLocations(DbIssues.Locations.newBuilder()
- .setTextRange(TextRange.newBuilder().build())
- .build()));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- verifyProject(response.getProject(), projectData.getProjectDto(), null, pullRequestKey);
- verifyComponent(response.getComponent(), file, null, pullRequestKey);
- }
-
- @Test
- public void returns_hotspot_changelog_and_comments() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
- t -> t.setLocations(DbIssues.Locations.newBuilder()
- .setTextRange(TextRange.newBuilder().build())
- .build()));
- List<Common.Changelog> changelog = IntStream.range(0, 1 + new Random().nextInt(12))
- .mapToObj(i -> Common.Changelog.newBuilder().setUser("u" + i).build())
- .toList();
- List<Common.Comment> comments = IntStream.range(0, 1 + new Random().nextInt(12))
- .mapToObj(i -> Common.Comment.newBuilder().setKey("u" + i).build())
- .toList();
- FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
- when(issueChangeSupport.formatChangelog(any(), any())).thenReturn(changelog.stream());
- when(issueChangeSupport.formatComments(any(), any(), any())).thenReturn(comments.stream());
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getChangelogList())
- .extracting(Common.Changelog::getUser)
- .containsExactly(changelog.stream().map(Common.Changelog::getUser).toArray(String[]::new));
- assertThat(response.getCommentList())
- .extracting(Common.Comment::getKey)
- .containsExactly(comments.stream().map(Common.Comment::getKey).toArray(String[]::new));
- verify(issueChangeSupport).newFormattingContext(any(DbSession.class), argThat(new IssueDtoSetArgumentMatcher(hotspot)), eq(Load.ALL), eq(emptySet()), eq(Set.of(file)));
- verify(issueChangeSupport).formatChangelog(argThat(new IssueDtoArgumentMatcher(hotspot)), eq(formattingContext));
- verify(issueChangeSupport).formatComments(argThat(new IssueDtoArgumentMatcher(hotspot)), any(Common.Comment.Builder.class), eq(formattingContext));
- }
-
- @Test
- public void returns_user_details_of_users_from_ChangelogAndComments() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file);
- FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
- Set<UserDto> changeLogAndCommentsUsers = IntStream.range(0, 1 + RANDOM.nextInt(14))
- .mapToObj(i -> UserTesting.newUserDto())
- .collect(Collectors.toSet());
- when(formattingContext.getUsers()).thenReturn(changeLogAndCommentsUsers);
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList())
- .extracting(User::getLogin, User::getName, User::getActive)
- .containsExactlyInAnyOrder(
- changeLogAndCommentsUsers.stream()
- .map(t -> tuple(t.getLogin(), t.getName(), t.isActive()))
- .toArray(Tuple[]::new));
- }
-
- @Test
- public void returns_user_of_users_from_ChangelogAndComments_and_assignee_and_author() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- UserDto author = dbTester.users().insertUser();
- UserDto assignee = dbTester.users().insertUser();
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
- t -> t.setAuthorLogin(author.getLogin())
- .setAssigneeUuid(assignee.getUuid()));
- FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
- Set<UserDto> changeLogAndCommentsUsers = IntStream.range(0, 1 + RANDOM.nextInt(14))
- .mapToObj(i -> UserTesting.newUserDto())
- .collect(Collectors.toSet());
- when(formattingContext.getUsers()).thenReturn(changeLogAndCommentsUsers);
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList())
- .extracting(User::getLogin, User::getName, User::getActive)
- .containsExactlyInAnyOrder(
- Stream.concat(
- Stream.of(author, assignee),
- changeLogAndCommentsUsers.stream())
- .map(t -> tuple(t.getLogin(), t.getName(), t.isActive()))
- .toArray(Tuple[]::new));
- }
-
- @Test
- public void do_not_duplicate_user_if_author_assignee_ChangeLogComment_user() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- UserDto author = dbTester.users().insertUser();
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file,
- t -> t.setAuthorLogin(author.getLogin())
- .setAssigneeUuid(author.getUuid()));
- FormattingContext formattingContext = mockChangelogAndCommentsFormattingContext();
- when(formattingContext.getUsers()).thenReturn(ImmutableSet.of(author));
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getUsersList())
- .extracting(User::getLogin, User::getName, User::getActive)
- .containsOnly(tuple(author.getLogin(), author.getName(), author.isActive()));
- }
-
- @Test
- public void response_shouldContainCodeVariants() {
- ProjectData projectData = dbTester.components().insertPublicProject();
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto());
- ComponentDto file = dbTester.components().insertComponent(newFileDto(mainBranchComponent));
- RuleDto rule = newRule(SECURITY_HOTSPOT);
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, t -> t.setCodeVariants(List.of("variant1", "variant2")));
- mockChangelogAndCommentsFormattingContext();
-
- Hotspots.ShowWsResponse response = newRequest(hotspot)
- .executeProtobuf(Hotspots.ShowWsResponse.class);
-
- assertThat(response.getCodeVariantsList()).containsOnly("variant1", "variant2");
- }
-
- @Test
- public void verify_response_example() {
- ProjectData projectData = dbTester.components().insertPublicProject(componentDto -> componentDto
- .setName("test-project")
- .setLongName("test-project")
- .setKey("com.sonarsource:test-project"));
- ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
-
- userSessionRule.registerProjects(projectData.getProjectDto())
- .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, projectData.getProjectDto());
-
- ComponentDto file = dbTester.components().insertComponent(
- newFileDto(mainBranchComponent)
- .setKey("com.sonarsource:test-project:src/main/java/com/sonarsource/FourthClass.java")
- .setName("FourthClass.java")
- .setLongName("src/main/java/com/sonarsource/FourthClass.java")
- .setPath("src/main/java/com/sonarsource/FourthClass.java"));
- UserDto author = dbTester.users().insertUser(u -> u.setLogin("joe")
- .setName("Joe"));
-
- long time = 1577976190000L;
- RuleDto rule = newRule(SECURITY_HOTSPOT, r -> r.setRuleKey("S4787")
- .setRepositoryKey("java")
- .setName("rule-name")
- .setSecurityStandards(Sets.newHashSet(SQCategory.WEAK_CRYPTOGRAPHY.getKey())));
- IssueDto hotspot = dbTester.issues().insertHotspot(rule, mainBranchComponent, file, h -> h
- .setAssigneeUuid("assignee-uuid")
- .setAuthorLogin("joe")
- .setMessage("message")
- .setMessageFormattings(DbIssues.MessageFormattings.newBuilder().addMessageFormatting(MESSAGE_FORMATTING).build())
- .setLine(10)
- .setChecksum("a227e508d6646b55a086ee11d63b21e9")
- .setIssueCreationTime(time)
- .setIssueUpdateTime(time)
- .setAuthorLogin(author.getLogin())
- .setAssigneeUuid(author.getUuid())
- .setKee("AW9mgJw6eFC3pGl94Wrf")
- .setCodeVariants(List.of("windows", "linux")));
-
- List<Common.Changelog> changelog = IntStream.range(0, 3)
- .mapToObj(i -> Common.Changelog.newBuilder()
- .setUser("joe")
- .setCreationDate("2020-01-02T14:44:55+0100")
- .addDiffs(Diff.newBuilder().setKey("diff-key-" + i).setNewValue("new-value-" + i).setOldValue("old-value-" + i))
- .setIsUserActive(true)
- .setUserName("Joe")
- .setAvatar("my-avatar")
- .build())
- .toList();
- List<Common.Comment> comments = IntStream.range(0, 3)
- .mapToObj(i -> Common.Comment.newBuilder()
- .setKey("comment-" + i)
- .setHtmlText("html text " + i)
- .setLogin("Joe")
- .setMarkdown("markdown " + i)
- .setCreatedAt("2020-01-02T14:47:47+0100")
- .build())
- .toList();
-
- mockChangelogAndCommentsFormattingContext();
- when(issueChangeSupport.formatChangelog(any(), any())).thenReturn(changelog.stream());
- when(issueChangeSupport.formatComments(any(), any(), any())).thenReturn(comments.stream());
-
- assertThat(actionTester.getDef().responseExampleAsString()).isNotNull();
- newRequest(hotspot)
- .execute()
- .assertJson(actionTester.getDef().responseExampleAsString());
- }
-
- private FormattingContext mockChangelogAndCommentsFormattingContext() {
- FormattingContext formattingContext = Mockito.mock(FormattingContext.class);
- when(issueChangeSupport.newFormattingContext(any(), any(), any(), anySet(), anySet())).thenReturn(formattingContext);
- return formattingContext;
- }
-
- private void verifyRule(Hotspots.Rule wsRule, RuleDto dto) {
- assertThat(wsRule.getKey()).isEqualTo(dto.getKey().toString());
- assertThat(wsRule.getName()).isEqualTo(dto.getName());
- assertThat(wsRule.getSecurityCategory()).isEqualTo(SQCategory.OTHERS.getKey());
- assertThat(wsRule.getVulnerabilityProbability()).isEqualTo(SQCategory.OTHERS.getVulnerability().name());
- }
-
- private static void verifyComponent(Hotspots.Component wsComponent, ComponentDto dto, @Nullable String branch, @Nullable String pullRequest) {
- assertThat(wsComponent.getKey()).isEqualTo(dto.getKey());
- if (dto.path() == null) {
- assertThat(wsComponent.hasPath()).isFalse();
- } else {
- assertThat(wsComponent.getPath()).isEqualTo(dto.path());
- }
- assertThat(wsComponent.getQualifier()).isEqualTo(dto.qualifier());
- assertThat(wsComponent.getName()).isEqualTo(dto.name());
- assertThat(wsComponent.getLongName()).isEqualTo(dto.longName());
- if (branch == null) {
- assertThat(wsComponent.hasBranch()).isFalse();
- } else {
- assertThat(wsComponent.getBranch()).isEqualTo(branch);
- }
- if (pullRequest == null) {
- assertThat(wsComponent.hasPullRequest()).isFalse();
- } else {
- assertThat(wsComponent.getPullRequest()).isEqualTo(pullRequest);
- }
- }
-
- private static void verifyProject(Hotspots.Component wsComponent, ProjectDto dto, @Nullable String branch, @Nullable String pullRequest) {
- assertThat(wsComponent.getKey()).isEqualTo(dto.getKey());
- assertThat(wsComponent.hasPath()).isFalse();
- assertThat(wsComponent.getQualifier()).isEqualTo(dto.getQualifier());
- assertThat(wsComponent.getName()).isEqualTo(dto.getName());
- assertThat(wsComponent.getLongName()).isEqualTo(dto.getName());
- if (branch == null) {
- assertThat(wsComponent.hasBranch()).isFalse();
- } else {
- assertThat(wsComponent.getBranch()).isEqualTo(branch);
- }
- if (pullRequest == null) {
- assertThat(wsComponent.hasPullRequest()).isFalse();
- } else {
- assertThat(wsComponent.getPullRequest()).isEqualTo(pullRequest);
- }
- }
-
- private static TextRange textRange(int startLine, int endLine, int startOffset, int endOffset) {
- return TextRange.newBuilder()
- .setStartLine(startLine)
- .setEndLine(endLine)
- .setStartOffset(startOffset)
- .setEndOffset(endOffset)
- .build();
- }
-
- private TestRequest newRequest(IssueDto hotspot) {
- return actionTester.newRequest()
- .setParam("hotspot", hotspot.getKey());
- }
-
- private RuleDto newRule(RuleType ruleType) {
- return newRule(ruleType, t -> {
- });
- }
-
- private RuleDto newRule(RuleType ruleType, Consumer<RuleDto> populate) {
- return newRule(ruleType, RuleTesting::newRule, populate);
- }
-
- private RuleDto newRuleWithoutSection(RuleType ruleType, Consumer<RuleDto> populate) {
- return newRule(ruleType, RuleTesting::newRuleWithoutDescriptionSection, populate);
- }
-
- private RuleDto newRule(RuleType ruleType, Supplier<RuleDto> ruleDefinitionDtoSupplier, Consumer<RuleDto> populate) {
- RuleDto ruleDefinitionDto = ruleDefinitionDtoSupplier.get().setType(ruleType);
- populate.accept(ruleDefinitionDto);
- dbTester.rules().insert(ruleDefinitionDto);
- return ruleDefinitionDto;
- }
-
- private static class IssueDtoSetArgumentMatcher implements ArgumentMatcher<Set<IssueDto>> {
- private final IssueDto expected;
-
- private IssueDtoSetArgumentMatcher(IssueDto expected) {
- this.expected = expected;
- }
-
- @Override
- public boolean matches(Set<IssueDto> argument) {
- return argument != null && argument.size() == 1 && argument.iterator().next().getKey().equals(expected.getKey());
- }
-
- @Override
- public String toString() {
- return "Set<IssueDto>[" + expected.getKey() + "]";
- }
- }
-
- private static class IssueDtoArgumentMatcher implements ArgumentMatcher<IssueDto> {
- private final IssueDto expected;
-
- private IssueDtoArgumentMatcher(IssueDto expected) {
- this.expected = expected;
- }
-
- @Override
- public boolean matches(IssueDto argument) {
- return argument != null && argument.getKey().equals(expected.getKey());
- }
-
- @Override
- public String toString() {
- return "IssueDto[key=" + expected.getKey() + "]";
- }
- }
-
- }
|