this.flowGenerator = flowGenerator;
}
- public Optional<PushEventDto> raiseEventOnIssue(DefaultIssue currentIssue) {
+ public Optional<PushEventDto> raiseEventOnIssue(String projectUuid, DefaultIssue currentIssue) {
var currentIssueComponentUuid = currentIssue.componentUuid();
if (!taintChecker.isTaintVulnerability(currentIssue) || currentIssueComponentUuid == null) {
return Optional.empty();
var component = treeRootHolder.getComponentByUuid(Objects.requireNonNull(currentIssue.componentUuid()));
if (currentIssue.isNew() || currentIssue.isCopied() || isReopened(currentIssue)) {
- return Optional.of(raiseTaintVulnerabilityRaisedEvent(component, currentIssue));
+ return Optional.of(raiseTaintVulnerabilityRaisedEvent(projectUuid, component, currentIssue));
}
if (currentIssue.isBeingClosed()) {
- return Optional.of(raiseTaintVulnerabilityClosedEvent(currentIssue));
+ return Optional.of(raiseTaintVulnerabilityClosedEvent(projectUuid, currentIssue));
}
return Optional.empty();
}
return status != null && status.toString().equals("CLOSED|OPEN");
}
- private PushEventDto raiseTaintVulnerabilityRaisedEvent(Component component, DefaultIssue issue) {
+ private PushEventDto raiseTaintVulnerabilityRaisedEvent(String projectUuid, Component component, DefaultIssue issue) {
TaintVulnerabilityRaised event = prepareEvent(component, issue);
return new PushEventDto()
.setName("TaintVulnerabilityRaised")
- .setProjectUuid(treeRootHolder.getRoot().getUuid())
+ .setProjectUuid(projectUuid)
+ .setLanguage(issue.language())
.setPayload(serializeEvent(event));
}
return event;
}
- private PushEventDto raiseTaintVulnerabilityClosedEvent(DefaultIssue issue) {
+ private static PushEventDto raiseTaintVulnerabilityClosedEvent(String projectUuid, DefaultIssue issue) {
TaintVulnerabilityClosed event = new TaintVulnerabilityClosed(issue.key(), issue.projectKey());
return new PushEventDto()
.setName("TaintVulnerabilityClosed")
- .setProjectUuid(treeRootHolder.getRoot().getUuid())
+ .setProjectUuid(projectUuid)
+ .setLanguage(issue.language())
.setPayload(serializeEvent(event));
}
import java.util.Optional;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
import org.sonar.ce.task.projectanalysis.issue.ProtoIssueCache;
import org.sonar.ce.task.projectanalysis.pushevent.PushEventFactory;
import org.sonar.ce.task.step.ComputationStep;
private final DbClient dbClient;
private final ProtoIssueCache protoIssueCache;
private final PushEventFactory pushEventFactory;
+ private final TreeRootHolder treeRootHolder;
public PersistPushEventsStep(DbClient dbClient,
ProtoIssueCache protoIssueCache,
- PushEventFactory pushEventFactory) {
+ PushEventFactory pushEventFactory,
+ TreeRootHolder treeRootHolder) {
this.dbClient = dbClient;
this.protoIssueCache = protoIssueCache;
this.pushEventFactory = pushEventFactory;
+ this.treeRootHolder = treeRootHolder;
}
@Override
try (DbSession dbSession = dbClient.openSession(true);
CloseableIterator<DefaultIssue> issues = protoIssueCache.traverse()) {
int batchCounter = 0;
+ var projectUuid = getProjectUuid(dbSession);
while (issues.hasNext()) {
DefaultIssue currentIssue = issues.next();
- Optional<PushEventDto> raisedEvent = pushEventFactory.raiseEventOnIssue(currentIssue);
+ Optional<PushEventDto> raisedEvent = pushEventFactory.raiseEventOnIssue(projectUuid, currentIssue);
if (raisedEvent.isEmpty()) {
continue;
}
}
+ private String getProjectUuid(DbSession dbSession) {
+ var branch = dbClient.branchDao().selectByUuid(dbSession, treeRootHolder.getRoot().getUuid());
+ if (branch.isEmpty()) {
+ return treeRootHolder.getRoot().getUuid();
+ }
+ return branch.get().getProjectUuid();
+ }
+
private static int flushIfNeeded(DbSession dbSession, int batchCounter) {
if (batchCounter > MAX_BATCH_SIZE) {
flushSession(dbSession);
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.mockito.ArgumentMatcher;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils;
import org.sonar.core.issue.FieldDiffs;
import org.sonar.db.protobuf.DbCommons;
import org.sonar.db.protobuf.DbIssues;
-import org.sonar.db.pushevent.PushEventDto;
import org.sonar.server.issue.TaintChecker;
import static org.assertj.core.api.Assertions.assertThat;
DefaultIssue defaultIssue = createDefaultIssue()
.setNew(true);
- assertThat(underTest.raiseEventOnIssue(defaultIssue))
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityRaised");
assertThat(pushEventDto.getPayload()).isNotNull();
+ assertThat(pushEventDto.getLanguage()).isEqualTo("java");
+ assertThat(pushEventDto.getProjectUuid()).isEqualTo("some-project-uuid");
});
}
.setCopied(false)
.setCurrentChange(new FieldDiffs().setDiff("status", "CLOSED", "OPEN"));
- assertThat(underTest.raiseEventOnIssue(defaultIssue))
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityRaised");
@Test
public void skip_event_if_taint_vulnerability_status_change() {
DefaultIssue defaultIssue = createDefaultIssue()
- .setChanged(true)
- .setNew(false)
- .setCopied(false)
- .setCurrentChange(new FieldDiffs().setDiff("status", "OPEN", "FIXED"));
+ .setChanged(true)
+ .setNew(false)
+ .setCopied(false)
+ .setCurrentChange(new FieldDiffs().setDiff("status", "OPEN", "FIXED"));
- assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}
@Test
DefaultIssue defaultIssue = createDefaultIssue()
.setCopied(true);
- assertThat(underTest.raiseEventOnIssue(defaultIssue))
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityRaised");
.setCopied(false)
.setBeingClosed(true);
- assertThat(underTest.raiseEventOnIssue(defaultIssue))
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityClosed");
.setCreationDate(DateUtils.parseDate("2022-01-01"))
.setRuleKey(RuleKey.of("javasecurity", "S123"));
- assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}
@Test
when(taintChecker.isTaintVulnerability(any())).thenReturn(false);
- assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
defaultIssue = new DefaultIssue()
.setComponentUuid("issue-component-uuid")
.setType(RuleType.VULNERABILITY)
.setRuleKey(RuleKey.of("weirdrepo", "S123"));
- assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}
@Test
when(taintChecker.isTaintVulnerability(any())).thenReturn(false);
- assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}
@Test
when(taintChecker.isTaintVulnerability(any())).thenReturn(false);
- assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
+ assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}
private void buildComponentTree() {
return new DefaultIssue()
.setComponentUuid("issue-component-uuid")
.setType(RuleType.VULNERABILITY)
+ .setLanguage("java")
.setCreationDate(new Date())
.setLocations(DbIssues.Locations.newBuilder()
.addFlow(DbIssues.Flow.newBuilder()
.setRuleKey(RuleKey.of("javasecurity", "S123"));
}
- private static class PushEventMatcher implements ArgumentMatcher<PushEventDto> {
-
- private final PushEventDto left;
-
- static PushEventMatcher eq(PushEventDto left) {
- return new PushEventMatcher(left);
- }
-
- private PushEventMatcher(PushEventDto left) {
- this.left = left;
- }
-
- @Override
- public boolean matches(PushEventDto right) {
- return left.getName().equals(right.getName());
- }
- }
-
}
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.System2;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.MutableTreeRootHolderRule;
+import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.issue.ProtoIssueCache;
import org.sonar.ce.task.projectanalysis.pushevent.PushEventFactory;
import org.sonar.ce.task.step.ComputationStep;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public final PushEventFactory pushEventFactory = mock(PushEventFactory.class);
@Rule
public TemporaryFolder temp = new TemporaryFolder();
-
+ @Rule
+ public MutableTreeRootHolderRule treeRootHolder = new MutableTreeRootHolderRule();
private ProtoIssueCache protoIssueCache;
private PersistPushEventsStep underTest;
@Before
public void before() throws IOException {
protoIssueCache = new ProtoIssueCache(temp.newFile(), System2.INSTANCE);
- underTest = new PersistPushEventsStep(db.getDbClient(), protoIssueCache, pushEventFactory);
+ buildComponentTree();
+ underTest = new PersistPushEventsStep(db.getDbClient(), protoIssueCache, pushEventFactory, treeRootHolder);
}
@Test
createIssue("key1").setType(RuleType.VULNERABILITY))
.close();
- when(pushEventFactory.raiseEventOnIssue(any())).thenThrow(new RuntimeException("I have a bad feelings about this"));
+ when(pushEventFactory.raiseEventOnIssue(any(), any())).thenThrow(new RuntimeException("I have a bad feelings about this"));
assertThatCode(() -> underTest.execute(mock(ComputationStep.Context.class)))
.doesNotThrowAnyException();
.setComponentKey("ck2"))
.close();
- when(pushEventFactory.raiseEventOnIssue(any(DefaultIssue.class))).thenReturn(
+ when(pushEventFactory.raiseEventOnIssue(eq("uuid_1"), any(DefaultIssue.class))).thenReturn(
+ Optional.of(createPushEvent()),
+ Optional.of(createPushEvent()));
+
+ underTest.execute(mock(ComputationStep.Context.class));
+
+ assertThat(db.countSql(db.getSession(), "SELECT count(uuid) FROM push_events")).isEqualTo(2);
+ }
+
+ @Test
+ public void store_push_events_for_branch() {
+ var project = db.components().insertPrivateProject();
+ db.components().insertProjectBranch(project, b -> b.setUuid("uuid_1"));
+
+ protoIssueCache.newAppender()
+ .append(createIssue("key1").setType(RuleType.VULNERABILITY)
+ .setComponentUuid("cu1")
+ .setComponentKey("ck1"))
+ .append(createIssue("key2").setType(RuleType.VULNERABILITY)
+ .setComponentUuid("cu2")
+ .setComponentKey("ck2"))
+ .close();
+
+ when(pushEventFactory.raiseEventOnIssue(eq(project.uuid()), any(DefaultIssue.class))).thenReturn(
Optional.of(createPushEvent()),
Optional.of(createPushEvent()));
.setComponentUuid("cu" + value)
.setComponentKey("ck" + value);
appender.append(defaultIssue);
- when(pushEventFactory.raiseEventOnIssue(defaultIssue)).thenReturn(Optional.of(createPushEvent()));
+ when(pushEventFactory.raiseEventOnIssue(anyString(), eq(defaultIssue))).thenReturn(Optional.of(createPushEvent()));
});
appender.close();
return new PushEventDto().setProjectUuid("project-uuid").setName("event").setPayload("test".getBytes(UTF_8));
}
+ private void buildComponentTree() {
+ treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1)
+ .setUuid("uuid_1")
+ .addChildren(ReportComponent.builder(Component.Type.FILE, 2)
+ .setUuid("issue-component-uuid")
+ .build())
+ .addChildren(ReportComponent.builder(Component.Type.FILE, 3)
+ .setUuid("location-component-uuid")
+ .build())
+ .build());
+ }
+
}