You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PullTaintActionProtobufObjectGenerator.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.issue.ws.pull;
  21. import java.util.ArrayList;
  22. import java.util.HashMap;
  23. import java.util.HashSet;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import java.util.stream.Collectors;
  28. import org.sonar.api.rules.CleanCodeAttribute;
  29. import org.sonar.api.server.ServerSide;
  30. import org.sonar.db.DbClient;
  31. import org.sonar.db.DbSession;
  32. import org.sonar.db.component.ComponentDto;
  33. import org.sonar.db.issue.IssueDto;
  34. import org.sonar.db.protobuf.DbIssues;
  35. import org.sonar.db.rule.RuleDto;
  36. import org.sonar.server.user.UserSession;
  37. import org.sonar.server.ws.MessageFormattingUtils;
  38. import org.sonarqube.ws.Common;
  39. import org.sonarqube.ws.Issues;
  40. import static org.sonar.db.protobuf.DbIssues.Locations;
  41. import static org.sonarqube.ws.Issues.TaintVulnerabilityLite;
  42. import static org.sonarqube.ws.Issues.TaintVulnerabilityPullQueryTimestamp;
  43. @ServerSide
  44. public class PullTaintActionProtobufObjectGenerator implements ProtobufObjectGenerator {
  45. private final DbClient dbClient;
  46. private final UserSession userSession;
  47. private Map<String, ComponentDto> componentsMap;
  48. public PullTaintActionProtobufObjectGenerator(DbClient dbClient, UserSession userSession) {
  49. this.dbClient = dbClient;
  50. this.userSession = userSession;
  51. }
  52. @Override
  53. public TaintVulnerabilityPullQueryTimestamp generateTimestampMessage(long timestamp) {
  54. refreshComponents();
  55. TaintVulnerabilityPullQueryTimestamp.Builder responseBuilder = TaintVulnerabilityPullQueryTimestamp.newBuilder();
  56. responseBuilder.setQueryTimestamp(timestamp);
  57. return responseBuilder.build();
  58. }
  59. @Override
  60. public TaintVulnerabilityLite generateIssueMessage(IssueDto issueDto, RuleDto ruleDto) {
  61. TaintVulnerabilityLite.Builder taintBuilder = TaintVulnerabilityLite.newBuilder();
  62. Locations locations = issueDto.parseLocations();
  63. if (componentsMap == null) {
  64. refreshComponents();
  65. }
  66. Issues.Location.Builder locationBuilder = Issues.Location.newBuilder();
  67. if (issueDto.getMessage() != null) {
  68. locationBuilder.setMessage(issueDto.getMessage());
  69. locationBuilder.addAllMessageFormattings(MessageFormattingUtils.dbMessageFormattingToWs(issueDto.parseMessageFormattings()));
  70. }
  71. if (issueDto.getFilePath() != null) {
  72. locationBuilder.setFilePath(issueDto.getFilePath());
  73. }
  74. if (locations != null) {
  75. Issues.TextRange textRange = buildTextRange(locations);
  76. locationBuilder.setTextRange(textRange);
  77. getFlows(taintBuilder, locations, issueDto);
  78. }
  79. taintBuilder.setAssignedToSubscribedUser(issueDto.getAssigneeUuid() != null &&
  80. issueDto.getAssigneeUuid().equals(userSession.getUuid()));
  81. taintBuilder.setKey(issueDto.getKey());
  82. taintBuilder.setCreationDate(issueDto.getCreatedAt());
  83. taintBuilder.setResolved(issueDto.getStatus().equals(org.sonar.api.issue.Issue.STATUS_RESOLVED));
  84. taintBuilder.setRuleKey(issueDto.getRuleKey().toString());
  85. if (issueDto.getSeverity() != null) {
  86. taintBuilder.setSeverity(Common.Severity.valueOf(issueDto.getSeverity()));
  87. }
  88. taintBuilder.setType(Common.RuleType.forNumber(issueDto.getType()));
  89. CleanCodeAttribute cleanCodeAttribute = issueDto.getCleanCodeAttribute();
  90. String cleanCodeAttributeString = cleanCodeAttribute != null ? cleanCodeAttribute.name() : null;
  91. String cleanCodeAttributeCategoryString = cleanCodeAttribute != null ? cleanCodeAttribute.getAttributeCategory().name() : null;
  92. if (cleanCodeAttributeString != null) {
  93. taintBuilder.setCleanCodeAttribute(Common.CleanCodeAttribute.valueOf(cleanCodeAttributeString));
  94. taintBuilder.setCleanCodeAttributeCategory(Common.CleanCodeAttributeCategory.valueOf(cleanCodeAttributeCategoryString));
  95. }
  96. taintBuilder.addAllImpacts(issueDto.getEffectiveImpacts().entrySet()
  97. .stream().map(entry -> Common.Impact.newBuilder()
  98. .setSoftwareQuality(Common.SoftwareQuality.valueOf(entry.getKey().name()))
  99. .setSeverity(Common.ImpactSeverity.valueOf(entry.getValue().name()))
  100. .build())
  101. .toList());
  102. taintBuilder.setClosed(false);
  103. taintBuilder.setMainLocation(locationBuilder.build());
  104. issueDto.getOptionalRuleDescriptionContextKey().ifPresent(taintBuilder::setRuleDescriptionContextKey);
  105. return taintBuilder.build();
  106. }
  107. @Override
  108. public TaintVulnerabilityLite generateClosedIssueMessage(String uuid) {
  109. TaintVulnerabilityLite.Builder taintBuilder = TaintVulnerabilityLite.newBuilder();
  110. taintBuilder.setKey(uuid);
  111. taintBuilder.setClosed(true);
  112. return taintBuilder.build();
  113. }
  114. private void getFlows(TaintVulnerabilityLite.Builder taintBuilder, Locations locations, IssueDto issueDto) {
  115. List<Issues.Flow> flows = new ArrayList<>();
  116. for (DbIssues.Flow f : locations.getFlowList()) {
  117. Set<String> componentUuids = new HashSet<>();
  118. Issues.Flow.Builder builder = Issues.Flow.newBuilder();
  119. List<Issues.Location> flowLocations = new ArrayList<>();
  120. getComponentUuids(f, componentUuids);
  121. for (DbIssues.Location l : f.getLocationList()) {
  122. Issues.Location.Builder flowLocationBuilder = Issues.Location
  123. .newBuilder()
  124. .setMessage(l.getMsg())
  125. .setTextRange(buildTextRange(l));
  126. if (l.hasComponentId() && componentsMap.containsKey(l.getComponentId())) {
  127. flowLocationBuilder.setFilePath(componentsMap.get(l.getComponentId()).path());
  128. } else {
  129. flowLocationBuilder.setFilePath(issueDto.getFilePath());
  130. }
  131. flowLocations.add(flowLocationBuilder.build());
  132. }
  133. builder.addAllLocations(flowLocations);
  134. flows.add(builder.build());
  135. taintBuilder.addAllFlows(flows);
  136. }
  137. }
  138. private void getComponentUuids(DbIssues.Flow f, Set<String> componentUuids) {
  139. for (DbIssues.Location l : f.getLocationList()) {
  140. if (l.hasComponentId() && !componentsMap.containsKey(l.getComponentId())) {
  141. componentUuids.add(l.getComponentId());
  142. }
  143. }
  144. if (!componentUuids.isEmpty()) {
  145. componentsMap.putAll(getLocationComponents(componentUuids));
  146. }
  147. }
  148. private static Issues.TextRange buildTextRange(DbIssues.Location location) {
  149. int startLine = location.getTextRange().getStartLine();
  150. int endLine = location.getTextRange().getEndLine();
  151. int startOffset = location.getTextRange().getStartOffset();
  152. int endOffset = location.getTextRange().getEndOffset();
  153. return Issues.TextRange.newBuilder()
  154. .setHash(location.getChecksum())
  155. .setStartLine(startLine)
  156. .setEndLine(endLine)
  157. .setStartLineOffset(startOffset)
  158. .setEndLineOffset(endOffset).build();
  159. }
  160. private void refreshComponents() {
  161. componentsMap = new HashMap<>();
  162. }
  163. private Map<String, ComponentDto> getLocationComponents(Set<String> components) {
  164. try (DbSession dbSession = dbClient.openSession(false)) {
  165. return dbClient.componentDao().selectByUuids(dbSession, components)
  166. .stream().collect(Collectors.toMap(ComponentDto::uuid, c -> c));
  167. }
  168. }
  169. }