Skip to content

Commit

Permalink
considered valuable input from maintainer
Browse files Browse the repository at this point in the history
  • Loading branch information
dtbaum committed Jul 27, 2023
1 parent 3d07ae4 commit 5b46de3
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 3,577 deletions.
69 changes: 44 additions & 25 deletions src/main/java/edu/hm/hafner/analysis/Severity.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
* Severity of an issue. The predefined set of severities consists of an error and 3 warnings with priorities high,
* normal, or low. Additional severities can be created if this set of severities is not sufficient. Note that new
* instances are not cached by this class so that there might exist several severity instances with the same name.
* Severity of an issue. The predefined set of severities consists of an error
* and 3 warnings with priorities high,
* normal, or low. Additional severities can be created if this set of
* severities is not sufficient. Note that new
* instances are not cached by this class so that there might exist several
* severity instances with the same name.
*
* @author Ullrich Hafner
*/
Expand All @@ -30,22 +33,32 @@ public class Severity implements Serializable {

/** An error, e.g. a compile error. */
public static final Severity ERROR = new Severity("ERROR");
/** A warning with priority high. Mapping of warning priorities is determined by the corresponding tool. */
/**
* A warning with priority high. Mapping of warning priorities is determined by
* the corresponding tool.
*/
public static final Severity WARNING_HIGH = new Severity("HIGH");
/** A warning with priority normal. Mapping of warning priorities is determined by the corresponding tool. */
/**
* A warning with priority normal. Mapping of warning priorities is determined
* by the corresponding tool.
*/
public static final Severity WARNING_NORMAL = new Severity("NORMAL");
/** A warning with priority low. Mapping of warning priorities is determined by the corresponding tool. */
/**
* A warning with priority low. Mapping of warning priorities is determined by
* the corresponding tool.
*/
public static final Severity WARNING_LOW = new Severity("LOW");

private static final Set<Severity> ALL_SEVERITIES = Collections.unmodifiableSet(new LinkedHashSet<>(
Arrays.asList(ERROR, WARNING_HIGH, WARNING_NORMAL, WARNING_LOW)));
Arrays.asList(ERROR, WARNING_HIGH, WARNING_NORMAL, WARNING_LOW)));

/**
* Creates a new {@link Severity} with the specified name. If the name is the same as the name of one of the
* Creates a new {@link Severity} with the specified name. If the name is the
* same as the name of one of the
* predefined severities, then this existing severity is returned.
*
* @param name
* the name of the severity
* the name of the severity
*
* @return the severity
*/
Expand All @@ -66,13 +79,15 @@ public static Severity valueOf(final String name) {
}

/**
* Converts a String severity to one of the predefined severities. If the provided String does not match then the default
* Converts a String severity to one of the predefined severities. If the
* provided String does not match then the default
* severity will be returned.
*
* @param severity
* priority as a String
* priority as a String
* @param defaultValue
* default severity, if the specified String is {@code null} or is not a valid {@link Severity} name
* default severity, if the specified String is {@code null}
* or is not a valid {@link Severity} name
*
* @return enumeration value
*/
Expand All @@ -86,32 +101,37 @@ public static Severity valueOf(@CheckForNull final String severity, final Severi
}

