Skip to content

Commit

Permalink
Reduce number of CVE collisions dependency-check#682
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan Strong committed Feb 24, 2023
1 parent 8d2fd2a commit 40f4e91
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public static boolean summarizeVulnerabilities(Configuration config) {

public static Optional<DependencyReason> getBestDependencyReason(@NonNull Dependency dependency, @NonNull Collection<DependencyReason> dependencyReasons) {

Comparator<DependencyReason> comparatorTextRange = Comparator.comparing(r -> r.getBestTextRange(dependency));
Comparator<DependencyReason> comparatorTextRange = Comparator.comparing(r -> r.getBestTextRange(dependency, null));
// Shorter Files-Names indicates to be a root configuration file
Comparator<DependencyReason> comparatorFileLength = Comparator.comparingInt(r -> r.getInputComponent().toString().length());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package org.sonar.dependencycheck.reason;

import java.util.List;
import java.util.Map;

import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
Expand Down Expand Up @@ -76,8 +77,9 @@ public Language getLanguage() {
return language;
}

protected static TextRangeConfidence addDependencyToFirstLine(Dependency dependency, InputFile inputFile) {
LOGGER.debug("We haven't found a TextRange for {} in {}. We link to first line with {} confidence", dependency.getFileName(), inputFile, Confidence.LOW);
protected static TextRangeConfidence addDependencyToFirstLine(Map<Dependency, Vulnerability> k, InputFile inputFile) {
Dependency dependency = k.entrySet().iterator().next().getKey();
LOGGER.debug("We haven't found a TextRange for {} in {}. We link to first line with {} confidence", dependency.getFileName(), inputFile, Confidence.LOW);
return new TextRangeConfidence(inputFile.selectLine(1), Confidence.LOW);
}
/**
Expand All @@ -87,15 +89,15 @@ protected static TextRangeConfidence addDependencyToFirstLine(Dependency depende
* @return TextRange
*/
@NonNull
public abstract TextRangeConfidence getBestTextRange(Dependency dependency);
public abstract TextRangeConfidence getBestTextRange(Dependency dependency, Vulnerability vulnerability);

public void addIssue(SensorContext context, Dependency dependency) {
dependency.sortVulnerabilityBycvssScore(context.config());
List<Vulnerability> vulnerabilities = dependency.getVulnerabilities();
Vulnerability highestVulnerability = vulnerabilities.get(0);
Severity severity = DependencyCheckUtils.cvssToSonarQubeSeverity(highestVulnerability.getCvssScore(context.config()), context.config());

TextRangeConfidence textRange = getBestTextRange(dependency);
TextRangeConfidence textRange = getBestTextRange(dependency, null);
InputComponent inputComponent = getInputComponent();

NewIssue sonarIssue = context.newIssue();
Expand All @@ -116,7 +118,7 @@ public void addIssue(SensorContext context, Dependency dependency) {
public void addIssue(SensorContext context, Dependency dependency, Vulnerability vulnerability) {
Severity severity = DependencyCheckUtils.cvssToSonarQubeSeverity(vulnerability.getCvssScore(context.config()), context.config());

TextRangeConfidence textRange = getBestTextRange(dependency);
TextRangeConfidence textRange = getBestTextRange(dependency, vulnerability);
InputComponent inputComponent = getInputComponent();

NewIssue sonarIssue = context.newIssue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand All @@ -36,15 +37,17 @@
import org.sonar.dependencycheck.parser.element.Confidence;
import org.sonar.dependencycheck.parser.element.Dependency;
import org.sonar.dependencycheck.parser.element.IncludedBy;
import org.sonar.dependencycheck.parser.element.Vulnerability;
import org.sonar.dependencycheck.reason.maven.MavenDependency;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;

public class GradleDependencyReason extends DependencyReason {

private final InputFile buildGradle;
private String content;
private final Map<Dependency, TextRangeConfidence> dependencyMap;
private final Map<Map<Dependency, Vulnerability>, TextRangeConfidence> dependencyMap;

private static final Logger LOGGER = Loggers.get(GradleDependencyReason.class);

Expand All @@ -62,45 +65,45 @@ public GradleDependencyReason(@NonNull InputFile buildGradle) {

@Override
@NonNull
public TextRangeConfidence getBestTextRange(@NonNull Dependency dependency) {
public TextRangeConfidence getBestTextRange(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability) {
if (dependencyMap.containsKey(dependency)) {
return dependencyMap.get(dependency);
} else {
Optional<MavenDependency> mavenDependency = DependencyCheckUtils.getMavenDependency(dependency);
if (mavenDependency.isPresent()) {
fillArtifactMatch(dependency, mavenDependency.get());
fillArtifactMatch(dependency, vulnerability, mavenDependency.get());
} else {
LOGGER.debug("No artifactId found for Dependency {}", dependency.getFileName());
}
Optional<Collection<IncludedBy>> includedBys = dependency.getIncludedBy();
if (includedBys.isPresent()) {
workOnIncludedBy(dependency, includedBys.get());
workOnIncludedBy(dependency, vulnerability, includedBys.get());
}
dependencyMap.computeIfAbsent(dependency, k -> addDependencyToFirstLine(k, buildGradle));
dependencyMap.computeIfAbsent(Collections.singletonMap(dependency, vulnerability), k -> addDependencyToFirstLine(k, buildGradle));
}
return dependencyMap.get(dependency);
return dependencyMap.get(Collections.singletonMap(dependency, vulnerability));
}

private void workOnIncludedBy(@NonNull Dependency dependency, Collection<IncludedBy> includedBys) {
private void workOnIncludedBy(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability, Collection<IncludedBy> includedBys) {
for (IncludedBy includedBy : includedBys) {
String reference = includedBy.getReference();
if (StringUtils.isNotBlank(reference)) {
Optional<SoftwareDependency> softwareDependency = DependencyCheckUtils.convertToSoftwareDependency(reference);
if (softwareDependency.isPresent() && DependencyCheckUtils.isMavenDependency(softwareDependency.get())) {
fillArtifactMatch(dependency, (MavenDependency) softwareDependency.get());
fillArtifactMatch(dependency, vulnerability, (MavenDependency) softwareDependency.get());
}
}
}
}

private void putDependencyMap(@NonNull Dependency dependency, TextRangeConfidence newTextRange) {
private void putDependencyMap(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability, TextRangeConfidence newTextRange) {
if (dependencyMap.containsKey(dependency)) {
TextRangeConfidence oldTextRange = dependencyMap.get(dependency);
if (oldTextRange.getConfidence().compareTo(newTextRange.getConfidence()) > 0) {
dependencyMap.put(dependency, newTextRange);
dependencyMap.put(Collections.singletonMap(dependency, vulnerability), newTextRange);
}
} else {
dependencyMap.put(dependency, newTextRange);
dependencyMap.put(Collections.singletonMap(dependency, vulnerability), newTextRange);
}
}

Expand All @@ -111,7 +114,7 @@ private void putDependencyMap(@NonNull Dependency dependency, TextRangeConfidenc
* @param mavenDependency Identifier for gradle
* @return TextRange if found in gradle, else null
*/
private void fillArtifactMatch(@NonNull Dependency dependency, MavenDependency mavenDependency) {
private void fillArtifactMatch(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability, MavenDependency mavenDependency) {
try (final Scanner scanner = new Scanner(content)) {
int linenumber = 0;
while (scanner.hasNextLine()) {
Expand All @@ -123,18 +126,18 @@ private void fillArtifactMatch(@NonNull Dependency dependency, MavenDependency m
if (depVersion.isPresent() &&
lineFromFile.contains(depVersion.get())) {
LOGGER.debug("Found a artifactId, groupId and version match in {}", buildGradle);
putDependencyMap(dependency, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.HIGHEST));
putDependencyMap(dependency, vulnerability, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.HIGHEST));
return;
} else {
LOGGER.debug("Found a artifactId and groupId match in {} on line {}", buildGradle, linenumber);
putDependencyMap(dependency, vulnerability, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.HIGH));
}
LOGGER.debug("Found a artifactId and groupId match in {} on line {}", buildGradle, linenumber);
putDependencyMap(dependency, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.HIGH));
}
if (lineFromFile.contains(mavenDependency.getArtifactId())) {
} else if (lineFromFile.contains(mavenDependency.getArtifactId())) {
LOGGER.debug("Found a artifactId match in {} for {}", buildGradle, mavenDependency.getArtifactId());
putDependencyMap(dependency, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.MEDIUM));
}
if (lineFromFile.contains(mavenDependency.getGroupId())) {
putDependencyMap(dependency, vulnerability, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.MEDIUM));
} else if (lineFromFile.contains(mavenDependency.getGroupId())) {
LOGGER.debug("Found a groupId match in {} for {}", buildGradle, mavenDependency.getGroupId());
putDependencyMap(dependency, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.MEDIUM));
putDependencyMap(dependency, vulnerability, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.MEDIUM));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
package org.sonar.dependencycheck.reason;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand All @@ -37,16 +39,18 @@
import org.sonar.dependencycheck.parser.element.Confidence;
import org.sonar.dependencycheck.parser.element.Dependency;
import org.sonar.dependencycheck.parser.element.IncludedBy;
import org.sonar.dependencycheck.parser.element.Vulnerability;
import org.sonar.dependencycheck.reason.maven.MavenDependency;
import org.sonar.dependencycheck.reason.maven.MavenDependencyLocation;
import org.sonar.dependencycheck.reason.maven.MavenPomModel;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;

public class MavenDependencyReason extends DependencyReason {

private final InputFile pom;
private final Map<Dependency, TextRangeConfidence> dependencyMap;
private final Map<Map<Dependency, Vulnerability>, TextRangeConfidence> dependencyMap;
private MavenPomModel pomModel;

private static final Logger LOGGER = Loggers.get(MavenDependencyReason.class);
Expand All @@ -66,30 +70,30 @@ public MavenDependencyReason(@NonNull InputFile pom) {

@Override
@NonNull
public TextRangeConfidence getBestTextRange(@NonNull Dependency dependency) {
public TextRangeConfidence getBestTextRange(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability) {
if (!dependencyMap.containsKey(dependency)) {
Optional<MavenDependency> mavenDependency = DependencyCheckUtils.getMavenDependency(dependency);
if (mavenDependency.isPresent()) {
fillArtifactMatch(dependency, mavenDependency.get());
fillArtifactMatch(dependency, vulnerability, mavenDependency.get());
} else {
LOGGER.debug("No Identifier with type maven found for Dependency {}", dependency.getFileName());
}
Optional<Collection<IncludedBy>> includedBys = dependency.getIncludedBy();
if (includedBys.isPresent()) {
workOnIncludedBy(dependency, includedBys.get());
workOnIncludedBy(dependency, vulnerability, includedBys.get());
}
dependencyMap.computeIfAbsent(dependency, k -> addDependencyToFirstLine(k, pom));
dependencyMap.computeIfAbsent(Collections.singletonMap(dependency, vulnerability), k -> addDependencyToFirstLine(k, pom));
}
return dependencyMap.get(dependency);
return dependencyMap.get(Collections.singletonMap(dependency, vulnerability));
}

private void workOnIncludedBy(@NonNull Dependency dependency, Collection<IncludedBy> includedBys) {
private void workOnIncludedBy(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability, Collection<IncludedBy> includedBys) {
for (IncludedBy includedBy : includedBys) {
String reference = includedBy.getReference();
if (StringUtils.isNotBlank(reference)) {
Optional<SoftwareDependency> softwareDependency = DependencyCheckUtils.convertToSoftwareDependency(reference);
if (softwareDependency.isPresent() && DependencyCheckUtils.isMavenDependency(softwareDependency.get())) {
fillArtifactMatch(dependency, (MavenDependency) softwareDependency.get());
fillArtifactMatch(dependency, vulnerability, (MavenDependency) softwareDependency.get());
}
}
}
Expand All @@ -99,49 +103,59 @@ private void workOnIncludedBy(@NonNull Dependency dependency, Collection<Include
* @param dependency
* @param mavenDependency
*/
private void fillArtifactMatch(@NonNull Dependency dependency, MavenDependency mavenDependency) {
// Try to find in <dependency>
private void fillArtifactMatch(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability, MavenDependency mavenDependency) {
BigInteger cveNum = BigInteger.valueOf(0);
if(vulnerability != null) {
String name = vulnerability.getName().replaceAll("[^\\d]", "");
if(!StringUtils.isEmpty(name)) {
cveNum = new BigInteger(name);
}
}

final int cve = cveNum.intValue();

// Try to find in <dependency>
for (MavenDependencyLocation mavenDependencyLocation : pomModel.getDependencies()) {
checkPomDependency(mavenDependency, mavenDependencyLocation)
.ifPresent(textRange -> putDependencyMap(dependency, textRange));
checkPomDependency(mavenDependency, mavenDependencyLocation, cve)
.ifPresent(textRange -> putDependencyMap(dependency, vulnerability, textRange));
}
// Check Parent if present
pomModel.getParent()
.ifPresent(parent -> checkPomDependency(mavenDependency, parent)
.ifPresent(textRange -> putDependencyMap(dependency, textRange)));
.ifPresent(parent -> checkPomDependency(mavenDependency, parent, cve)
.ifPresent(textRange -> putDependencyMap(dependency, vulnerability, textRange)));
}

private void putDependencyMap(@NonNull Dependency dependency, TextRangeConfidence newTextRange) {
private void putDependencyMap(@NonNull Dependency dependency, @Nullable Vulnerability vulnerability, TextRangeConfidence newTextRange) {
if (dependencyMap.containsKey(dependency)) {
TextRangeConfidence oldTextRange = dependencyMap.get(dependency);
if (oldTextRange.getConfidence().compareTo(newTextRange.getConfidence()) > 0) {
dependencyMap.put(dependency, newTextRange);
dependencyMap.put(Collections.singletonMap(dependency, vulnerability), newTextRange);
}
} else {
dependencyMap.put(dependency, newTextRange);
dependencyMap.put(Collections.singletonMap(dependency, vulnerability), newTextRange);
}
}

private Optional<TextRangeConfidence> checkPomDependency(MavenDependency mavenDependency, MavenDependencyLocation mavenDependencyLocation) {
private Optional<TextRangeConfidence> checkPomDependency(MavenDependency mavenDependency, MavenDependencyLocation mavenDependencyLocation, int cveNum) {
if (StringUtils.equals(mavenDependency.getArtifactId(), mavenDependencyLocation.getArtifactId())
&& StringUtils.equals(mavenDependency.getGroupId(), mavenDependencyLocation.getGroupId())) {
Optional<String> depVersion = mavenDependency.getVersion();
Optional<String> depLocVersion = mavenDependencyLocation.getVersion();
if (depVersion.isPresent() && depLocVersion.isPresent() &&
StringUtils.equals(depVersion.get(), depLocVersion.get())) {
LOGGER.debug("Found a artifactId, groupId and version match in {} ({} - {})", pom, mavenDependencyLocation.getStartLineNr(), mavenDependencyLocation.getEndLineNr());
return Optional.of(new TextRangeConfidence(pom.newRange(pom.selectLine(mavenDependencyLocation.getStartLineNr()).start(), pom.selectLine(mavenDependencyLocation.getEndLineNr()).end()), Confidence.HIGHEST));
return Optional.of(new TextRangeConfidence(pom.newRange(mavenDependencyLocation.getStartLineNr(), cveNum, mavenDependencyLocation.getEndLineNr(), cveNum + 1), Confidence.HIGHEST));
}
LOGGER.debug("Found a artifactId and groupId match in {} ({} - {})", pom, mavenDependencyLocation.getStartLineNr(), mavenDependencyLocation.getEndLineNr());
return Optional.of(new TextRangeConfidence(pom.newRange(pom.selectLine(mavenDependencyLocation.getStartLineNr()).start(), pom.selectLine(mavenDependencyLocation.getEndLineNr()).end()), Confidence.HIGH));
return Optional.of(new TextRangeConfidence(pom.newRange(mavenDependencyLocation.getStartLineNr(), cveNum, mavenDependencyLocation.getEndLineNr(), cveNum + 1), Confidence.HIGH));
}
if (StringUtils.equals(mavenDependency.getArtifactId(), mavenDependencyLocation.getArtifactId())) {
LOGGER.debug("Found a artifactId match in {} ({} - {})", pom, mavenDependencyLocation.getStartLineNr(), mavenDependencyLocation.getEndLineNr());
return Optional.of(new TextRangeConfidence(pom.newRange(pom.selectLine(mavenDependencyLocation.getStartLineNr()).start(), pom.selectLine(mavenDependencyLocation.getEndLineNr()).end()), Confidence.MEDIUM));
return Optional.of(new TextRangeConfidence(pom.newRange(mavenDependencyLocation.getStartLineNr(), cveNum, mavenDependencyLocation.getEndLineNr(), cveNum + 1), Confidence.MEDIUM));
}
if (StringUtils.equals(mavenDependency.getGroupId(), mavenDependencyLocation.getGroupId())) {
LOGGER.debug("Found a groupId match in {} ({} - {})", pom, mavenDependencyLocation.getStartLineNr(), mavenDependencyLocation.getEndLineNr());
return Optional.of(new TextRangeConfidence(pom.newRange(pom.selectLine(mavenDependencyLocation.getStartLineNr()).start(), pom.selectLine(mavenDependencyLocation.getEndLineNr()).end()), Confidence.MEDIUM));
return Optional.of(new TextRangeConfidence(pom.newRange(mavenDependencyLocation.getStartLineNr(), cveNum, mavenDependencyLocation.getEndLineNr(), cveNum + 1), Confidence.MEDIUM));
}
return Optional.empty();
}
Expand Down
Loading

0 comments on commit 40f4e91

Please sign in to comment.