Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce number of CVE collisions dependency-check/dependency-check-son… #763

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -22,6 +22,7 @@

import java.util.List;

import org.apache.commons.lang3.tuple.Pair;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.Severity;
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(Pair<Dependency, Vulnerability> pair, InputFile inputFile) {
Dependency dependency = pair.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 @@ -28,6 +28,7 @@
import java.util.Scanner;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.utils.log.Logger;
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<Pair<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(Pair.of(dependency, vulnerability), k -> addDependencyToFirstLine(k, buildGradle));
}
return dependencyMap.get(dependency);
return dependencyMap.get(Pair.of(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(Pair.of(dependency, vulnerability), newTextRange);
}
} else {
dependencyMap.put(dependency, newTextRange);
dependencyMap.put(Pair.of(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,17 @@ 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;
}
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())) {
putDependencyMap(dependency, vulnerability, new TextRangeConfidence(buildGradle.selectLine(linenumber), Confidence.HIGH));
} 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,12 +21,14 @@
package org.sonar.dependencycheck.reason;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.utils.log.Logger;
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<Pair<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(Pair.of(dependency, vulnerability), k -> addDependencyToFirstLine(k, pom));
}
return dependencyMap.get(dependency);
return dependencyMap.get(Pair.of(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(Pair.of(dependency, vulnerability), newTextRange);
}
} else {
dependencyMap.put(dependency, newTextRange);
dependencyMap.put(Pair.of(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