mirror of
https://github.com/ysoftdevs/odc-analyzer.git
synced 2026-05-30 19:30:37 +02:00
Added new ODC scans for Java libraries. Those can scan even transitive dependencies and can be run before adding a new library to a project.
This commit is contained in:
@@ -1,13 +1,25 @@
|
||||
@(depPrefix: String, dep: GroupedDependency, selectorOption: Option[String])
|
||||
@(depPrefix: String, dep: GroupedDependency, selectorOption: Option[String], showAffectedProjects: Boolean = false, expandVulnerabilities: Boolean = false, vulnerabilitySearch: Boolean = true)
|
||||
|
||||
@dep.cpeIdentifiers.toSeq match {
|
||||
case Seq() => {}
|
||||
case cpeIds => {
|
||||
<p>
|
||||
<a href="@routes.Statistics.searchVulnerableSoftware(
|
||||
cpeIds.map(_.name.split(':').take(4).mkString(":")).toSeq, None
|
||||
)" title="Search for known vulnerabilities" class="btn btn-default">Look for vulnerabilities in other versions</a>
|
||||
</p>
|
||||
@if(vulnerabilitySearch){
|
||||
@vulnerableSoftwareSearches(dep) match {
|
||||
case Seq() => {}
|
||||
case Seq((link, description)) => {
|
||||
<p>
|
||||
<a href="@link" title="Search for known vulnerabilities" class="btn btn-default">Look for vulnerabilities in other versions</a>
|
||||
</p>
|
||||
}
|
||||
case options => {
|
||||
<p>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">Look for vulnerabilities in other versions <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
@for((link, description) <- options){
|
||||
<li><a href="@link">@description</a></li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</p>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,30 +74,32 @@
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
<h4 class="expandable" data-toggle="collapse" data-target="#@depPrefix-projects-details">Affected projects (@dep.projects.size)</h4>
|
||||
<div id="@depPrefix-projects-details" class="collapse in">
|
||||
<ul>
|
||||
@for(p <- dep.projects.toIndexedSeq.sorted){
|
||||
<li>@friendlyProjectName(p)</li>
|
||||
@if(showAffectedProjects){
|
||||
<h4 class="expandable" data-toggle="collapse" data-target="#@depPrefix-projects-details">Affected projects (@dep.projects.size)</h4>
|
||||
<div id="@depPrefix-projects-details" class="collapse in">
|
||||
<ul>
|
||||
@for(p <- dep.projects.toIndexedSeq.sorted){
|
||||
<li>@friendlyProjectName(p)</li>
|
||||
}
|
||||
</ul>
|
||||
@if(selectorOption.isDefined){
|
||||
<h5 class="expandable collapsed sublist" data-toggle="collapse" data-target="#@depPrefix-projects-all-details">All affected projects (including those that aren't included by the filter)</h5>
|
||||
<div id="@depPrefix-projects-all-details" class="collapse" data-lazyload-url="@routes.Statistics.affectedProjects(
|
||||
depId = dep.hashes
|
||||
)"></div>
|
||||
}
|
||||
</ul>
|
||||
@if(selectorOption.isDefined){
|
||||
<h5 class="expandable collapsed sublist" data-toggle="collapse" data-target="#@depPrefix-projects-all-details">All affected projects (including those that aren't included by the filter)</h5>
|
||||
<div id="@depPrefix-projects-all-details" class="collapse" data-lazyload-url="@routes.Statistics.affectedProjects(
|
||||
depId = dep.hashes
|
||||
)"></div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<h4 class="expandable" data-toggle="collapse" data-target="#@depPrefix-vulnerabilities-details">Vulnerabilities (@dep.vulnerabilities.size)</h4>
|
||||
<ul id="@depPrefix-vulnerabilities-details" class="collapse in vulnerabilities-details">
|
||||
@for(vuln <- dep.vulnerabilities.toSeq.sortBy(_.cvssScore.map(-_)); vulnPrefix = s"$depPrefix-vulnerabilities-details-${vuln.name}"){
|
||||
<li>
|
||||
<h5 data-toggle="collapse" class="expandable collapsed" data-target="#@vulnPrefix-details">
|
||||
<h5 data-toggle="collapse" class="expandable@if(!expandVulnerabilities){ collapsed}" data-target="#@vulnPrefix-details">
|
||||
@vuln.name
|
||||
<a href="@routes.Statistics.vulnerability(vuln.name, selectorOption)" target="_blank" onclick="event.stopPropagation();"><span class="glyphicon glyphicon-new-window"></span></a>
|
||||
@if(vuln.likelyMatchesOnlyWithoutVersion(dep.identifiers)){<span class="warning-expandable" title="Heuristics suspect false positive. Double check <b>what version</b> does this vulnerability apply to, please. It seems that the vulnerability database does not provide enough information to check it automatically." onmouseover="$(this).tooltip({placement: 'right', html:true}).tooltip('show');"></span>}
|
||||
</h5>
|
||||
<div id="@vulnPrefix-details" class="collapse vulnerability-expandable">
|
||||
<div id="@vulnPrefix-details" class="collapse vulnerability-expandable@if(expandVulnerabilities){ in}">
|
||||
@vulnerability("h6", depPrefix+"-"+vuln.name, vuln)
|
||||
<p><a class="btn btn-primary more" target="_blank" href="@routes.Statistics.vulnerability(vuln.name, selectorOption)">Full details about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@(idPrefix: String, list: Seq[GroupedDependency], selectorOption: Option[String], expandByDefault: Boolean = true, addButtons: 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)
|
||||
@cpeHtmlId(cpe: String) = @{
|
||||
cpe.getBytes("utf-8").mkString("-")
|
||||
}
|
||||
@@ -15,11 +15,15 @@
|
||||
@for(dep <- list; depPrefix = s"$idPrefix-${dep.hashes.serialized}"){
|
||||
<tr>
|
||||
<td class="severity">
|
||||
@for(s <- dep.maxCvssScore) {
|
||||
@dep.maxCvssScore.fold{
|
||||
<span class="label label-success">OK</span>
|
||||
}{ s =>
|
||||
<span class="score-vulnerability">@s</span>
|
||||
<span class="computation-details">
|
||||
<span class="score-projects">affects @dep.projects.size @if(dep.projects.size>1){projects}else{project}</span>
|
||||
</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">
|
||||
@@ -27,14 +31,18 @@
|
||||
</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 collapsed expandable expandable-right"></button>
|
||||
<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" data-lazyload-url="@routes.Statistics.dependencyDetails(
|
||||
<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
|
||||
)"></tr>
|
||||
)"}>
|
||||
@if(!lazyLoad){
|
||||
<td colspan="4">@dependencyDetailsInner(depPrefix = depPrefix, dep = dep, selectorOption = selectorOption, showAffectedProjects = showAffectedProjects, expandVulnerabilities = expandVulnerabilities, vulnerabilitySearch = vulnerabilitySearch)</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
@()(implicit header: DefaultRequest, mainTemplateData: MainTemplateData)
|
||||
|
||||
@main(
|
||||
title = s"OWASP Dependency Check not configured"
|
||||
){
|
||||
<div class="alert alert-danger">OWASP Dependency Check is not configured, so you cannot run it right now. Contact your administrator, please.</div>
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
@(dependency: String)
|
||||
<div class="alert alert-danger">Dependency @dependency was not found.</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
@(message: String)(implicit header: DefaultRequest, mainTemplateData: MainTemplateData)
|
||||
|
||||
<div class="alert alert-danger">I did not scan the library, because I was unable to understand what library you mean. @message</div>
|
||||
@@ -0,0 +1,82 @@
|
||||
@(identifier: Option[String], inputHints: Seq[Html])(implicit header: DefaultRequest, mainTemplateData: MainTemplateData)
|
||||
|
||||
@main(
|
||||
title = s"Library check"
|
||||
){
|
||||
|
||||
<script type="text/javascript">
|
||||
var LibraryAdvisorUI = {
|
||||
scan: function(){
|
||||
var submitButton = $("#submit-button");
|
||||
var resultsArea = $("#scan-results");
|
||||
var identifierArea = $("#library-identifier");
|
||||
var identifier = identifierArea.val();
|
||||
function disableSubmit(){
|
||||
submitButton.attr({disabled: true});
|
||||
identifierArea.attr({disabled: true});
|
||||
}
|
||||
function enableSubmit(){
|
||||
submitButton.attr({disabled: false});
|
||||
identifierArea.attr({disabled: false});
|
||||
}
|
||||
disableSubmit();
|
||||
resultsArea.html($('<div class="progress">')
|
||||
.append(
|
||||
$('<div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 100%;">Scanning, please wait a minute…</div>')
|
||||
)
|
||||
);
|
||||
$.ajax({
|
||||
url: Routes.controllers.LibraryAdvisor.scan().url,
|
||||
data: JSON.stringify(identifier),
|
||||
method: 'POST',
|
||||
dataType: "text",
|
||||
contentType : 'application/json',
|
||||
success: function(res){
|
||||
resultsArea.html(res);
|
||||
enableSubmit();
|
||||
},
|
||||
error: function(x, e){
|
||||
if(x.status === 404){
|
||||
resultsArea.html(x.responseText);
|
||||
}else{
|
||||
resultsArea.html($('<div class="alert alert-danger">An error has happened during scan. Check logs for more information.</div>'))
|
||||
console.log("error", e)
|
||||
}
|
||||
enableSubmit();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(function(){
|
||||
$('#library-identifier').keydown(function (e) {
|
||||
var isEnter = (e.keyCode === 13 || e.keyCode === 10);
|
||||
if (isEnter && !e.shiftKey) { // capture enter, pass shift+enter
|
||||
LibraryAdvisorUI.scan();
|
||||
};
|
||||
}).on("input", function(){
|
||||
var $this = $(this);
|
||||
$this.scrollTop($this.height());
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
</script>
|
||||
<div class="alert alert-info">This tool helps you with selecting a new libraries (or with choosing the right library version for update) by automating a boring part of the process: It can look for known vulnerabilities.</div>
|
||||
<div class="input-group">
|
||||
<div id="library-identifier-wrapper">
|
||||
<textarea
|
||||
class="form-control" id="library-identifier"
|
||||
placeholder="Specification of one library"
|
||||
data-toggle="tooltip" data-placement="bottom"
|
||||
title="Supported formats:<ul>@for(hint <- inputHints){<li>@hint.toString()</li>}</ul>"
|
||||
data-html="true"
|
||||
style="height: 46px;"
|
||||
>@identifier</textarea>
|
||||
</div>
|
||||
<span class="input-group-btn">
|
||||
<button id="submit-button" class="btn btn-primary btn-lg" onclick="LibraryAdvisorUI.scan()">Scan</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="scan-results"></div>
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
@import services.SingleLibraryScanResult
|
||||
@(isDbOld: Boolean, singleLibraryScanResult: SingleLibraryScanResult)(implicit header: DefaultRequest, mainTemplateData: MainTemplateData)
|
||||
@import singleLibraryScanResult.{transitiveDependencies, includesTransitive, mainDependency}
|
||||
<h2>Overall result</h2>
|
||||
@vulnerableTransitive = @{transitiveDependencies.exists(_.isVulnerable)}
|
||||
@vulnerableMain = @{mainDependency.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>
|
||||
}
|
||||
@(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>
|
||||
}
|
||||
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", Seq(mainDependency), None, expand = _.isVulnerable, addButtons = false, lazyLoad = false, showAffectedProjects = false, expandVulnerabilities = true, vulnerabilitySearch = false)
|
||||
@if(includesTransitive) {
|
||||
<h2>Transitive dependencies</h2>
|
||||
@if(transitiveDependencies.nonEmpty) {
|
||||
@if(vulnerableTransitive){
|
||||
<div class="alert alert-info">Those vulnerabilities are primarily sorted by highest-rated known vulnerability. Transitive dependencies without a known vulnerability are at the end of the list.</div>
|
||||
}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)
|
||||
}else{
|
||||
This library has no transitive dependencies.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@()(implicit mainTemplateData: MainTemplateData)
|
||||
@for(msg <- mainTemplateData.templateCustomization.vulnerableLibraryAdvice){
|
||||
@msg
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
@filter = @{projectsOption.flatMap(_._1.selectorString)}
|
||||
<li><a href="@routes.Statistics.vulnerableLibraries(filter)">Vulnerable libraries</a></li>
|
||||
<li><a href="@routes.Statistics.vulnerabilities(filter, None)">Vulnerabilities</a></li>
|
||||
<li><a href="@routes.LibraryAdvisor.index()">Scan library</a></li>
|
||||
<li><a href="@routes.Notifications.listProjects(filter)">Notifications</a></li>
|
||||
<li><a href="@routes.Application.index(Map())">Status</a></li>
|
||||
<li><a href="#" data-toggle="collapse" data-target=".extended-menu">…</a></li>
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
"all",
|
||||
allDependencies.sortBy(_.identifiers.toIndexedSeq.sortBy(i => (i.confidence.id, i.identifierType, i.name)).mkString(", ")),
|
||||
selectorOption = projectsWithSelection.selectorString,
|
||||
expandByDefault = false,
|
||||
addButtons = false
|
||||
)
|
||||
|
||||
|
||||
@@ -62,15 +62,8 @@ $(document).ready(function(){
|
||||
</div>
|
||||
@dependencyList(
|
||||
"vulnerable",
|
||||
vulnerableDependencies.sortBy(d => (
|
||||
d.maxCvssScore.map(-_), // maximum CVSS score is the king
|
||||
if(d.maxCvssScore.isEmpty) Some(-d.dependencies.size) else None, // more affected dependencies if no vulnerability has defined severity
|
||||
-d.vulnerabilities.size, // more vulnerabilities
|
||||
-d.projects.size, // more affected projects
|
||||
d.cpeIdentifiers.map(_.toCpeIdentifierOption.get).toSeq.sorted.mkString(" ")) // at least make the order deterministic
|
||||
),
|
||||
vulnerableDependencies.sorted(severityOrdering),
|
||||
selectorOption = projectsWithSelection.selectorString,
|
||||
expandByDefault = false,
|
||||
addButtons = false
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user