Skip to content

Commit aa4cc54

Browse files
xieshenzhzvigrinberg
authored andcommitted
feat: support multi-source
1 parent 845f7d2 commit aa4cc54

17 files changed

+674
-105
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ dependencies {
6363

6464
implementation 'org.kohsuke:github-api:1.314'
6565
implementation 'org.apache.commons:commons-compress:1.21'
66-
implementation 'com.redhat.exhort:exhort-java-api:0.0.3-SNAPSHOT'
66+
implementation 'com.redhat.exhort:exhort-java-api:1.0.0-SNAPSHOT'
6767
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
6868

6969
testImplementation('junit:junit:4.13.1')

src/main/java/org/jboss/tools/intellij/componentanalysis/CAAnnotator.java

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@
3131
import org.jetbrains.annotations.NotNull;
3232
import org.jetbrains.annotations.Nullable;
3333

34-
import java.util.List;
35-
import java.util.Map;
36-
import java.util.Set;
34+
import java.util.*;
3735
import java.util.stream.Collectors;
3836

3937
public abstract class CAAnnotator extends ExternalAnnotator<CAAnnotator.Info, Map<Dependency, CAAnnotator.Result>> {
@@ -82,7 +80,7 @@ public abstract class CAAnnotator extends ExternalAnnotator<CAAnnotator.Info, Ma
8280
}
8381

8482
LOG.info("Get vulnerability report from cache");
85-
Map<Dependency, DependencyReport> reports = CAService.getReports(path);
83+
Map<Dependency, Map<VulnerabilitySource, DependencyReport>> reports = CAService.getReports(path);
8684
return this.matchDependencies(info.getDependencies(), reports);
8785
}
8886

