Fix handling of non-features from Clair and other small UI fixes

This commit is contained in:
Joseph Schorr 2016-03-04 18:07:44 -05:00
parent 5b7d6b0638
commit 65037ac5e1
8 changed files with 95 additions and 17 deletions

View file

@ -1243,6 +1243,13 @@ a:focus {
border-bottom: none !important; border-bottom: none !important;
} }
.empty-icon {
color: #ddd;
font-size: 46px;
margin-bottom: 20px;
text-align: center;
}
.empty-primary-msg { .empty-primary-msg {
font-size: 18px; font-size: 18px;
margin-bottom: 10px; margin-bottom: 10px;

View file

@ -4136,3 +4136,13 @@ i.rocket-icon {
color: #888; 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;
}

View file

@ -15,8 +15,21 @@
</div> </div>
</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 --> <!-- Scanned -->
<div ng-if="securityStatus == 'scanned'"> <div ng-if="securityStatus == 'scanned' && securityFeatures.length">
<!-- Header --> <!-- Header -->
<div class="security-header row"> <div class="security-header row">
<div class="donut-col col-md-3"> <div class="donut-col col-md-3">

View file

@ -11,12 +11,25 @@
<div class="empty" ng-if="securityStatus == 'failed'"> <div class="empty" ng-if="securityStatus == 'failed'">
<div class="empty-primary-msg">This image could not be indexed</div> <div class="empty-primary-msg">This image could not be indexed</div>
<div class="empty-secondary-msg"> <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>
</div> </div>
<!-- Scanned --> <!-- Scanned and has no features -->
<div ng-if="securityStatus == 'scanned'"> <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 --> <!-- Header -->
<div class="security-header row"> <div class="security-header row">
<div class="donut-col col-md-3"> <div class="donut-col col-md-3">
@ -37,13 +50,13 @@
</ul> </ul>
<div ng-if="!priorityBreakdown.length"> <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> </div>
</div> </div>
<!-- Filter --> <!-- 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"> <span class="filter-message" ng-if="options.vulnFilter || options.fixableVulns">
Showing {{ orderedVulnerabilities.entries.length }} of {{ securityVulnerabilities.length }} Vulnerabilities Showing {{ orderedVulnerabilities.entries.length }} of {{ securityVulnerabilities.length }} Vulnerabilities
</span> </span>
@ -55,7 +68,13 @@
<h3>Image Vulnerabilities</h3> <h3>Image Vulnerabilities</h3>
<!-- Table --> <!-- 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> <thead>
<td class="caret-col"></td> <td class="caret-col"></td>
<td ng-class="tablePredicateClass('name', options.predicate, options.reverse)"> <td ng-class="tablePredicateClass('name', options.predicate, options.reverse)">

View file

@ -143,12 +143,22 @@
data-title="The image for this tag could not be scanned for vulnerabilities" data-title="The image for this tag could not be scanned for vulnerabilities"
bs-tooltip> bs-tooltip>
<i class="fa fa-question-circle"></i> <i class="fa fa-question-circle"></i>
Unrecognized OS Unable to scan image
</span> </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" <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" data-title="The image for this tag has no vulnerabilities as found in our database"
bs-tooltip bs-tooltip
bindonce> bindonce>

View file

@ -171,8 +171,11 @@ angular.module('quay').directive('repoPanelTags', function () {
'index': 100000 'index': 100000
}; };
var hasFeatures = false;
if (resp.data && resp.data.Layer && resp.data.Layer.Features) { if (resp.data && resp.data.Layer && resp.data.Layer.Features) {
resp.data.Layer.Features.forEach(function(feature) { resp.data.Layer.Features.forEach(function(feature) {
hasFeatures = true;
if (feature.Vulnerabilities) { if (feature.Vulnerabilities) {
feature.Vulnerabilities.forEach(function(vuln) { feature.Vulnerabilities.forEach(function(vuln) {
if (VulnerabilityService.LEVELS[vuln.Severity].index == 0) { if (VulnerabilityService.LEVELS[vuln.Severity].index == 0) {
@ -197,6 +200,7 @@ angular.module('quay').directive('repoPanelTags', function () {
} }
imageData.hasVulnerabilities = !!vulnerabilities.length; imageData.hasVulnerabilities = !!vulnerabilities.length;
imageData.hasFeatures = hasFeatures;
imageData.vulnerabilities = vulnerabilities; imageData.vulnerabilities = vulnerabilities;
imageData.highestVulnerability = highest; imageData.highestVulnerability = highest;
} }

View file

@ -132,7 +132,11 @@ angular.module('quay').directive('imageFeatureView', function () {
if (data && data.Layer && data.Layer.Features) { if (data && data.Layer && data.Layer.Features) {
data.Layer.Features.forEach(function(feature) { 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 = { feature_obj = {
'name': feature.Name, 'name': feature.Name,
'namespace': feature.Namespace, 'namespace': feature.Namespace,
@ -268,11 +272,13 @@ angular.module('quay').directive('imageFeatureView', function () {
}); });
} }
$scope.featureBreakdown.push({ if (greenCount > 0) {
'label': 'None', $scope.featureBreakdown.push({
'value': greenCount, 'label': 'None',
'color': '#2FC98E' 'value': greenCount,
}); 'color': '#2FC98E'
});
}
buildOrderedFeatures(); buildOrderedFeatures();
}; };

View file

@ -25,6 +25,10 @@ angular.module('quay').factory('ImageMetadataService', ['UtilService', function(
}; };
metadataService.getImageCommand = function(image, imageId) { metadataService.getImageCommand = function(image, imageId) {
if (!image) {
return null;
}
if (!image.__imageMap) { if (!image.__imageMap) {
image.__imageMap = {}; image.__imageMap = {};
for (var i = 0; i < image.history.length; ++i) { 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) { var getDockerfileCommand = function(command) {