diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/JsonInspectionsReportConverter.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/JsonInspectionsReportConverter.java index c0bbc222470e..34bffcf37bd2 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/JsonInspectionsReportConverter.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/JsonInspectionsReportConverter.java @@ -8,6 +8,7 @@ import com.intellij.codeInspection.DefaultInspectionToolResultExporter; import com.intellij.codeInspection.InspectionsReportConverter; import com.intellij.codeInspection.InspectionsResultUtil; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.ContainerUtil; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; @@ -21,6 +22,8 @@ import java.io.IOException; import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Predicate; @@ -61,6 +64,7 @@ public class JsonInspectionsReportConverter implements InspectionsReportConverte @NonNls private static final String HIGHLIGHTED_ELEMENT = "highlighted_element"; @NonNls public static final String DUPLICATED_CODE = "DuplicatedCode"; @NonNls public static final String DUPLICATED_CODE_AGGREGATE = DUPLICATED_CODE + InspectionsResultUtil.AGGREGATE; + @NonNls public static final String PHP_VULNERABLE_PATHS_AGGREGATE = "PhpVulnerablePathsInspection" + InspectionsResultUtil.AGGREGATE; @Override public String getFormatName() { @@ -100,6 +104,9 @@ public class JsonInspectionsReportConverter implements InspectionsReportConverte else if (DUPLICATED_CODE_AGGREGATE.equals(fileNameWithoutExt)) { convertDuplicatedCode(jsonWriter, doc); } + else if (PHP_VULNERABLE_PATHS_AGGREGATE.equals(fileNameWithoutExt)) { + convertPhpVulnerablePaths(jsonWriter, doc); + } else { convertProblems(jsonWriter, doc); } @@ -131,19 +138,192 @@ public class JsonInspectionsReportConverter implements InspectionsReportConverte private static void convertDuplicateFragment(@NotNull JsonWriter jsonWriter, Element fragment) throws IOException { jsonWriter.beginObject(); - jsonWriter.name(FILE).value(fragment.getAttributeValue(FILE)); - String line = fragment.getAttributeValue(LINE); - String start = fragment.getAttributeValue("start"); - String end = fragment.getAttributeValue("end"); + writeFileSegmentAttributes(jsonWriter, fragment); + jsonWriter.endObject(); + } + + private static void writeFileSegmentAttributes(@NotNull JsonWriter jsonWriter, Element fileSegment) throws IOException { + writeFileAttribute(jsonWriter, fileSegment); + writeSegmentAttributes(jsonWriter, fileSegment); + } + + private static void writeFileAttribute(@NotNull JsonWriter jsonWriter, Element fileSegment) throws IOException { + jsonWriter.name(FILE).value(fileSegment.getAttributeValue(FILE)); + } + + private static void writeSegmentAttributes(@NotNull JsonWriter jsonWriter, Element segment) throws IOException { + String line = segment.getAttributeValue(LINE); + String start = segment.getAttributeValue("start"); + String end = segment.getAttributeValue("end"); assert line != null; assert start != null; assert end != null; jsonWriter.name(LINE).value(Integer.parseInt(line)); jsonWriter.name("start").value(Integer.parseInt(start)); jsonWriter.name("end").value(Integer.parseInt(end)); + } + + public static void convertPhpVulnerablePaths(@NotNull JsonWriter jsonWriter, @NotNull Document problems) throws IOException { + jsonWriter.beginObject(); + jsonWriter.name(PROBLEMS); + jsonWriter.beginArray(); + for (Element problem : problems.getRootElement().getChildren(PROBLEM)) { + convertPhpVulnerablePath(jsonWriter, problem); + } + jsonWriter.endArray(); jsonWriter.endObject(); } + public static void convertPhpVulnerablePath(@NotNull JsonWriter jsonWriter, Element problem) throws IOException { + jsonWriter.beginObject(); + + jsonWriter.name(DESCRIPTION).value("Vulnerable code flow"); + jsonWriter.name("fragments"); + jsonWriter.beginArray(); + Element fragmentsElement = problem.getChild("fragments"); + assert fragmentsElement != null; + for (Element fragment : fragmentsElement.getChildren("fragment")) { + convertPhpVulnerableFragment(jsonWriter, fragment); + } + jsonWriter.endArray(); + + convertPhpSink(jsonWriter, problem); + + jsonWriter.name("sources"); + jsonWriter.beginArray(); + Element sourcesElement = problem.getChild("sources"); + assert sourcesElement != null; + for (Element source : sourcesElement.getChildren("source")) { + convertPhpTaintSource(jsonWriter, source); + } + jsonWriter.endArray(); + + jsonWriter.name(LANGUAGE).value(problem.getChildText(LANGUAGE)); + Element problemClassElement = problem.getChild(DefaultInspectionToolResultExporter.INSPECTION_RESULTS_PROBLEM_CLASS_ELEMENT); + if (problemClassElement != null) { + convertProblemClass(jsonWriter, problemClassElement); + } + + jsonWriter.endObject(); + } + + private static void convertPhpSink(@NotNull JsonWriter jsonWriter, @NotNull Element problem) throws IOException { + jsonWriter.name("sink"); + Element sink = problem.getChild("sink"); + assert sink != null; + jsonWriter.beginObject(); + jsonWriter.name("text").value(sink.getAttributeValue("text")); + String sinkFqn = sink.getAttributeValue("fqn"); + if (sinkFqn != null) { + jsonWriter.name("fqn").value(sinkFqn); + } + writeOrderAttribute(jsonWriter, sink); + jsonWriter.name("vulnerabilities"); + jsonWriter.beginArray(); + Collection vulnerabilityValues = getVulnerabilityValues(sink, "vulnerabilities"); + for (String vulnerability : vulnerabilityValues) { + jsonWriter.value(vulnerability); + } + jsonWriter.endArray(); + jsonWriter.name("parameters"); + jsonWriter.beginArray(); + String parameterName = getParameterName(sink); + if (parameterName != null) { + jsonWriter.value(parameterName); + } + jsonWriter.endArray(); + jsonWriter.endObject(); + } + + private static void convertPhpTaintSource(@NotNull JsonWriter jsonWriter, @NotNull Element source) throws IOException { + jsonWriter.beginObject(); + jsonWriter.name("text").value(source.getAttributeValue("text")); + writeFileAttribute(jsonWriter, source); + writeOrderAttribute(jsonWriter, source); + writeSanitizedVulnerabilities(jsonWriter, source); + jsonWriter.endObject(); + } + + private static void convertPhpVulnerableFragment(@NotNull JsonWriter jsonWriter, Element fragment) throws IOException { + jsonWriter.beginObject(); + + writeFileSegmentAttributes(jsonWriter, fragment); + + jsonWriter.name("markers"); + jsonWriter.beginArray(); + for (Element marker : fragment.getChildren("marker")) { + convertPhpTaintMarker(jsonWriter, marker); + } + jsonWriter.endArray(); + + jsonWriter.endObject(); + } + + private static void convertPhpTaintMarker(@NotNull JsonWriter jsonWriter, @NotNull Element marker) throws IOException { + jsonWriter.beginObject(); + + writeSegmentAttributes(jsonWriter, marker); + writeOrderAttribute(jsonWriter, marker); + + jsonWriter.name("successors"); + jsonWriter.beginArray(); + Element successorsElement = marker.getChild("successors"); + if (successorsElement != null) { + Collection markerOrders = ContainerUtil.map(successorsElement.getChildren("marker"), Element::getText); + for (String markerOrder : markerOrders) { + jsonWriter.value(markerOrder); + } + } + jsonWriter.endArray(); + jsonWriter.name("predecessors"); + jsonWriter.beginArray(); + Element predecessorsElement = marker.getChild("predecessors"); + if (predecessorsElement != null) { + Collection markerOrders = ContainerUtil.map(predecessorsElement.getChildren("marker"), Element::getText); + for (String markerOrder : markerOrders) { + jsonWriter.value(markerOrder); + } + } + jsonWriter.endArray(); + + writeSanitizedVulnerabilities(jsonWriter, marker); + + jsonWriter.endObject(); + } + + private static void writeOrderAttribute(@NotNull JsonWriter jsonWriter, @NotNull Element marker) throws IOException { + jsonWriter.name("order").value(marker.getAttributeValue("order")); + } + + private static void writeSanitizedVulnerabilities(@NotNull JsonWriter jsonWriter, @NotNull Element element) throws IOException { + jsonWriter.name("sanitized_vulnerabilities"); + jsonWriter.beginArray(); + Collection vulnerabilityValues = getVulnerabilityValues(element, "sanitized_vulnerabilities"); + for (String vulnerability : vulnerabilityValues) { + jsonWriter.value(vulnerability); + } + jsonWriter.endArray(); + } + + @Nullable + private static String getParameterName(@NotNull Element element) { + Element parameters = element.getChild("parameters"); + Collection parameterElements = parameters != null ? parameters.getChildren("parameter") : null; + Element parameter = ContainerUtil.getFirstItem(parameterElements); + return parameter != null ? parameter.getAttributeValue("name") : null; + } + + @NotNull + private static Collection getVulnerabilityValues(@NotNull Element element, + @NotNull String vulnerabilitiesTagName) { + Element vulnerabilities = element.getChild(vulnerabilitiesTagName); + if (vulnerabilities == null) { + return Collections.emptyList(); + } + return ContainerUtil.map(vulnerabilities.getChildren("vulnerability"), + vulnerability -> vulnerability.getAttributeValue("name")); + } + private static void convertProblems(@NotNull JsonWriter jsonWriter, @NotNull Document problems) throws IOException { jsonWriter.beginObject(); jsonWriter.name(PROBLEMS);