/**
* Converts a String severity to one of the predefined severities. If the provided String does not match (even
* Converts a String severity to one of the predefined severities. If the
* provided String does not match (even
* partly) then the default severity will be returned.
*
* @param severity
* the severity string
* the severity string
*
* @return mapped level.
*/
public static Severity guessFromString(@CheckForNull final String severity) {
if (StringUtils.containsAnyIgnoreCase(severity, "error", "severe", "critical", "fatal")) {
return Severity.ERROR;
}
if (StringUtils.containsAnyIgnoreCase(severity, "info", "note")) {
if (StringUtils.containsAnyIgnoreCase(severity, "info", "note", "low")) {
return Severity.WARNING_LOW;
}
if (StringUtils.containsIgnoreCase(severity, "warning")) {
if (StringUtils.containsAnyIgnoreCase(severity, "warning", "medium")) {
return Severity.WARNING_NORMAL;
}
if (StringUtils.containsIgnoreCase(severity, "high")) {
return Severity.WARNING_HIGH;
}
return Severity.WARNING_LOW;
}

/**
* Gets the severities starting from the specified severity to {@link Severity#ERROR}.
* Gets the severities starting from the specified severity to
* {@link Severity#ERROR}.
*
* @param minimumSeverity
* the minimum priority
* the minimum priority
*
* @return the priorities starting from the specified priority
*/
Expand All @@ -120,12 +140,10 @@ public static Collection<Severity> collectSeveritiesFrom(final Severity minimumS
priorities.add(Severity.ERROR);
if (WARNING_HIGH.equals(minimumSeverity)) {
priorities.add(WARNING_HIGH);
}
else if (WARNING_NORMAL.equals(minimumSeverity)) {
} else if (WARNING_NORMAL.equals(minimumSeverity)) {
priorities.add(WARNING_HIGH);
priorities.add(WARNING_NORMAL);
}
else if (WARNING_LOW.equals(minimumSeverity)) {
} else if (WARNING_LOW.equals(minimumSeverity)) {
priorities.add(WARNING_HIGH);
priorities.add(WARNING_NORMAL);
priorities.add(WARNING_LOW);
Expand All @@ -149,7 +167,7 @@ public static Set<Severity> getPredefinedValues() {
* Creates a new {@link Severity} with the specified name.
*
* @param name
* the name of the severity
* the name of the severity
*/
public Severity(final String name) {
Ensure.that(name).isNotBlank();
Expand All @@ -175,9 +193,10 @@ public String toString() {
* Checks if this instance has a name that is equal to the specified name.
*
* @param severityName
* the name to check
* the name to check
*
* @return {@code true} if this instance has the same name, {@code false} otherwise
* @return {@code true} if this instance has the same name, {@code false}
* otherwise
*/
public boolean equalsIgnoreCase(final String severityName) {
return IssueParser.equalsIgnoreCase(getName(), severityName);
Expand Down
58 changes: 26 additions & 32 deletions src/main/java/edu/hm/hafner/analysis/parser/GrypeParser.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package edu.hm.hafner.analysis.parser;

import static j2html.TagCreator.a;
import static j2html.TagCreator.p;

import org.json.JSONArray;
import org.json.JSONObject;

import edu.hm.hafner.analysis.Issue;
import edu.hm.hafner.analysis.IssueBuilder;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.Severity;

import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONObject;

/**
* JSON report parser for grype (https://plugins.jenkins.io/grypescanner/ /
* https://github.com/anchore/grype).
Expand All @@ -32,36 +33,29 @@ protected void parseJsonObject(final Report report, final JSONObject jsonReport,
final JSONArray matches = jsonReport.getJSONArray(MATCHES_TAG);
for (int i = 0; i < matches.length(); i++) {
final JSONObject match = matches.getJSONObject(i);
if (!match.has(VULNERABILIY_TAG)) {
continue;
if (match.has(VULNERABILIY_TAG)) {
Issue issue = getIssue(issueBuilder, match);
report.add(issue);
}
JSONObject vuln = match.getJSONObject(VULNERABILIY_TAG);
String fileName = match.getJSONObject(ARTIFACT_TAG).getJSONArray(LOCATIONS_TAG).getJSONObject(0)
.getString(PATH_TAG);
Issue issue = issueBuilder.setFileName(fileName)
.setCategory(vuln.getString(SEVERITY_TAG))
.setSeverity(mapSeverity(vuln.getString(SEVERITY_TAG)))
.setType(vuln.getString(ID_TAG))
.setMessage(vuln.getString(DESCRIPTION_TAG))
.setOriginName("Grype")
.setPathName(fileName)
.setDescription(vuln.getString(DATA_SOURCE_TAG)).build();
report.add(issue);
}
}

private Severity mapSeverity(final String severity) {
switch (severity.toUpperCase(Locale.ENGLISH)) {
case "LOW":
return Severity.WARNING_LOW;
case "MEDIUM":
return Severity.WARNING_NORMAL;
case "CRITICAL":
return Severity.ERROR;
case "HIGH":
return Severity.WARNING_HIGH;
default:
return new Severity(severity);
}
private Issue getIssue(final IssueBuilder issueBuilder, final JSONObject match) {
JSONObject vuln = match.getJSONObject(VULNERABILIY_TAG);
String fileName = match.getJSONObject(ARTIFACT_TAG).getJSONArray(LOCATIONS_TAG).getJSONObject(0)
.getString(PATH_TAG);

Issue issue = issueBuilder.setFileName(fileName)
.setCategory(vuln.getString(SEVERITY_TAG))
.setSeverity(Severity.guessFromString(vuln.getString(SEVERITY_TAG)))
.setType(vuln.getString(ID_TAG))
.setMessage(vuln.getString(DESCRIPTION_TAG))
.setOriginName("Grype")
.setPathName(fileName)
.setDescription(p().with(a()
.withHref(vuln.getString(DATA_SOURCE_TAG))
.withText(vuln.getString(DATA_SOURCE_TAG))).render())
.build();
return issue;
}
}
15 changes: 11 additions & 4 deletions src/test/java/edu/hm/hafner/analysis/parser/GrypeParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.Severity;
import edu.hm.hafner.analysis.assertions.SoftAssertions;
import static j2html.TagCreator.a;
import static j2html.TagCreator.p;

class GrypeParserTest extends AbstractParserTest {
protected GrypeParserTest() {
Expand All @@ -13,24 +15,29 @@ protected GrypeParserTest() {

@Override
protected void assertThatIssuesArePresent(final Report report, final SoftAssertions softly) {
softly.assertThat(report).hasSize(29).hasDuplicatesSize(0);
softly.assertThat(report).hasSize(3).hasDuplicatesSize(0);
softly.assertThat(report.get(0))
.hasFileName("tomcat-jdbc/8.0.28/tomcat-jdbc-8.0.28.jar")
.hasSeverity(Severity.WARNING_NORMAL)
.hasCategory("Medium")
.hasType("CVE-2015-5345")
.hasMessage(
"The Mapper component in Apache Tomcat 6.x before 6.0.45, 7.x before 7.0.68, 8.x before 8.0.30, and 9.x before 9.0.0.M2 processes redirects before considering security constraints and Filters, which allows remote attackers to determine the existence of a directory via a URL that lacks a trailing / (slash) character.")
.hasDescription("https://nvd.nist.gov/vuln/detail/CVE-2015-5345");
.hasDescription(p().with(a()
.withHref("https://nvd.nist.gov/vuln/detail/CVE-2015-5345")
.withText("https://nvd.nist.gov/vuln/detail/CVE-2015-5345")).render());

softly.assertThat(report.get(17))
softly.assertThat(report.get(2))
.hasFileName("tomcat-jdbc/8.0.28/tomcat-jdbc-8.0.28.jar")
.hasSeverity(Severity.WARNING_HIGH)
.hasCategory("High")
.hasType("CVE-2016-8745")
.hasMessage(
"A bug in the error handling of the send file code for the NIO HTTP connector in Apache Tomcat 9.0.0.M1 to 9.0.0.M13, 8.5.0 to 8.5.8, 8.0.0.RC1 to 8.0.39, 7.0.0 to 7.0.73 and 6.0.16 to 6.0.48 resulted in the current Processor object being added to the Processor cache multiple times. This in turn meant that the same Processor could be used for concurrent requests. Sharing a Processor can result in information leakage between requests including, not not limited to, session ID and the response body. The bug was first noticed in 8.5.x onwards where it appears the refactoring of the Connector code for 8.5.x onwards made it more likely that the bug was observed. Initially it was thought that the 8.5.x refactoring introduced the bug but further investigation has shown that the bug is present in all currently supported Tomcat versions.")
.hasDescription("https://nvd.nist.gov/vuln/detail/CVE-2016-8745");

.hasDescription(p().with(a()
.withHref("https://nvd.nist.gov/vuln/detail/CVE-2016-8745")
.withText("https://nvd.nist.gov/vuln/detail/CVE-2016-8745")).render());
}

@Override
Expand Down
Loading

0 comments on commit 5b46de3

Please sign in to comment.