@@ -94,38 +92,79 @@ public void apply(@NotNull PsiFile file, Map<Dependency, Result> annotationResul
9492
LOG.info("Annotate dependencies");
9593
annotationResult.forEach((key, value) -> {
9694
if (value != null) {
97-
DependencyReport report = value.getReport();
95+
Map<VulnerabilitySource, DependencyReport> reports = value.getReports();
9896
List<PsiElement> elements = value.getElements();
99-
if (report.getIssues() != null && !report.getIssues().isEmpty()
97+
if (reports != null && !reports.isEmpty()
10098
&& elements != null && !elements.isEmpty()) {
101-
if (report.getRef() != null) {
102-
String d = getDependencyString(report.getRef().purl());
103-
int num = report.getIssues().size();
104-
String m = d + ", " + "Known security vulnerabilities: " + num + ", ";
105-
String t = "<html>" +
106-
"<p>" + d + "</p>" +
107-
"<p>Known security vulnerabilities: " + num + "</p>";
108-
109-
if (report.getHighestVulnerability() != null && report.getHighestVulnerability().getSeverity() != null) {
110-
String severity = report.getHighestVulnerability().getSeverity().getValue();
111-
m += "Highest severity: " + severity + ", ";
112-
t += "<p>Highest severity: " + severity + "</p>";
113-
}
99+
Optional<DependencyReport> reportOptional = reports.values().stream()
100+
.filter(Objects::nonNull).findAny();
101+
102+
if (reportOptional.isPresent() && reportOptional.get().getRef() != null) {
103+
String name = getDependencyString(reportOptional.get().getRef().purl());
104+
105+
StringBuilder messageBuilder = new StringBuilder(name);
106+
StringBuilder tooltipBuilder = new StringBuilder("<html>").append("<p>").append(name).append("</p>");
107+
Map<VulnerabilitySource, DependencyReport> quickfixes = new HashMap<>();
108+
109+
reports.forEach((source, report) -> {
110+
if (report.getIssues() != null && !report.getIssues().isEmpty()) {
111+
messageBuilder.append(System.lineSeparator());
112+
tooltipBuilder.append("<p/>");
114113

115-
m += "Dependency Analytics Plugin [Powered by Snyk]";
116-
t += "<p>Dependency Analytics Plugin [Powered by <a href='https://snyk.io/'>Snyk</a>]</p>" +
117-
"</html>";
114+
if (source.getProvider().equals(source.getSource())) {
115+
messageBuilder.append(source.getProvider())
116+
.append(" vulnerability info: ");
117+
tooltipBuilder.append("<p>")
118+
.append(source.getProvider())
119+
.append(" vulnerability info:</p>");
120+
} else {
121+
messageBuilder.append(source.getSource())
122+
.append(" (")
123+
.append(source.getProvider())
124+
.append(") vulnerability info: ");
125+
tooltipBuilder.append("<p>")
126+
.append(source.getSource())
127+
.append(" (")
128+
.append(source.getProvider())
129+
.append(") vulnerability info:</p>");
130+
}
131+
132+
int num = report.getIssues().size();
133+
messageBuilder.append("Known security vulnerabilities: ")
134+
.append(num);
135+
tooltipBuilder.append("<p>Known security vulnerabilities: ")
136+
.append(num)
137+
.append("</p>");
138+
139+
if (report.getHighestVulnerability() != null && report.getHighestVulnerability().getSeverity() != null) {
140+
String severity = report.getHighestVulnerability().getSeverity().getValue();
141+
messageBuilder.append(", Highest severity: ")
142+
.append(severity);
143+
tooltipBuilder.append("<p>Highest severity: ")
144+
.append(severity)
145+
.append("</p>");
146+
}
147+
}
118148

119-
String message = m;
120-
String tooltip = t;
149+
if (CAIntentionAction.isQuickFixAvailable(report)) {
150+
quickfixes.put(source, report);
151+
}
152+
});
121153

122154
elements.forEach(e -> {
123155
if (e != null) {
124156
AnnotationBuilder builder = holder
125-
.newAnnotation(HighlightSeverity.ERROR, message)
126-
.tooltip(tooltip)
127-
.range(e)
128-
.withFix(new CAIntentionAction());
157+
.newAnnotation(HighlightSeverity.ERROR, messageBuilder.toString())
158+
.tooltip(tooltipBuilder.toString())
159+
.range(e);
160+
161+
builder.withFix(new SAIntentionAction());
162+
163+
if (!quickfixes.isEmpty() && this.isQuickFixApplicable(e)) {
164+
quickfixes.forEach((source, report) ->
165+
builder.withFix(this.createQuickFix(e, source, report)));
166+
}
167+
129168
builder.create();
130169
}
131170
});
@@ -139,8 +178,12 @@ public void apply(@NotNull PsiFile file, Map<Dependency, Result> annotationResul
139178

140179
abstract protected Map<Dependency, List<PsiElement>> getDependencies(PsiFile file);
141180

181+
abstract protected CAIntentionAction createQuickFix(PsiElement element, VulnerabilitySource source, DependencyReport report);
182+
183+
abstract protected boolean isQuickFixApplicable(PsiElement element);
184+
142185
private Map<Dependency, Result> matchDependencies(Map<Dependency, List<PsiElement>> dependencies,
143-
Map<Dependency, DependencyReport> reports) {
186+
Map<Dependency, Map<VulnerabilitySource, DependencyReport>> reports) {
144187
if (dependencies != null && !dependencies.isEmpty()
145188
&& reports != null && !reports.isEmpty()) {
146189
return dependencies.entrySet()
@@ -217,19 +260,19 @@ public Map<Dependency, List<PsiElement>> getDependencies() {
217260

218261
public static class Result {
219262
List<PsiElement> elements;
220-
DependencyReport report;
263+
Map<VulnerabilitySource, DependencyReport> reports;
221264

222-
public Result(List<PsiElement> elements, DependencyReport report) {
265+
public Result(List<PsiElement> elements, Map<VulnerabilitySource, DependencyReport> reports) {
223266
this.elements = elements;
224-
this.report = report;
267+
this.reports = reports;
225268
}
226269

227270
public List<PsiElement> getElements() {
228271
return elements;
229272
}
230273

231-
public DependencyReport getReport() {
232-
return report;
274+
public Map<VulnerabilitySource, DependencyReport> getReports() {
275+
return reports;
233276
}
234277
}
235278
}

src/main/java/org/jboss/tools/intellij/componentanalysis/CAIntentionAction.java

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,62 +11,73 @@
1111

1212
package org.jboss.tools.intellij.componentanalysis;
1313

14-
import com.google.gson.JsonObject;
14+
import com.intellij.codeInsight.intention.FileModifier;
1515
import com.intellij.codeInsight.intention.IntentionAction;
1616
import com.intellij.codeInspection.util.IntentionFamilyName;
1717
import com.intellij.codeInspection.util.IntentionName;
1818
import com.intellij.openapi.editor.Editor;
19-
import com.intellij.openapi.fileEditor.FileEditorManager;
2019
import com.intellij.openapi.project.Project;
21-
import com.intellij.openapi.vfs.VirtualFile;
20+
import com.intellij.psi.PsiElement;
2221
import com.intellij.psi.PsiFile;
22+
import com.intellij.psi.util.PsiTreeUtil;
2323
import com.intellij.util.IncorrectOperationException;
24-
import org.jboss.tools.intellij.stackanalysis.SaUtils;
24+
import com.redhat.exhort.api.DependencyReport;
2525
import org.jetbrains.annotations.NotNull;
26+
import org.jetbrains.annotations.Nullable;
2627

27-
import java.io.IOException;
28+
public abstract class CAIntentionAction implements IntentionAction {
29+
30+
protected @SafeFieldForPreview PsiElement element;
31+
protected @SafeFieldForPreview VulnerabilitySource source;
32+
protected @SafeFieldForPreview DependencyReport report;
33+
34+
protected CAIntentionAction(PsiElement element, VulnerabilitySource source, DependencyReport report) {
35+
this.element = element;
36+
this.source = source;
37+
this.report = report;
38+
}
2839

29-
public class CAIntentionAction implements IntentionAction {
3040
@Override
3141
public @IntentionName @NotNull String getText() {
32-
return "Detailed Vulnerability Report";
42+
return getQuickFixText(this.source, this.report);
3343
}
3444

3545
@Override
3646
public @NotNull @IntentionFamilyName String getFamilyName() {
37-
return "Maven";
47+
return "RHDA";
3848
}
3949

4050
@Override
41-
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
42-
if (file == null) {
43-
return false;
44-
}
45-
return "pom.xml".equals(file.getName())
46-
|| "package.json".equals(file.getName())
47-
|| "go.mod".equals(file.getName())
48-
|| "requirements.txt".equals(file.getName());
51+
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
52+
this.updateVersion(project, editor, file, getRecommendedVersion(this.report));
4953
}
5054

5155
@Override
52-
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
53-
SaUtils saUtils = new SaUtils();
54-
VirtualFile vf = file.getVirtualFile();
55-
56-
if (vf != null) {
57-
JsonObject manifestDetails = saUtils.performSA(vf);
58-
if (manifestDetails != null) {
59-
try {
60-
saUtils.openCustomEditor(FileEditorManager.getInstance(project), manifestDetails);
61-
} catch (IOException ex) {
62-
throw new RuntimeException(ex);
63-
}
64-
}
65-
}
56+
public boolean startInWriteAction() {
57+
return true;
6658
}
6759

6860
@Override
69-
public boolean startInWriteAction() {
70-
return false;
61+
public @Nullable FileModifier getFileModifierForPreview(@NotNull PsiFile target) {
62+
return this.createCAIntentionActionInCopy(PsiTreeUtil.findSameElementInCopy(this.element, target));
63+
}
64+
65+
protected abstract void updateVersion(@NotNull Project project, Editor editor, PsiFile file, String version);
66+
67+
protected abstract @Nullable FileModifier createCAIntentionActionInCopy(PsiElement element);
68+
69+
//TODO
70+
private static @NotNull String getRecommendedVersion(DependencyReport report) {
71+
return "123";
72+
}
73+
74+
//TODO
75+
private static @NotNull String getQuickFixText(VulnerabilitySource source, DependencyReport report) {
76+
return "test";
77+
}
78+
79+
//TODO
80+
static boolean isQuickFixAvailable(DependencyReport report) {
81+
return true;
7182
}
7283
}

0 commit comments

Comments
 (0)