Fix handling of non-features from Clair and other small UI fixes
This commit is contained in:
parent
5b7d6b0638
commit
65037ac5e1
8 changed files with 95 additions and 17 deletions
|
@ -1243,6 +1243,13 @@ a:focus {
|
|||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
color: #ddd;
|
||||
font-size: 46px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-primary-msg {
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
|
|
|
@ -4136,3 +4136,13 @@ i.rocket-icon {
|
|||
color: #888;
|
||||
}
|
||||
|
||||
.nvtooltip h3 {
|
||||
margin: 0;
|
||||
padding: 4px 14px;
|
||||
line-height: 18px;
|
||||
font-weight: normal;
|
||||
background-color: transparent !important;
|
||||
text-align: center;
|
||||
font-size: 16px !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,21 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scanned and has no features -->
|
||||
<div ng-if="securityStatus == 'scanned' && !securityFeatures.length">
|
||||
<div class="empty" style="margin-top: 20px;">
|
||||
<div class="empty-icon">
|
||||
<i class="fa ci-package"></i>
|
||||
</div>
|
||||
<div class="empty-primary-msg">Image is not supported by Quay Security Scanner</div>
|
||||
<div class="empty-secondary-msg">
|
||||
This image has an operating system or package manager unsupported by Quay Security Scanner.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scanned -->
|
||||
<div ng-if="securityStatus == 'scanned'">
|
||||
<div ng-if="securityStatus == 'scanned' && securityFeatures.length">
|
||||
<!-- Header -->
|
||||
<div class="security-header row">
|
||||
<div class="donut-col col-md-3">
|
||||
|
|
|
@ -11,12 +11,25 @@
|
|||
<div class="empty" ng-if="securityStatus == 'failed'">
|
||||
<div class="empty-primary-msg">This image could not be indexed</div>
|
||||
<div class="empty-secondary-msg">
|
||||
Our security scanner was unable to index this image.
|
||||
Quay security scanner was unable to index this image.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scanned -->
|
||||
<div ng-if="securityStatus == 'scanned'">
|
||||
<!-- Scanned and has no features -->
|
||||
<div ng-if="securityStatus == 'scanned' && !securityFeatures.length">
|
||||
<div class="empty" style="margin-top: 20px;">
|
||||
<div class="empty-icon">
|
||||
<i class="fa fa-bug"></i>
|
||||
</div>
|
||||
<div class="empty-primary-msg">Image is not supported by Quay Security Scanner</div>
|
||||
<div class="empty-secondary-msg">
|
||||
This image has an operating system or package manager unsupported by Quay Security Scanner.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scanned and has features -->
|
||||
<div ng-if="securityStatus == 'scanned' && securityFeatures.length">
|
||||
<!-- Header -->
|
||||
<div class="security-header row">
|
||||
<div class="donut-col col-md-3">
|
||||
|
@ -37,13 +50,13 @@
|
|||
</ul>
|
||||
|
||||
<div ng-if="!priorityBreakdown.length">
|
||||
<li class="title-item">Quay Security Scanner has detected no vulnerabilities in this image.</li>
|
||||
Quay Security Scanner has detected no vulnerabilities in this image.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter -->
|
||||
<span class="co-filter-box">
|
||||
<span class="co-filter-box" ng-show="priorityBreakdown.length">
|
||||
<span class="filter-message" ng-if="options.vulnFilter || options.fixableVulns">
|
||||
Showing {{ orderedVulnerabilities.entries.length }} of {{ securityVulnerabilities.length }} Vulnerabilities
|
||||
</span>
|
||||
|
@ -55,7 +68,13 @@
|
|||
<h3>Image Vulnerabilities</h3>
|
||||
|
||||
<!-- Table -->
|
||||
<table class="co-table">
|
||||
<div class="empty" ng-if="!securityVulnerabilities.length"
|
||||
style="margin-top: 20px;">
|
||||
<div class="empty-primary-msg">No vulnerabilities found.</div>
|
||||
<div class="empty-secondary-msg">Quay Security Scanner has detected no vulnerabilities in this image.</div>
|
||||
</div>
|
||||
|
||||
<table class="co-table" ng-show="priorityBreakdown.length">
|
||||
<thead>
|
||||
<td class="caret-col"></td>
|
||||
<td ng-class="tablePredicateClass('name', options.predicate, options.reverse)">
|
||||
|
|
|
@ -143,12 +143,22 @@
|
|||
data-title="The image for this tag could not be scanned for vulnerabilities"
|
||||
bs-tooltip>
|
||||
<i class="fa fa-question-circle"></i>
|
||||
Unrecognized OS
|
||||
Unable to scan image
|
||||
</span>
|
||||
|
||||
<!-- No Vulns -->
|
||||
<!-- No Features -->
|
||||
<span class="failed-scan"
|
||||
ng-if="getTagVulnerabilities(tag).status == 'scanned' && !getTagVulnerabilities(tag).hasFeatures"
|
||||
data-title="The image for this tag has an operating system or package manager unsupported by Quay Security Scanner"
|
||||
bs-tooltip
|
||||
bindonce>
|
||||
<i class="fa fa-times-circle"></i>
|
||||
Unsupported
|
||||
</span>
|
||||
|
||||
<!-- Features and No Vulns -->
|
||||
<span class="no-vulns"
|
||||
ng-if="getTagVulnerabilities(tag).status == 'scanned' && !getTagVulnerabilities(tag).hasVulnerabilities"
|
||||
ng-if="getTagVulnerabilities(tag).status == 'scanned' && getTagVulnerabilities(tag).hasFeatures && !getTagVulnerabilities(tag).hasVulnerabilities"
|
||||
data-title="The image for this tag has no vulnerabilities as found in our database"
|
||||
bs-tooltip
|
||||
bindonce>
|
||||
|
|
|
@ -171,8 +171,11 @@ angular.module('quay').directive('repoPanelTags', function () {
|
|||
'index': 100000
|
||||
};
|
||||
|
||||
var hasFeatures = false;
|
||||
if (resp.data && resp.data.Layer && resp.data.Layer.Features) {
|
||||
resp.data.Layer.Features.forEach(function(feature) {
|
||||
hasFeatures = true;
|
||||
|
||||
if (feature.Vulnerabilities) {
|
||||
feature.Vulnerabilities.forEach(function(vuln) {
|
||||
if (VulnerabilityService.LEVELS[vuln.Severity].index == 0) {
|
||||
|
@ -197,6 +200,7 @@ angular.module('quay').directive('repoPanelTags', function () {
|
|||
}
|
||||
|
||||
imageData.hasVulnerabilities = !!vulnerabilities.length;
|
||||
imageData.hasFeatures = hasFeatures;
|
||||
imageData.vulnerabilities = vulnerabilities;
|
||||
imageData.highestVulnerability = highest;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,11 @@ angular.module('quay').directive('imageFeatureView', function () {
|
|||
|
||||
if (data && data.Layer && data.Layer.Features) {
|
||||
data.Layer.Features.forEach(function(feature) {
|
||||
var imageId = feature.AddedBy.split('.')[0];
|
||||
var imageId = null;
|
||||
if (feature.AddedBy) {
|
||||
imageId = feature.AddedBy.split('.')[0];
|
||||
}
|
||||
|
||||
feature_obj = {
|
||||
'name': feature.Name,
|
||||
'namespace': feature.Namespace,
|
||||
|
@ -268,11 +272,13 @@ angular.module('quay').directive('imageFeatureView', function () {
|
|||
});
|
||||
}
|
||||
|
||||
$scope.featureBreakdown.push({
|
||||
'label': 'None',
|
||||
'value': greenCount,
|
||||
'color': '#2FC98E'
|
||||
});
|
||||
if (greenCount > 0) {
|
||||
$scope.featureBreakdown.push({
|
||||
'label': 'None',
|
||||
'value': greenCount,
|
||||
'color': '#2FC98E'
|
||||
});
|
||||
}
|
||||
|
||||
buildOrderedFeatures();
|
||||
};
|
||||
|
|
|
@ -25,6 +25,10 @@ angular.module('quay').factory('ImageMetadataService', ['UtilService', function(
|
|||
};
|
||||
|
||||
metadataService.getImageCommand = function(image, imageId) {
|
||||
if (!image) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!image.__imageMap) {
|
||||
image.__imageMap = {};
|
||||
for (var i = 0; i < image.history.length; ++i) {
|
||||
|
@ -33,7 +37,12 @@ angular.module('quay').factory('ImageMetadataService', ['UtilService', function(
|
|||
}
|
||||
}
|
||||
|
||||
return getDockerfileCommand(image.__imageMap[imageId].command);
|
||||
var found = image.__imageMap[imageId];
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getDockerfileCommand(found.command);
|
||||
};
|
||||
|
||||
var getDockerfileCommand = function(command) {
|
||||
|
|
Reference in a new issue