update templates
This commit is contained in:
parent
d78cb4356d
commit
b3d7eb7060
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
**/.vscode
|
**/.vscode
|
||||||
|
/cmd/clairctl/reports
|
||||||
|
@ -19,27 +19,34 @@ var Report ReportConfig
|
|||||||
|
|
||||||
//VulnerabiliesCounts Total count of vulnerabilities
|
//VulnerabiliesCounts Total count of vulnerabilities
|
||||||
type VulnerabiliesCounts struct {
|
type VulnerabiliesCounts struct {
|
||||||
Total int
|
Total int
|
||||||
High int
|
Unknown, Negligible, Low, Medium, High, Critical, Defcon1 int
|
||||||
Medium int
|
|
||||||
Low int
|
|
||||||
Negligible int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//RelativeCount get the percentage of vulnerabilities of a severity
|
//RelativeCount get the percentage of vulnerabilities of a severity
|
||||||
func (vulnerabilityCount VulnerabiliesCounts) RelativeCount(severity string) float64 {
|
func (vulnerabilityCount VulnerabiliesCounts) RelativeCount(severity string) float64 {
|
||||||
var count int
|
var count int
|
||||||
|
|
||||||
switch severity {
|
switch strings.TrimSpace(severity) {
|
||||||
|
case "Defcon1":
|
||||||
|
count = vulnerabilityCount.Defcon1
|
||||||
|
case "Critical":
|
||||||
|
count = vulnerabilityCount.Critical
|
||||||
case "High":
|
case "High":
|
||||||
count = vulnerabilityCount.High
|
count = vulnerabilityCount.High
|
||||||
case "Medium":
|
case "Medium":
|
||||||
count = vulnerabilityCount.Medium
|
count = vulnerabilityCount.Medium
|
||||||
case "Low":
|
case "Low":
|
||||||
count = vulnerabilityCount.Low
|
count = vulnerabilityCount.Low
|
||||||
|
case "Negligible":
|
||||||
|
count = vulnerabilityCount.Negligible
|
||||||
|
case "Unknown":
|
||||||
|
count = vulnerabilityCount.Unknown
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return math.Ceil(float64(count)/float64(vulnerabilityCount.Total)*100*100) / 100
|
result := float64(count) / float64(vulnerabilityCount.Total) * 100
|
||||||
|
return math.Ceil(result*100) / 100
|
||||||
}
|
}
|
||||||
|
|
||||||
//ImageAnalysis Full image analysis
|
//ImageAnalysis Full image analysis
|
||||||
@ -71,25 +78,36 @@ func (imageAnalysis ImageAnalysis) CountVulnerabilities(l v1.Layer) int {
|
|||||||
func (imageAnalysis ImageAnalysis) CountAllVulnerabilities() VulnerabiliesCounts {
|
func (imageAnalysis ImageAnalysis) CountAllVulnerabilities() VulnerabiliesCounts {
|
||||||
var result VulnerabiliesCounts
|
var result VulnerabiliesCounts
|
||||||
result.Total = 0
|
result.Total = 0
|
||||||
|
result.Defcon1 = 0
|
||||||
|
result.Critical = 0
|
||||||
result.High = 0
|
result.High = 0
|
||||||
result.Medium = 0
|
result.Medium = 0
|
||||||
result.Low = 0
|
result.Low = 0
|
||||||
result.Negligible = 0
|
result.Negligible = 0
|
||||||
|
result.Unknown = 0
|
||||||
|
|
||||||
for _, l := range imageAnalysis.Layers {
|
l := imageAnalysis.Layers[len(imageAnalysis.Layers)-1]
|
||||||
for _, f := range l.Layer.Features {
|
|
||||||
result.Total += len(f.Vulnerabilities)
|
for _, f := range l.Layer.Features {
|
||||||
for _, v := range f.Vulnerabilities {
|
|
||||||
switch v.Severity {
|
result.Total += len(f.Vulnerabilities)
|
||||||
case "High":
|
|
||||||
result.High++
|
for _, v := range f.Vulnerabilities {
|
||||||
case "Medium":
|
switch v.Severity {
|
||||||
result.Medium++
|
case "Defcon1":
|
||||||
case "Low":
|
result.Defcon1++
|
||||||
result.Low++
|
case "Critical":
|
||||||
case "Negligible":
|
result.Critical++
|
||||||
result.Negligible++
|
case "High":
|
||||||
}
|
result.High++
|
||||||
|
case "Medium":
|
||||||
|
result.Medium++
|
||||||
|
case "Low":
|
||||||
|
result.Low++
|
||||||
|
case "Negligible":
|
||||||
|
result.Negligible++
|
||||||
|
case "Unknown":
|
||||||
|
result.Unknown++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,13 +125,19 @@ func (v Vulnerability) Weight() int {
|
|||||||
weight := 0
|
weight := 0
|
||||||
|
|
||||||
switch v.Severity {
|
switch v.Severity {
|
||||||
|
case "Defcon1":
|
||||||
|
weight = 7
|
||||||
|
case "Critical":
|
||||||
|
weight = 6
|
||||||
case "High":
|
case "High":
|
||||||
weight = 4
|
weight = 5
|
||||||
case "Medium":
|
case "Medium":
|
||||||
weight = 3
|
weight = 4
|
||||||
case "Low":
|
case "Low":
|
||||||
weight = 2
|
weight = 3
|
||||||
case "Negligible":
|
case "Negligible":
|
||||||
|
weight = 2
|
||||||
|
case "Unknown":
|
||||||
weight = 1
|
weight = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,47 +217,48 @@ func (a FeatureByVulnerabilities) Less(i, j int) bool {
|
|||||||
// SortLayers give layers ordered by vulnerability algorithm
|
// SortLayers give layers ordered by vulnerability algorithm
|
||||||
func (imageAnalysis ImageAnalysis) SortLayers() []Layer {
|
func (imageAnalysis ImageAnalysis) SortLayers() []Layer {
|
||||||
layers := []Layer{}
|
layers := []Layer{}
|
||||||
|
l := imageAnalysis.Layers[len(imageAnalysis.Layers)-1]
|
||||||
|
|
||||||
for _, l := range imageAnalysis.Layers {
|
// for _, l := range imageAnalysis.Layers {
|
||||||
features := []Feature{}
|
features := []Feature{}
|
||||||
|
|
||||||
for _, f := range l.Layer.Features {
|
for _, f := range l.Layer.Features {
|
||||||
vulnerabilities := []Vulnerability{}
|
vulnerabilities := []Vulnerability{}
|
||||||
|
|
||||||
for _, v := range f.Vulnerabilities {
|
for _, v := range f.Vulnerabilities {
|
||||||
nv := Vulnerability{
|
nv := Vulnerability{
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
Severity: v.Severity,
|
Severity: v.Severity,
|
||||||
IntroduceBy: f.Name + ":" + f.Version,
|
IntroduceBy: f.Name + ":" + f.Version,
|
||||||
Description: v.Description,
|
Description: v.Description,
|
||||||
Layer: l.Layer.Name,
|
Layer: l.Layer.Name,
|
||||||
Link: v.Link,
|
Link: v.Link,
|
||||||
}
|
|
||||||
|
|
||||||
vulnerabilities = append(vulnerabilities, nv)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(VulnerabilitiesBySeverity(vulnerabilities))
|
vulnerabilities = append(vulnerabilities, nv)
|
||||||
|
|
||||||
nf := Feature{
|
|
||||||
Name: f.Name,
|
|
||||||
Version: f.Version,
|
|
||||||
Vulnerabilities: vulnerabilities,
|
|
||||||
}
|
|
||||||
|
|
||||||
features = append(features, nf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(FeatureByVulnerabilities(features))
|
sort.Sort(VulnerabilitiesBySeverity(vulnerabilities))
|
||||||
|
|
||||||
nl := Layer{
|
nf := Feature{
|
||||||
Name: l.Layer.Name,
|
Name: f.Name,
|
||||||
Path: l.Layer.Path,
|
Version: f.Version,
|
||||||
Features: features,
|
Vulnerabilities: vulnerabilities,
|
||||||
}
|
}
|
||||||
layers = append(layers, nl)
|
|
||||||
|
features = append(features, nf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Sort(FeatureByVulnerabilities(features))
|
||||||
|
|
||||||
|
nl := Layer{
|
||||||
|
Name: l.Layer.Name,
|
||||||
|
Path: l.Layer.Path,
|
||||||
|
Features: features,
|
||||||
|
}
|
||||||
|
layers = append(layers, nl)
|
||||||
|
// }
|
||||||
|
|
||||||
sort.Sort(LayerByVulnerabilities(layers))
|
sort.Sort(LayerByVulnerabilities(layers))
|
||||||
|
|
||||||
return layers
|
return layers
|
||||||
@ -244,21 +269,23 @@ func (imageAnalysis ImageAnalysis) SortVulnerabilities() []Vulnerability {
|
|||||||
vulnerabilities := []Vulnerability{}
|
vulnerabilities := []Vulnerability{}
|
||||||
|
|
||||||
// there should be a better method, but I don't know how to easlily concert []v1.Vulnerability to [Vulnerability]
|
// there should be a better method, but I don't know how to easlily concert []v1.Vulnerability to [Vulnerability]
|
||||||
for _, l := range imageAnalysis.Layers {
|
l := imageAnalysis.Layers[len(imageAnalysis.Layers)-1]
|
||||||
for _, f := range l.Layer.Features {
|
|
||||||
for _, v := range f.Vulnerabilities {
|
|
||||||
nv := Vulnerability{
|
|
||||||
Name: v.Name,
|
|
||||||
Severity: v.Severity,
|
|
||||||
IntroduceBy: f.Name + ":" + f.Version,
|
|
||||||
Description: v.Description,
|
|
||||||
Layer: l.Layer.Name,
|
|
||||||
}
|
|
||||||
|
|
||||||
vulnerabilities = append(vulnerabilities, nv)
|
// for _, l := range imageAnalysis.Layers {
|
||||||
|
for _, f := range l.Layer.Features {
|
||||||
|
for _, v := range f.Vulnerabilities {
|
||||||
|
nv := Vulnerability{
|
||||||
|
Name: v.Name,
|
||||||
|
Severity: v.Severity,
|
||||||
|
IntroduceBy: f.Name + ":" + f.Version,
|
||||||
|
Description: v.Description,
|
||||||
|
Layer: l.Layer.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vulnerabilities = append(vulnerabilities, nv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
sort.Sort(VulnerabilitiesBySeverity(vulnerabilities))
|
sort.Sort(VulnerabilitiesBySeverity(vulnerabilities))
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//execute go generate ./clair
|
||||||
//go:generate go-bindata -pkg clair -o templates.go templates/...
|
//go:generate go-bindata -pkg clair -o templates.go templates/...
|
||||||
|
|
||||||
//ReportConfig Reporting configuration
|
//ReportConfig Reporting configuration
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,420 +1,560 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
|
<head>
|
||||||
<title>Clair Control report : {{.ImageName}}</title>
|
<title>Clair Control report : {{.ImageName}}</title>
|
||||||
|
|
||||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,600,600italic,400italic,300italic,300' rel='stylesheet' type='text/css'>
|
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,600,600italic,400italic,300italic,300' rel='stylesheet' type='text/css'>
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css">
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: 'Open Sans', sans-serif;
|
font-family: 'Open Sans', sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background: ghostwhite;
|
background: ghostwhite;
|
||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
/* Typography */
|
||||||
|
|
||||||
/* Typography */
|
.lead {
|
||||||
|
font-size: 1.4em;
|
||||||
|
}
|
||||||
|
/* global layout */
|
||||||
|
|
||||||
.lead {
|
.container {
|
||||||
font-size: 1.4em;
|
padding: 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* global layout */
|
.clearfix:after {
|
||||||
.container {
|
content: "";
|
||||||
padding: 0 0;
|
display: block;
|
||||||
}
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.clearfix:after {
|
.row {
|
||||||
content:"";
|
margin: 0 -20px;
|
||||||
display:block;
|
}
|
||||||
clear:both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
.row:after {
|
||||||
margin: 0 -20px;
|
display: block;
|
||||||
}
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.row:after {
|
[class*="col-"] {
|
||||||
display: block;
|
padding: 0 20px;
|
||||||
clear: both;
|
float: left;
|
||||||
}
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
[class*="col-"] {
|
.col-6 {
|
||||||
padding: 0 20px;
|
width: 50%;
|
||||||
float: left;
|
}
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-6 {
|
.panel {
|
||||||
width: 50%;
|
/* padding: 1em; */
|
||||||
}
|
border-radius: 4px;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0px 1px 2px #e2e2e2;
|
||||||
|
}
|
||||||
|
|
||||||
.panel {
|
.panel h2 {
|
||||||
/* padding: 1em; */
|
margin-top: 0;
|
||||||
border-radius: 4px;
|
padding-bottom: .2em;
|
||||||
background: white;
|
border-bottom: solid 1px gainsboro;
|
||||||
box-shadow: 0px 1px 2px #e2e2e2;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.panel h2 {
|
.panel:last-child {
|
||||||
margin-top: 0;
|
margin-bottom: 0;
|
||||||
padding-bottom: .2em;
|
}
|
||||||
border-bottom: solid 1px gainsboro;
|
/* Header */
|
||||||
}
|
|
||||||
|
|
||||||
.panel :last-child {
|
.app-header {
|
||||||
margin-bottom: 0;
|
background: #2196F3;
|
||||||
}
|
color: white;
|
||||||
|
margin: 0 0px 0px 0px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
box-shadow: 0 -2px 16px #263238;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
/* Header */
|
.app-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: lighter;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
.app-header {
|
.app-intro {
|
||||||
background: #2196F3;
|
padding: 20px;
|
||||||
color: white;
|
text-align: center;
|
||||||
margin: 0 0px 0px 0px;
|
color: #263238;
|
||||||
padding: 16px 20px;
|
background: rgba(255, 255, 255, .8);
|
||||||
box-shadow: 0 -2px 16px #263238;
|
border-bottom: solid 1px #ECEFF1;
|
||||||
position: relative;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.app-header h1 {
|
.app-intro h2 {
|
||||||
margin: 0;
|
font-size: 2em;
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
text-transform: uppercase;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.app-intro {
|
.summary {
|
||||||
padding: 20px;
|
line-height: .6em;
|
||||||
text-align: center;
|
}
|
||||||
color: #263238;
|
/* report */
|
||||||
background: rgba(255, 255, 255, .8);
|
|
||||||
border-bottom: solid 1px #ECEFF1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-intro h2 {
|
.report {
|
||||||
font-size: 2em;
|
margin-top: 20px;
|
||||||
font-weight: lighter;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.summary {
|
.graph {
|
||||||
line-height: .6em;
|
margin: 0 auto;
|
||||||
}
|
max-width: 960px;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
/* Style of the graph */
|
||||||
|
|
||||||
/* report */
|
.graph .node {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.report {
|
.graph .node .dot {
|
||||||
margin-top: 20px;
|
position: relative;
|
||||||
}
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
.graph {
|
border-radius: 24px;
|
||||||
margin: 0 auto;
|
float: left;
|
||||||
max-width: 960px;
|
background: gray;
|
||||||
margin-top: 30px;
|
/* box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
|
||||||
}
|
|
||||||
|
|
||||||
/* Style of the graph */
|
|
||||||
.graph .node {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
height: 24px;
|
|
||||||
width: 24px;
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
.graph .node .dot {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
height: 24px;
|
|
||||||
width: 24px;
|
|
||||||
border-radius: 24px;
|
|
||||||
|
|
||||||
float: left;
|
|
||||||
|
|
||||||
background: gray;
|
|
||||||
|
|
||||||
/* box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
|
|
||||||
border: solid 1px rgba(255, 255, 255, .2); */
|
border: solid 1px rgba(255, 255, 255, .2); */
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node.High .dot {
|
.graph .node.Defcon1 .dot {
|
||||||
background: #E91E63;
|
background: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node.Medium .dot {
|
.graph .node.Critical .dot {
|
||||||
background: #FFA726;
|
background: #e81e1e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node.Low .dot {
|
.graph .node.High .dot {
|
||||||
background: #8BC34A;
|
background: #E91E63;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node .popup {
|
.graph .node.Medium .dot {
|
||||||
display: none;
|
background: #FFA726;
|
||||||
|
}
|
||||||
|
|
||||||
width: 300px;
|
.graph .node.Low .dot {
|
||||||
|
background: #8BC34A;
|
||||||
|
}
|
||||||
|
|
||||||
position: absolute;
|
.graph .node.Negligible .dot {
|
||||||
bottom: 100%;
|
background: #37474F;
|
||||||
margin-bottom: 20px;
|
}
|
||||||
margin-left: -150px;
|
|
||||||
left: 2px;
|
|
||||||
|
|
||||||
background: white;
|
.graph .node.Unknown .dot {
|
||||||
box-shadow: 0px 1px 2px rgba(0, 0, 0, .2);
|
background: #37474F;
|
||||||
|
}
|
||||||
|
|
||||||
padding: 10px;
|
.graph .node .popup {
|
||||||
border-radius: 4px;
|
display: none;
|
||||||
/* border: solid 1px #e2e2e2; */
|
width: 300px;
|
||||||
text-shadow: 0 0 0 transparent;
|
position: absolute;
|
||||||
}
|
bottom: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-left: -150px;
|
||||||
|
left: 2px;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0px 1px 2px rgba(0, 0, 0, .2);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
/* border: solid 1px #e2e2e2; */
|
||||||
|
text-shadow: 0 0 0 transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.graph .node .popup:after {
|
.graph .node .popup:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -10px;
|
margin-left: -10px;
|
||||||
display: block;
|
display: block;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-width: 10px 10px 0 10px;
|
border-width: 10px 10px 0 10px;
|
||||||
border-color: white transparent transparent transparent;
|
border-color: white transparent transparent transparent;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node .popup:before {
|
.graph .node .popup:before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -10px;
|
margin-left: -10px;
|
||||||
display: block;
|
display: block;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-width: 11px 11px 0 10px;
|
border-width: 11px 11px 0 10px;
|
||||||
border-color: rgba(0, 0, 0, .2) transparent transparent transparent;
|
border-color: rgba(0, 0, 0, .2) transparent transparent transparent;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node .popup > div {
|
.graph .node .popup > div {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node:hover .dot {
|
.graph .node:hover .dot {
|
||||||
opacity: .8;
|
opacity: .8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .node:hover .popup {
|
.graph .node:hover .popup {
|
||||||
display: block;
|
display: block;
|
||||||
max-height: 180px;
|
max-height: 180px;
|
||||||
color: dimgray;
|
color: dimgray;
|
||||||
}
|
}
|
||||||
|
/* bars */
|
||||||
|
|
||||||
/* bars */
|
.bar-bg {
|
||||||
.bar-bg {
|
display: inline-block;
|
||||||
display: inline-block;
|
width: 240px;
|
||||||
width: 240px;
|
height: 6px;
|
||||||
height: 6px;
|
position: relative;
|
||||||
position: relative;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.bar-bar {
|
.bar-bar {
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: #E91E63;
|
background: #E91E63;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar-bar.High {
|
.bar-bar.Defcon1 {
|
||||||
background: #E91E63;
|
background: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar-bar.Medium {
|
.bar-bar.Critical {
|
||||||
background: #FFA726;
|
background: #e81e1e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar-bar.Low {
|
.bar-bar.High {
|
||||||
background: #8BC34A;
|
background: #E91E63;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vulnerabilities */
|
.bar-bar.Medium {
|
||||||
.report {
|
background: #FFA726;
|
||||||
margin: 18px auto;
|
}
|
||||||
max-width: 960px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report .vulnerabilities,
|
.bar-bar.Low {
|
||||||
.report .features > ul {
|
background: #8BC34A;
|
||||||
margin: 0;
|
}
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report .features > ul {
|
.bar-bar.Negligible {
|
||||||
list-style: none;
|
background: #37474F;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature {
|
.bar-bar.Unknown {
|
||||||
border-bottom: solid 1px #ECEFF1;
|
background: #37474F;
|
||||||
}
|
}
|
||||||
|
/* vulnerabilities */
|
||||||
|
|
||||||
.feature:last-child {
|
.report {
|
||||||
border-color: #CFD8DC;
|
margin: 18px auto;
|
||||||
}
|
max-width: 960px;
|
||||||
|
}
|
||||||
|
|
||||||
.feature__title {
|
.report .vulnerabilities,
|
||||||
padding: 1em;
|
.report .features > ul {
|
||||||
}
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.vulnerabilities {
|
.report .features > ul {
|
||||||
padding-left: 2.6em !important;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vulnerability {
|
.feature {
|
||||||
padding-bottom: .8em;
|
border-bottom: solid 1px #ECEFF1;
|
||||||
padding-right: 2.2em;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.vulnerabilities .High .name {
|
.feature:last-child {
|
||||||
color: #E91E63;
|
border-color: #CFD8DC;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vulnerabilities .Medium .name {
|
.feature__title {
|
||||||
color: #FFA726;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vulnerabilities .Low .name {
|
.vulnerabilities {
|
||||||
color: #8BC34A;
|
padding-left: 2.6em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* layers */
|
.vulnerability {
|
||||||
|
padding-bottom: .8em;
|
||||||
|
padding-right: 2.2em;
|
||||||
|
}
|
||||||
|
|
||||||
.layer .layer__title {
|
.vulnerabilities .Defcon1 .name {
|
||||||
cursor: pointer;
|
color: black;
|
||||||
padding: 1em;
|
}
|
||||||
border-bottom: solid 1px #CFD8DC;
|
|
||||||
color: #37474F;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer .layer__title:hover {
|
.vulnerabilities .Critical .name {
|
||||||
background: #ECEFF1;
|
color: #e81e1e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layer.closed .features {
|
.vulnerabilities .High .name {
|
||||||
display: none;
|
color: #E91E63;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vulnerabilities .Medium .name {
|
||||||
|
color: #FFA726;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vulnerabilities .Low .name {
|
||||||
|
color: #8BC34A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vulnerabilities .Negligible .name {
|
||||||
|
color: #37474F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vulnerabilities .Unknown .name {
|
||||||
|
color: #37474F;
|
||||||
|
}
|
||||||
|
/* layers */
|
||||||
|
|
||||||
|
.layer .layer__title {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 1em;
|
||||||
|
border-bottom: solid 1px #CFD8DC;
|
||||||
|
color: #37474F;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer .layer__title:hover {
|
||||||
|
background: #ECEFF1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer.closed .features {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text {
|
||||||
|
display: flex;
|
||||||
|
max-width: 940px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
margin-top: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node {
|
||||||
|
text-align: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node:before {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
height: 10px;
|
||||||
|
width: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #2196F3;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node.Defcon1:before {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node.Critical:before {
|
||||||
|
background: #e81e1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node.High:before {
|
||||||
|
background: #E91E63;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node.Medium:before {
|
||||||
|
background: #FFA726;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node.Low:before {
|
||||||
|
background: #8BC34A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node.Negligible:before {
|
||||||
|
background: #37474F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-text .node.Unknown:before {
|
||||||
|
background: #37474F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph {
|
||||||
|
display: flex;
|
||||||
|
max-width: 940px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #2196F3;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
border-radius: 3px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node {
|
||||||
|
text-align: center;
|
||||||
|
height: 8px;
|
||||||
|
background: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node.Defcon1 {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node.Critical {
|
||||||
|
background: #e81e1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node.High {
|
||||||
|
background: #E91E63;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node.Medium {
|
||||||
|
background: #FFA726;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node.Low {
|
||||||
|
background: #8BC34A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node.Negligible {
|
||||||
|
background: #37474F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative-graph .node.Unknown {
|
||||||
|
background: #37474F;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<h1>Clair Control report</h1>
|
<h1>Clair Control report</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="app-intro clearfix">
|
<div class="app-intro clearfix">
|
||||||
<h2>Image: {{.ImageName}}</h2>
|
<h2>Image: {{.ImageName}}</h2>
|
||||||
|
|
||||||
<section class="summary">
|
<section class="summary">
|
||||||
<div>
|
<div>
|
||||||
{{with $vulnerabilitiesCount := .CountAllVulnerabilities}}
|
{{with $vulnerabilitiesCount := .CountAllVulnerabilities}}
|
||||||
<p><span class="lead"><strong>Total : {{$vulnerabilitiesCount.Total}}</strong></span></p>
|
<p><span class="lead"><strong>Total : {{$vulnerabilitiesCount.Total}} vulnerabilities</strong></span></p>
|
||||||
<p>
|
</p>
|
||||||
<span style="display: inline-block; width: 120px;">Critical : <strong>{{$vulnerabilitiesCount.High}}</strong></span>
|
<div class="summary-text">
|
||||||
<!--<span class="bar-bg">
|
{{if gt $vulnerabilitiesCount.Unknown 0}}
|
||||||
<span class="bar-bar High" style="width: {{$vulnerabilitiesCount.RelativeCount "High"}}%"></span>
|
<div class="node Unknown">Unknown : <strong>{{$vulnerabilitiesCount.Unknown}}</strong></div>
|
||||||
</span>-->
|
{{end}} {{if gt $vulnerabilitiesCount.Negligible 0}}
|
||||||
</p>
|
<div class="node Negligible">Negligible : <strong>{{$vulnerabilitiesCount.Negligible}}</strong></div>
|
||||||
<p>
|
{{end}} {{if gt $vulnerabilitiesCount.Low 0}}
|
||||||
<span style="display: inline-block; width: 120px;">Medium : <strong>{{$vulnerabilitiesCount.Medium}}</strong></span>
|
<div class="node Low">Low : <strong>{{$vulnerabilitiesCount.Low}}</strong></div>
|
||||||
<!--<span class="bar-bg">
|
{{end}} {{if gt $vulnerabilitiesCount.Medium 0}}
|
||||||
<span class="bar-bar Medium" style="width: {{$vulnerabilitiesCount.RelativeCount "Medium"}}%"></span>
|
<div class="node Medium">Medium : <strong>{{$vulnerabilitiesCount.Medium}}</strong></div>
|
||||||
</span>-->
|
{{end}} {{if gt $vulnerabilitiesCount.High 0}}
|
||||||
</p>
|
<div class="node High">High : <strong>{{$vulnerabilitiesCount.High}}</strong></div>
|
||||||
<p>
|
{{end}} {{if gt $vulnerabilitiesCount.Critical 0}}
|
||||||
<span style="display: inline-block; width: 120px;">Low : <strong>{{$vulnerabilitiesCount.Low}}</strong></span>
|
<div class="node Critical">Critical : <strong>{{$vulnerabilitiesCount.Critical}}</strong></div>
|
||||||
<!--<span class="bar-bg">
|
{{end}} {{if gt $vulnerabilitiesCount.Defcon1 0}}
|
||||||
<span class="bar-bar Low" style="width: {{$vulnerabilitiesCount.RelativeCount "Low"}}%"></span>
|
<div class="node Defcon1">Defcon1 : <strong>{{$vulnerabilitiesCount.Defcon1}}</strong></div>
|
||||||
</span>-->
|
|
||||||
</p>
|
|
||||||
<span style="display: inline-block; width: 120px;">Negligible : <strong>{{$vulnerabilitiesCount.Negligible}}</strong></span>
|
|
||||||
<p>
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<div class="graph">
|
|
||||||
{{range .SortVulnerabilities}}
|
|
||||||
<a class="node {{.Severity}}" href="#{{ .Name }}">
|
|
||||||
<div class="dot"></div>
|
|
||||||
<div class="popup">
|
|
||||||
<div><strong>{{.Name}}</strong></div>
|
|
||||||
<div>{{.Severity}}</div>
|
|
||||||
<!--<div>{{.IntroduceBy}}</div>-->
|
|
||||||
<!--<div>{{.Description}}</div>-->
|
|
||||||
<div>{{.Layer}}</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section class="report">
|
|
||||||
<div>
|
|
||||||
<div class="panel">
|
|
||||||
<div class="layers">
|
|
||||||
{{range .SortLayers}}
|
|
||||||
<div id="{{.Name}}" class="layer">
|
|
||||||
<h3 class="layer__title" data-toggle-layer="{{.Name}}">{{.Name}}</h3>
|
|
||||||
<div>{{.Path}}</div>
|
|
||||||
<div class="features">
|
|
||||||
<ul>
|
|
||||||
{{range .Features}}
|
|
||||||
<li class="feature">
|
|
||||||
<div class="feature__title">
|
|
||||||
<strong>{{ .Name }}</strong> <span>{{ .Version }}</span> - <span class="fa fa-{{if .Status}}check-circle{{else}}exclamation-triangle{{end}}" aria-hidden="true"></span>
|
|
||||||
</div>
|
|
||||||
<ul class="vulnerabilities">
|
|
||||||
{{range .Vulnerabilities}}
|
|
||||||
<li class="vulnerability {{ .Severity }}">
|
|
||||||
<a class="vulnerability__title" name="{{ .Name }}"></a>
|
|
||||||
<strong class="name">{{ .Name }}</strong>
|
|
||||||
<div>{{ .Description }}</div>
|
|
||||||
<a href="{{ .Link }}" target="blank">Link</a>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
{{end}}
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="relative-graph">
|
||||||
|
<div class="node Defcon1" style="width: {{$vulnerabilitiesCount.RelativeCount " Defcon1 "}}%"></div>
|
||||||
|
<div class="node Critical" style="width: {{$vulnerabilitiesCount.RelativeCount " Critical "}}%"></div>
|
||||||
|
<div class="node High" style="width: {{$vulnerabilitiesCount.RelativeCount " High "}}%"></div>
|
||||||
|
<div class="node Medium" style="width: {{$vulnerabilitiesCount.RelativeCount " Medium "}}%"></div>
|
||||||
|
<div class="node Low" style="width: {{$vulnerabilitiesCount.RelativeCount " Low "}}%"></div>
|
||||||
|
<div class="node Negligible" style="width: {{$vulnerabilitiesCount.RelativeCount " Negligible "}}%"></div>
|
||||||
|
<div class="node Unknown" style="width: {{$vulnerabilitiesCount.RelativeCount " Unknown "}}%"></div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="graph">
|
||||||
|
{{range .SortVulnerabilities}}
|
||||||
|
<a class="node {{.Severity}}" href="#{{ .Name }}">
|
||||||
|
<div class="dot"></div>
|
||||||
|
<div class="popup">
|
||||||
|
<div><strong>{{.Name}}</strong></div>
|
||||||
|
<div>{{.Severity}}</div>
|
||||||
|
<!--<div>{{.IntroduceBy}}</div>-->
|
||||||
|
<!--<div>{{.Description}}</div>-->
|
||||||
|
<div>{{.Layer}}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
|
||||||
|
<section class="report">
|
||||||
|
<div>
|
||||||
|
<div class="panel">
|
||||||
|
<div class="layers">
|
||||||
|
{{range .SortLayers}}
|
||||||
|
<div id="{{.Name}}" class="layer">
|
||||||
|
<h3 class="layer__title" data-toggle-layer="{{.Name}}">{{.Name}}</h3>
|
||||||
|
<div>{{.Path}}</div>
|
||||||
|
<div class="features">
|
||||||
|
<ul>
|
||||||
|
{{range .Features}}
|
||||||
|
<li class="feature">
|
||||||
|
<div class="feature__title">
|
||||||
|
<strong>{{ .Name }}</strong> <span>{{ .Version }}</span> - <span class="fa fa-{{if .Status}}check-circle{{else}}exclamation-triangle{{end}}" aria-hidden="true"></span>
|
||||||
|
</div>
|
||||||
|
<ul class="vulnerabilities">
|
||||||
|
{{range .Vulnerabilities}}
|
||||||
|
<li class="vulnerability {{ .Severity }}">
|
||||||
|
<a class="vulnerability__title" name="{{ .Name }}"></a>
|
||||||
|
<strong class="name">{{ .Name }}</strong>
|
||||||
|
<div>{{ .Description }}</div>
|
||||||
|
<a href="{{ .Link }}" target="blank">Link</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function() {
|
||||||
const togglers = document.querySelectorAll('[data-toggle-layer]');
|
const togglers = document.querySelectorAll('[data-toggle-layer]');
|
||||||
console.log(togglers);
|
console.log(togglers);
|
||||||
|
|
||||||
for (var i = togglers.length - 1; i >= 0; i--) {
|
for (var i = togglers.length - 1; i >= 0; i--) {
|
||||||
togglers[i].onclick = function (e) {
|
togglers[i].onclick = function(e) {
|
||||||
e.target.parentNode.classList.toggle('closed');
|
e.target.parentNode.classList.toggle('closed');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user