github.com/SAP/jenkins-library@v1.362.0/pkg/contrast/contrast.go (about) 1 package contrast 2 3 import ( 4 "fmt" 5 6 "github.com/SAP/jenkins-library/pkg/log" 7 ) 8 9 const ( 10 StatusReported = "REPORTED" 11 Critical = "CRITICAL" 12 High = "HIGH" 13 Medium = "MEDIUM" 14 AuditAll = "Audit All" 15 Optional = "Optional" 16 pageSize = 100 17 startPage = 0 18 ) 19 20 type VulnerabilitiesResponse struct { 21 Size int `json:"size"` 22 TotalElements int `json:"totalElements"` 23 TotalPages int `json:"totalPages"` 24 Empty bool `json:"empty"` 25 First bool `json:"first"` 26 Last bool `json:"last"` 27 Vulnerabilities []Vulnerability `json:"content"` 28 } 29 30 type Vulnerability struct { 31 Severity string `json:"severity"` 32 Status string `json:"status"` 33 } 34 35 type ApplicationResponse struct { 36 Id string `json:"id"` 37 Name string `json:"name"` 38 DisplayName string `json:"displayName"` 39 Path string `json:"path"` 40 Language string `json:"language"` 41 Importance string `json:"importance"` 42 } 43 44 type Contrast interface { 45 GetVulnerabilities() error 46 GetAppInfo(appUIUrl, server string) 47 } 48 49 type ContrastInstance struct { 50 url string 51 apiKey string 52 auth string 53 } 54 55 func NewContrastInstance(url, apiKey, auth string) ContrastInstance { 56 return ContrastInstance{ 57 url: url, 58 apiKey: apiKey, 59 auth: auth, 60 } 61 } 62 63 func (contrast *ContrastInstance) GetVulnerabilities() ([]ContrastFindings, error) { 64 url := contrast.url + "/vulnerabilities" 65 client := NewContrastHttpClient(contrast.apiKey, contrast.auth) 66 67 return getVulnerabilitiesFromClient(client, url, startPage) 68 } 69 70 func (contrast *ContrastInstance) GetAppInfo(appUIUrl, server string) (*ApplicationInfo, error) { 71 client := NewContrastHttpClient(contrast.apiKey, contrast.auth) 72 app, err := getApplicationFromClient(client, contrast.url) 73 if err != nil { 74 log.Entry().Errorf("failed to get application from client: %v", err) 75 return nil, err 76 } 77 app.Url = appUIUrl 78 app.Server = server 79 return app, nil 80 } 81 82 func getApplicationFromClient(client ContrastHttpClient, url string) (*ApplicationInfo, error) { 83 var appResponse ApplicationResponse 84 err := client.ExecuteRequest(url, nil, &appResponse) 85 if err != nil { 86 return nil, err 87 } 88 89 return &ApplicationInfo{ 90 Id: appResponse.Id, 91 Name: appResponse.Name, 92 }, nil 93 } 94 95 func getVulnerabilitiesFromClient(client ContrastHttpClient, url string, page int) ([]ContrastFindings, error) { 96 params := map[string]string{ 97 "page": fmt.Sprintf("%d", page), 98 "size": fmt.Sprintf("%d", pageSize), 99 } 100 var vulnsResponse VulnerabilitiesResponse 101 err := client.ExecuteRequest(url, params, &vulnsResponse) 102 if err != nil { 103 return nil, err 104 } 105 106 if vulnsResponse.Empty { 107 log.Entry().Info("empty vulnerabilities response") 108 return []ContrastFindings{}, nil 109 } 110 111 auditAllFindings, optionalFindings := getFindings(vulnsResponse.Vulnerabilities) 112 113 if !vulnsResponse.Last { 114 findings, err := getVulnerabilitiesFromClient(client, url, page+1) 115 if err != nil { 116 return nil, err 117 } 118 accumulateFindings(auditAllFindings, optionalFindings, findings) 119 return findings, nil 120 } 121 return []ContrastFindings{auditAllFindings, optionalFindings}, nil 122 } 123 124 func getFindings(vulnerabilities []Vulnerability) (ContrastFindings, ContrastFindings) { 125 var auditAllFindings, optionalFindings ContrastFindings 126 auditAllFindings.ClassificationName = AuditAll 127 optionalFindings.ClassificationName = Optional 128 129 for _, vuln := range vulnerabilities { 130 if vuln.Severity == Critical || vuln.Severity == High || vuln.Severity == Medium { 131 if vuln.Status != StatusReported { 132 auditAllFindings.Audited += 1 133 } 134 auditAllFindings.Total += 1 135 } else { 136 if vuln.Status != StatusReported { 137 optionalFindings.Audited += 1 138 } 139 optionalFindings.Total += 1 140 } 141 } 142 return auditAllFindings, optionalFindings 143 } 144 145 func accumulateFindings(auditAllFindings, optionalFindings ContrastFindings, contrastFindings []ContrastFindings) { 146 for i, fr := range contrastFindings { 147 if fr.ClassificationName == AuditAll { 148 contrastFindings[i].Total += auditAllFindings.Total 149 contrastFindings[i].Audited += auditAllFindings.Audited 150 } 151 if fr.ClassificationName == Optional { 152 contrastFindings[i].Total += optionalFindings.Total 153 contrastFindings[i].Audited += optionalFindings.Audited 154 } 155 } 156 }