reorganize report class
This commit is contained in:
parent
21c68cd795
commit
f8d0f10c78
@ -1,46 +1,17 @@
|
|||||||
package clair
|
package clair
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/clair/api/v1"
|
"github.com/coreos/clair/api/v1"
|
||||||
"github.com/coreos/clair/cmd/clairctl/xstrings"
|
"github.com/coreos/clair/cmd/clairctl/xstrings"
|
||||||
"github.com/coreos/clair/utils/types"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var uri string
|
var uri string
|
||||||
var healthURI string
|
var healthURI string
|
||||||
|
|
||||||
//Report Reporting Config value
|
|
||||||
var Report ReportConfig
|
|
||||||
|
|
||||||
//VulnerabiliesCounts Total count of vulnerabilities by type
|
|
||||||
type vulnerabiliesCounts map[types.Priority]int
|
|
||||||
|
|
||||||
//Total return to total of Vulnerabilities
|
|
||||||
func (v vulnerabiliesCounts) Total() int {
|
|
||||||
var c int
|
|
||||||
for _, count := range v {
|
|
||||||
c += count
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
//Count return count of severities in Vulnerabilities
|
|
||||||
func (v vulnerabiliesCounts) Count(severity string) int {
|
|
||||||
return v[types.Priority(severity)]
|
|
||||||
}
|
|
||||||
|
|
||||||
//RelativeCount get the percentage of vulnerabilities of a severity
|
|
||||||
func (v vulnerabiliesCounts) RelativeCount(severity string) float64 {
|
|
||||||
count := v[types.Priority(severity)]
|
|
||||||
result := float64(count) / float64(v.Total()) * 100
|
|
||||||
return math.Ceil(result*100) / 100
|
|
||||||
}
|
|
||||||
|
|
||||||
//ImageAnalysis Full image analysis
|
//ImageAnalysis Full image analysis
|
||||||
type ImageAnalysis struct {
|
type ImageAnalysis struct {
|
||||||
Registry, ImageName, Tag string
|
Registry, ImageName, Tag string
|
||||||
@ -51,41 +22,11 @@ func (imageAnalysis ImageAnalysis) String() string {
|
|||||||
return imageAnalysis.Registry + "/" + imageAnalysis.ImageName + ":" + imageAnalysis.Tag
|
return imageAnalysis.Registry + "/" + imageAnalysis.ImageName + ":" + imageAnalysis.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountVulnerabilities counts all image vulnerability
|
|
||||||
func (imageAnalysis ImageAnalysis) countVulnerabilities(l v1.Layer) int {
|
|
||||||
count := 0
|
|
||||||
for _, f := range l.Features {
|
|
||||||
count += len(f.Vulnerabilities)
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountAllVulnerabilities Total count of vulnerabilities
|
|
||||||
func (imageAnalysis ImageAnalysis) CountAllVulnerabilities() vulnerabiliesCounts {
|
|
||||||
result := make(vulnerabiliesCounts)
|
|
||||||
|
|
||||||
l := imageAnalysis.Layers[len(imageAnalysis.Layers)-1]
|
|
||||||
|
|
||||||
for _, f := range l.Layer.Features {
|
|
||||||
|
|
||||||
for _, v := range f.Vulnerabilities {
|
|
||||||
result[types.Priority(v.Severity)]++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
//LastLayer return the last layer of ImageAnalysis
|
//LastLayer return the last layer of ImageAnalysis
|
||||||
func (imageAnalysis ImageAnalysis) LastLayer() *v1.Layer {
|
func (imageAnalysis ImageAnalysis) LastLayer() *v1.Layer {
|
||||||
return imageAnalysis.Layers[len(imageAnalysis.Layers)-1].Layer
|
return imageAnalysis.Layers[len(imageAnalysis.Layers)-1].Layer
|
||||||
}
|
}
|
||||||
|
|
||||||
type vulnerabilityWithFeature struct {
|
|
||||||
v1.Vulnerability
|
|
||||||
Feature string
|
|
||||||
}
|
|
||||||
|
|
||||||
func fmtURI(u string, port int) string {
|
func fmtURI(u string, port int) string {
|
||||||
|
|
||||||
if port != 0 {
|
if port != 0 {
|
||||||
|
@ -7,13 +7,15 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSampleAnalysis() []byte {
|
func getSampleAnalysis() []byte {
|
||||||
file, err := ioutil.ReadFile("./samples/clair_report.json")
|
file, err := ioutil.ReadFile("./samples/clair_report.json")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("File error: %v\n", err)
|
logrus.Errorf("File error: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return file
|
return file
|
||||||
@ -28,7 +30,7 @@ func newServer(httpStatus int) *httptest.Server {
|
|||||||
func TestIsHealthy(t *testing.T) {
|
func TestIsHealthy(t *testing.T) {
|
||||||
server := newServer(http.StatusOK)
|
server := newServer(http.StatusOK)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
uri = server.URL
|
healthURI = server.URL
|
||||||
if h := IsHealthy(); !h {
|
if h := IsHealthy(); !h {
|
||||||
t.Errorf("IsHealthy() => %v, want %v", h, true)
|
t.Errorf("IsHealthy() => %v, want %v", h, true)
|
||||||
}
|
}
|
||||||
@ -43,37 +45,6 @@ func TestIsNotHealthy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func TestCountAllVulnerabilities(t *testing.T) {
|
|
||||||
|
|
||||||
// var analysis ImageAnalysis
|
|
||||||
// err := json.Unmarshal([]byte(getSampleAnalysis()), &analysis)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// t.Errorf("Failing with error: %v", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// vulnerabilitiesCount := analysis.CountAllVulnerabilities()
|
|
||||||
|
|
||||||
// if vulnerabilitiesCount.Total != 77 {
|
|
||||||
// t.Errorf("analysis.CountAllVulnerabilities().Total => %v, want 77", vulnerabilitiesCount.Total)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if vulnerabilitiesCount.High != 1 {
|
|
||||||
// t.Errorf("analysis.CountAllVulnerabilities().High => %v, want 1", vulnerabilitiesCount.High)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if vulnerabilitiesCount.Medium != 18 {
|
|
||||||
// t.Errorf("analysis.CountAllVulnerabilities().Medium => %v, want 18", vulnerabilitiesCount.Medium)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if vulnerabilitiesCount.Low != 57 {
|
|
||||||
// t.Errorf("analysis.CountAllVulnerabilities().Low => %v, want 57", vulnerabilitiesCount.Low)
|
|
||||||
// }
|
|
||||||
// if vulnerabilitiesCount.Negligible != 1 {
|
|
||||||
// t.Errorf("analysis.CountAllVulnerabilities().Negligible => %v, want 1", vulnerabilitiesCount.Negligible)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
func TestRelativeCount(t *testing.T) {
|
func TestRelativeCount(t *testing.T) {
|
||||||
var analysis ImageAnalysis
|
var analysis ImageAnalysis
|
||||||
err := json.Unmarshal([]byte(getSampleAnalysis()), &analysis)
|
err := json.Unmarshal([]byte(getSampleAnalysis()), &analysis)
|
||||||
@ -82,8 +53,8 @@ func TestRelativeCount(t *testing.T) {
|
|||||||
t.Errorf("Failing with error: %v", err)
|
t.Errorf("Failing with error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vulnerabilitiesCount := analysis.CountAllVulnerabilities()
|
vulnerabilitiesCount := allVulnerabilities(analysis)
|
||||||
|
fmt.Printf("v: %v\n", vulnerabilitiesCount)
|
||||||
if vulnerabilitiesCount.RelativeCount("High") != 1.3 {
|
if vulnerabilitiesCount.RelativeCount("High") != 1.3 {
|
||||||
t.Errorf("analysis.CountAllVulnerabilities().RelativeCount(\"High\") => %v, want 1.3", vulnerabilitiesCount.RelativeCount("High"))
|
t.Errorf("analysis.CountAllVulnerabilities().RelativeCount(\"High\") => %v, want 1.3", vulnerabilitiesCount.RelativeCount("High"))
|
||||||
}
|
}
|
||||||
@ -96,34 +67,3 @@ func TestRelativeCount(t *testing.T) {
|
|||||||
t.Errorf("analysis.CountAllVulnerabilities().RelativeCount(\"Low\") => %v, want 74.03", vulnerabilitiesCount.RelativeCount("Low"))
|
t.Errorf("analysis.CountAllVulnerabilities().RelativeCount(\"Low\") => %v, want 74.03", vulnerabilitiesCount.RelativeCount("Low"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func TestFeatureWeight(t *testing.T) {
|
|
||||||
// feature := Feature{
|
|
||||||
// Vulnerabilities: []Vulnerability{},
|
|
||||||
// }
|
|
||||||
|
|
||||||
// v1 := Vulnerability{
|
|
||||||
// Severity: "High",
|
|
||||||
// }
|
|
||||||
|
|
||||||
// v2 := Vulnerability{
|
|
||||||
// Severity: "Medium",
|
|
||||||
// }
|
|
||||||
|
|
||||||
// v3 := Vulnerability{
|
|
||||||
// Severity: "Low",
|
|
||||||
// }
|
|
||||||
|
|
||||||
// v4 := Vulnerability{
|
|
||||||
// Severity: "Negligible",
|
|
||||||
// }
|
|
||||||
|
|
||||||
// feature.Vulnerabilities = append(feature.Vulnerabilities, v1)
|
|
||||||
// feature.Vulnerabilities = append(feature.Vulnerabilities, v2)
|
|
||||||
// feature.Vulnerabilities = append(feature.Vulnerabilities, v3)
|
|
||||||
// feature.Vulnerabilities = append(feature.Vulnerabilities, v4)
|
|
||||||
|
|
||||||
// if feature.Weight() != 10 {
|
|
||||||
// t.Errorf("feature.Weigh => %v, want 6", feature.Weight())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
package clair
|
package clair
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//IsHealthy return Health clair result
|
||||||
func IsHealthy() bool {
|
func IsHealthy() bool {
|
||||||
logrus.Debugln("requesting health on: " + healthURI)
|
logrus.Debugln("requesting health on: " + healthURI)
|
||||||
response, err := http.Get(healthURI)
|
response, err := http.Get(healthURI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logrus.Errorf("requesting Clair health: %v", err)
|
||||||
fmt.Fprintf(os.Stderr, "requesting Clair health: %v", err)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
@ -3,6 +3,7 @@ package clair
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/coreos/clair/api/v1"
|
"github.com/coreos/clair/api/v1"
|
||||||
@ -12,6 +13,9 @@ import (
|
|||||||
//execute go generate ./clair
|
//execute go generate ./clair
|
||||||
//go:generate go-bindata -pkg clair -o templates.go templates/...
|
//go:generate go-bindata -pkg clair -o templates.go templates/...
|
||||||
|
|
||||||
|
//Report Reporting Config value
|
||||||
|
var Report ReportConfig
|
||||||
|
|
||||||
//ReportConfig Reporting configuration
|
//ReportConfig Reporting configuration
|
||||||
type ReportConfig struct {
|
type ReportConfig struct {
|
||||||
Path string
|
Path string
|
||||||
@ -27,7 +31,8 @@ func ReportAsHTML(analyzes ImageAnalysis) (string, error) {
|
|||||||
|
|
||||||
funcs := template.FuncMap{
|
funcs := template.FuncMap{
|
||||||
"vulnerabilities": vulnerabilities,
|
"vulnerabilities": vulnerabilities,
|
||||||
"sortedVulnerabilities": SortedVulnerabilities,
|
"allVulnerabilities": allVulnerabilities,
|
||||||
|
"sortedVulnerabilities": sortedVulnerabilities,
|
||||||
}
|
}
|
||||||
|
|
||||||
templte := template.Must(template.New("analysis-template").Funcs(funcs).Parse(string(asset)))
|
templte := template.Must(template.New("analysis-template").Funcs(funcs).Parse(string(asset)))
|
||||||
@ -49,6 +54,51 @@ func invertedPriorities() []types.Priority {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type vulnerabilityWithFeature struct {
|
||||||
|
v1.Vulnerability
|
||||||
|
Feature string
|
||||||
|
}
|
||||||
|
|
||||||
|
//VulnerabiliesCounts Total count of vulnerabilities by type
|
||||||
|
type vulnerabiliesCounts map[types.Priority]int
|
||||||
|
|
||||||
|
//Total return to total of Vulnerabilities
|
||||||
|
func (v vulnerabiliesCounts) Total() int {
|
||||||
|
var c int
|
||||||
|
for _, count := range v {
|
||||||
|
c += count
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
//Count return count of severities in Vulnerabilities
|
||||||
|
func (v vulnerabiliesCounts) Count(severity string) int {
|
||||||
|
return v[types.Priority(severity)]
|
||||||
|
}
|
||||||
|
|
||||||
|
//RelativeCount get the percentage of vulnerabilities of a severity
|
||||||
|
func (v vulnerabiliesCounts) RelativeCount(severity string) float64 {
|
||||||
|
count := v[types.Priority(severity)]
|
||||||
|
result := float64(count) / float64(v.Total()) * 100
|
||||||
|
return math.Ceil(result*100) / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
// allVulnerabilities Total count of vulnerabilities
|
||||||
|
func allVulnerabilities(imageAnalysis ImageAnalysis) vulnerabiliesCounts {
|
||||||
|
result := make(vulnerabiliesCounts)
|
||||||
|
|
||||||
|
l := imageAnalysis.Layers[len(imageAnalysis.Layers)-1]
|
||||||
|
|
||||||
|
for _, f := range l.Layer.Features {
|
||||||
|
|
||||||
|
for _, v := range f.Vulnerabilities {
|
||||||
|
result[types.Priority(v.Severity)]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
//Vulnerabilities return a list a vulnerabilities
|
//Vulnerabilities return a list a vulnerabilities
|
||||||
func vulnerabilities(imageAnalysis ImageAnalysis) map[types.Priority][]vulnerabilityWithFeature {
|
func vulnerabilities(imageAnalysis ImageAnalysis) map[types.Priority][]vulnerabilityWithFeature {
|
||||||
|
|
||||||
@ -66,7 +116,7 @@ func vulnerabilities(imageAnalysis ImageAnalysis) map[types.Priority][]vulnerabi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SortedVulnerabilities get all vulnerabilities sorted by Severity
|
// SortedVulnerabilities get all vulnerabilities sorted by Severity
|
||||||
func SortedVulnerabilities(imageAnalysis ImageAnalysis) []v1.Feature {
|
func sortedVulnerabilities(imageAnalysis ImageAnalysis) []v1.Feature {
|
||||||
features := []v1.Feature{}
|
features := []v1.Feature{}
|
||||||
|
|
||||||
l := imageAnalysis.Layers[len(imageAnalysis.Layers)-1]
|
l := imageAnalysis.Layers[len(imageAnalysis.Layers)-1]
|
||||||
|
@ -34,7 +34,7 @@ func TestReportAsHtml(t *testing.T) {
|
|||||||
|
|
||||||
func TestInvertedPriorities(t *testing.T) {
|
func TestInvertedPriorities(t *testing.T) {
|
||||||
expected := []types.Priority{types.Defcon1, types.Critical, types.High, types.Medium, types.Low, types.Negligible, types.Unknown}
|
expected := []types.Priority{types.Defcon1, types.Critical, types.High, types.Medium, types.Low, types.Negligible, types.Unknown}
|
||||||
ip := InvertedPriorities()
|
ip := invertedPriorities()
|
||||||
fmt.Printf("%v - %v", len(expected), len(ip))
|
fmt.Printf("%v - %v", len(expected), len(ip))
|
||||||
for i, v := range ip {
|
for i, v := range ip {
|
||||||
if v != expected[i] {
|
if v != expected[i] {
|
||||||
|
@ -1553,28 +1553,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"Layer": {
|
|
||||||
"Name": "sha256:9e0bc8a71bde464f710bc2b593a1fc21521517671e918687892303151331fa56",
|
|
||||||
"Namespace": "ubuntu:14.04",
|
|
||||||
"ParentName": "sha256:27aa681c95e5165caf287dcfe896532df4ae8b10e099500f2f8f71acf4002a89",
|
|
||||||
"IndexedByVersion": 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Layer": {
|
|
||||||
"Name": "sha256:27aa681c95e5165caf287dcfe896532df4ae8b10e099500f2f8f71acf4002a89",
|
|
||||||
"Namespace": "ubuntu:14.04",
|
|
||||||
"ParentName": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4",
|
|
||||||
"IndexedByVersion": 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Layer": {
|
|
||||||
"Name": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4",
|
|
||||||
"IndexedByVersion": 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
File diff suppressed because one or more lines are too long
@ -452,10 +452,11 @@
|
|||||||
|
|
||||||
<div class="app-intro clearfix">
|
<div class="app-intro clearfix">
|
||||||
<h2>Image: {{.ImageName}}</h2>
|
<h2>Image: {{.ImageName}}</h2>
|
||||||
|
{{ $ia := .}}
|
||||||
|
|
||||||
<section class="summary">
|
<section class="summary">
|
||||||
<div>
|
<div>
|
||||||
{{with $vulnerabilitiesCount := .CountAllVulnerabilities}}
|
{{with $vulnerabilitiesCount := allVulnerabilities $ia}}
|
||||||
<p><span class="lead"><strong>Total : {{$vulnerabilitiesCount.Total}} vulnerabilities</strong></span></p>
|
<p><span class="lead"><strong>Total : {{$vulnerabilitiesCount.Total}} vulnerabilities</strong></span></p>
|
||||||
</p>
|
</p>
|
||||||
<div class="summary-text">
|
<div class="summary-text">
|
||||||
@ -489,7 +490,6 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="graph">
|
<div class="graph">
|
||||||
{{ $ia := .}}
|
|
||||||
{{range $k,$v := vulnerabilities $ia}}
|
{{range $k,$v := vulnerabilities $ia}}
|
||||||
{{range $v}}
|
{{range $v}}
|
||||||
<a class="node {{.Severity}}" href="#{{ .Name }}">
|
<a class="node {{.Severity}}" href="#{{ .Name }}">
|
||||||
|
Loading…
Reference in New Issue
Block a user