Added support for scanning transitive dependencies for .NET libraries (except those with unlimited set of supported TMFs).

This commit is contained in:
Šesták Vít
2018-03-07 13:59:43 +01:00
parent d87535df84
commit dcc109a729
8 changed files with 229 additions and 89 deletions
+33 -31
View File
@@ -1,9 +1,9 @@
@(idPrefix: String, list: Seq[GroupedDependency], selectorOption: Option[String], lazyLoad: Boolean = true, expand: GroupedDependency => Boolean = _ => false, addButtons: Boolean = true, showAffectedProjects: Boolean = true, expandVulnerabilities: Boolean = false, vulnerabilitySearch: Boolean = true)
@(idPrefix: String, list: Seq[GroupedDependency], selectorOption: Option[String], lazyLoad: Boolean = true, expand: GroupedDependency => Boolean = _ => false, addButtons: Boolean = true, showAffectedProjects: Boolean = true, expandVulnerabilities: Boolean = false, vulnerabilitySearch: Boolean = true, profilesOption: Option[(Seq[String], GroupedDependency => Seq[String])] = None)
@cpeHtmlId(cpe: String) = @{
cpe.getBytes("utf-8").mkString("-")
}
<table class="table table-condensed dependencies-table">
<table class="table table-condensed dependencies-table" id="@idPrefix-table">
<thead>
<tr>
<th>Severity</th>
@@ -12,37 +12,39 @@
<th class="actions"></th>
</tr>
</thead>
@for(dep <- list; depPrefix = s"$idPrefix-${dep.hashes.serialized}"){
<tr>
<td class="severity">
@dep.maxCvssScore.fold{
<span class="label label-success">OK</span>
}{ s =>
<span class="score-vulnerability">@s</span>
@if(showAffectedProjects){
<span class="computation-details">
<span class="score-projects">affects @dep.projects.size @if(dep.projects.size>1){projects}else{project}</span>
</span>
@for(dep <- list; depPrefix = s"$idPrefix-${dep.hashes.serialized}"; classes={profilesOption.fold(Seq[String]()){case (_, parser) => parser(dep).map(profileClass)}}){
<tbody class="@((classes++Seq("library")).mkString(" "))">
<tr>
<td class="severity">
@dep.maxCvssScore.fold{
<span class="label label-success">OK</span>
}{ s =>
<span class="score-vulnerability">@s</span>
@if(showAffectedProjects){
<span class="computation-details">
<span class="score-projects">affects @dep.projects.size @if(dep.projects.size>1){projects}else{project}</span>
</span>
}
}
</td>
<td class="identifiers">
@libraryIdentificationList(dep, Some(cpe => s"$idPrefix-${dep.hashes.serialized}-suppression-cpe-${cpeHtmlId(cpe)}"), addLink = false, addButtons = addButtons)
</td>
<td class="vulns">@for(s <- dep.maxCvssScore) {@dep.vulnerabilities.size}</td>
<td class="actions">
<button data-toggle="collapse" data-target="#@depPrefix-details" class="btn btn-info @if(!expand(dep)){collapsed} expandable expandable-right"></button>
</td>
</tr>
<tr data-wrapper="<td colspan='4'></td>" id="@depPrefix-details" class="details collapse@if(expand(dep)){ in}" @if(lazyLoad){data-lazyload-url="@routes.Statistics.dependencyDetails(
depPrefix = depPrefix,
depId = dep.hashes,
selectorOption = selectorOption
)"}>
@if(!lazyLoad){
<td colspan="4">@dependencyDetailsInner(depPrefix = depPrefix, dep = dep, selectorOption = selectorOption, showAffectedProjects = showAffectedProjects, expandVulnerabilities = expandVulnerabilities, vulnerabilitySearch = vulnerabilitySearch)</td>
}
</td>
<td class="identifiers">
@libraryIdentificationList(dep, Some(cpe => s"$idPrefix-${dep.hashes.serialized}-suppression-cpe-${cpeHtmlId(cpe)}"), addLink = false, addButtons = addButtons)
</td>
<td class="vulns">@for(s <- dep.maxCvssScore) {@dep.vulnerabilities.size}</td>
<td class="actions">
<button data-toggle="collapse" data-target="#@depPrefix-details" class="btn btn-info @if(!expand(dep)){collapsed} expandable expandable-right"></button>
</td>
</tr>
<tr data-wrapper="<td colspan='4'></td>" id="@depPrefix-details" class="details collapse@if(expand(dep)){ in}" @if(lazyLoad){data-lazyload-url="@routes.Statistics.dependencyDetails(
depPrefix = depPrefix,
depId = dep.hashes,
selectorOption = selectorOption
)"}>
@if(!lazyLoad){
<td colspan="4">@dependencyDetailsInner(depPrefix = depPrefix, dep = dep, selectorOption = selectorOption, showAffectedProjects = showAffectedProjects, expandVulnerabilities = expandVulnerabilities, vulnerabilitySearch = vulnerabilitySearch)</td>
}
</tr>
</tr>
</tbody>
}
</table>
<script type="text/javascript">
@@ -45,6 +45,22 @@
enableSubmit();
}
});
},
filterByProfile: function (el){
$("> *", el.parentNode).removeClass("active");
function filter(root){
var profileClass = $(el).data("profileclass");
var allLibraries = $(root.getElementsByClassName("library"));
if(profileClass){
allLibraries.hide();
$(root.getElementsByClassName(profileClass)).show();
}else{
allLibraries.show();
}
}
filter(document.getElementById("main-table"));
filter(document.getElementById("transitive-table"));
$(el).addClass("active");
}
};
@@ -1,28 +1,43 @@
@import services.SingleLibraryScanResult
@(isDbOld: Boolean, singleLibraryScanResult: SingleLibraryScanResult)(implicit header: DefaultRequest, mainTemplateData: MainTemplateData)
@import singleLibraryScanResult.{transitiveDependencies, includesTransitive, mainDependencies, limitations}
@import singleLibraryScanResult.{transitiveDependencies, includesTransitive, mainDependencies, limitations, profilesOption}
@requiresAttention = @{limitations.exists(_.requiresAttention)}
@for((profiles, _) <- profilesOption){
<h2>Profiles</h2>
@if(profiles.size > 1) {
<p>This scan provider results for multiple profiles. By default, all results all shown, but you can filter it.</p>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" onclick="LibraryAdvisorUI.filterByProfile(this)">All profiles</button>
@for(profile <- profiles) {
<button type="button" class="btn btn-default" onclick="LibraryAdvisorUI.filterByProfile(this)" data-profileclass="@profileClass(profile)">@profile</button>
}
</div>
}else{
All results belong to profile <strong>@profiles.head</strong>.
}
}
<h2>Overall result</h2>
@vulnerableTransitive = @{transitiveDependencies.exists(_.isVulnerable)}
@vulnerableMain = @{mainDependencies.exists(_.isVulnerable)}
@if(isDbOld){
<div class="alert alert-warning">The vulnerability database seems to be outdated. Result might be thus inaccurate. Contact the administrator, please.</div>
}
@for(limitations <- limitations){
<div class="alert alert-warning"><strong>This scan has some limitations: </strong>@limitations</div>
@for(limitation <- limitations){
<div class="alert alert-@limitation.severity"><strong>Limitation: </strong>@limitation.message</div>
}
@(vulnerableMain, vulnerableTransitive) match {
case (false, false) => {
<div class="alert alert-success">No vulnerability has been found in the library@if(includesTransitive){ or in its transitive dependencies}.</div>
<div class="alert alert-@if(requiresAttention){warning}else{success}">
No vulnerability has been found in the library@if(includesTransitive){ or in its transitive dependencies}.
@if(requiresAttention){However, take care of the limitations above, please.}
</div>
}
case (false, true) => {<div class="alert alert-warning">While there is no vulnerability found in the library itself, but scan has identified some issues in its transitive dependencies. Maybe you should evict some dependency with a fixed version. @vulnerabilityAdvice()</div>}
case (true, false) => {<div class="alert alert-danger">There is a vulnerability found in the main dependency. Transitive dependencies are OK. Please consider using a patched version or consider impact of the vulnerabilities. @vulnerabilityAdvice()</div>}
case (true, true) => {<div class="alert alert-danger">There is a vulnerability found in both the main dependency and transitive dependencies. Please consider using a patched version or consider impact of the vulnerabilities. @vulnerabilityAdvice()</div>}
}
@if(!includesTransitive){
<div class="alert alert-warning">This type of scan does not scan transitive dependencies.</div>
}
<h2>The library itself</h2>
@dependencyList("id", mainDependencies, None, expand = _.isVulnerable, addButtons = false, lazyLoad = false, showAffectedProjects = false, expandVulnerabilities = true, vulnerabilitySearch = false)
@dependencyList("main", mainDependencies, None, expand = _.isVulnerable, addButtons = false, lazyLoad = false, showAffectedProjects = false, expandVulnerabilities = true, vulnerabilitySearch = false, profilesOption = profilesOption)
@if(includesTransitive) {
<h2>Transitive dependencies</h2>
@if(transitiveDependencies.nonEmpty) {
@@ -31,7 +46,7 @@
}else{
<div class="alert alert-info">There is no known vulnerability in transitive dependencies. They are listed just for your information.</div>
}
@dependencyList("id", transitiveDependencies.sorted(severityOrdering), None, expand = _.isVulnerable, addButtons = false, lazyLoad = false, showAffectedProjects = false, expandVulnerabilities = true, vulnerabilitySearch = true)
@dependencyList("transitive", transitiveDependencies.sorted(severityOrdering), None, expand = _.isVulnerable, addButtons = false, lazyLoad = false, showAffectedProjects = false, expandVulnerabilities = true, vulnerabilitySearch = true, profilesOption = profilesOption)
}else{
This library has no transitive dependencies.
}