mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-28 05:47:08 +02:00
Refinement of SARIF generation for BD and WS (#3942)
* Fix docs and format * Assessment format added * Added sample file * Added parsing * Added packageurl implementation * Slight refinement * Refactored assessment options * Adapted sample file * First attempt of ws sbom gen * Reworked SBOM generation * Fix test code * Add assessment handling * Update dependencies * Added golden test * Small fix * feat(fortify): Added a check for fortify binary in $PATH (#3925) * added check for fortifyupdate and sourceanalyzer bin Co-authored-by: sumeet patil <sumeet.patil@sap.com> * Modify SARIF * Enhanced SARID contents * Small refinement for hub detect * Small adjustments * Extend SARIF contents * Consistency to Mend part * Fix tests * Fix merge * Fix test * Add debug log, enhance output * Enhance meta info * Fix libType for node * Fix log entry * Fix pointers and test * Fix test * Fix library types * Fix test * Extend libType mappings Co-authored-by: Vinayak S <vinayaks439@gmail.com> Co-authored-by: sumeet patil <sumeet.patil@sap.com>
This commit is contained in:
parent
ed4467282f
commit
c81e741224
@ -493,7 +493,7 @@ func isMajorVulnerability(v bd.Vulnerability) bool {
|
||||
|
||||
func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOptions, influx *detectExecuteScanInflux, utils detectUtils, sys *blackduckSystem) error {
|
||||
errorsOccured := []string{}
|
||||
vulns, _, err := getVulnsAndComponents(config, influx, sys)
|
||||
vulns, components, err := getVulnsAndComponents(config, influx, sys)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to fetch vulnerabilities")
|
||||
}
|
||||
@ -514,7 +514,7 @@ func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOpt
|
||||
}
|
||||
}
|
||||
|
||||
sarif := bd.CreateSarifResultFile(vulns)
|
||||
sarif := bd.CreateSarifResultFile(vulns, components)
|
||||
paths, err := bd.WriteSarifFile(sarif, utils)
|
||||
if err != nil {
|
||||
errorsOccured = append(errorsOccured, fmt.Sprint(err))
|
||||
|
@ -133,6 +133,7 @@ func newWhitesourceScan(config *ScanOptions) *ws.Scan {
|
||||
return &ws.Scan{
|
||||
AggregateProjectName: config.ProjectName,
|
||||
ProductVersion: config.Version,
|
||||
BuildTool: config.BuildTool,
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,6 +353,8 @@ func resolveProjectIdentifiers(config *ScanOptions, scan *ws.Scan, utils whiteso
|
||||
return errors.Wrap(err, "error resolving aggregate project token")
|
||||
}
|
||||
|
||||
scan.ProductToken = config.ProductToken
|
||||
|
||||
return scan.UpdateProjects(config.ProductToken, sys)
|
||||
}
|
||||
|
||||
|
@ -623,8 +623,8 @@ func TestCheckProjectSecurityViolations(t *testing.T) {
|
||||
t.Run("error - some vulnerabilities", func(t *testing.T) {
|
||||
systemMock := ws.NewSystemMock("ignored")
|
||||
systemMock.Alerts = []ws.Alert{
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 7, Name: "CVE-2025-001"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "MAVEN_ARTIFACT"}},
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 6, Name: "CVE-2025-002"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "MAVEN_ARTIFACT"}},
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 7, Name: "CVE-2025-001"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "Java"}},
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 6, Name: "CVE-2025-002"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "Java"}},
|
||||
}
|
||||
influx := whitesourceExecuteScanInflux{}
|
||||
|
||||
@ -637,8 +637,8 @@ func TestCheckProjectSecurityViolations(t *testing.T) {
|
||||
t.Run("success - assessed vulnerabilities", func(t *testing.T) {
|
||||
systemMock := ws.NewSystemMock("ignored")
|
||||
systemMock.Alerts = []ws.Alert{
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 7, Name: "CVE-2025-001"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "MAVEN_ARTIFACT"}},
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 6, Name: "CVE-2025-002"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "MAVEN_ARTIFACT"}},
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 7.8, Name: "CVE-2025-001"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "Java"}},
|
||||
{Vulnerability: ws.Vulnerability{CVSS3Score: 6, Name: "CVE-2025-002"}, Library: ws.Library{KeyID: 42, Name: "test", GroupID: "com.sap", ArtifactID: "test", Version: "1.2.3", LibType: "Java"}},
|
||||
}
|
||||
influx := whitesourceExecuteScanInflux{}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/reporting"
|
||||
"github.com/package-url/packageurl-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -66,10 +67,16 @@ type Components struct {
|
||||
}
|
||||
|
||||
type Component struct {
|
||||
Name string `json:"componentName,omitempty"`
|
||||
Version string `json:"componentVersionName,omitempty"`
|
||||
PolicyStatus string `json:"policyStatus,omitempty"`
|
||||
Metadata `json:"_meta,omitempty"`
|
||||
Name string `json:"componentName,omitempty"`
|
||||
Version string `json:"componentVersionName,omitempty"`
|
||||
ComponentOriginName string `json:"componentVersionOriginName,omitempty"`
|
||||
PrimaryLanguage string `json:"primaryLanguage,omitempty"`
|
||||
PolicyStatus string `json:"policyStatus,omitempty"`
|
||||
Metadata `json:"_meta,omitempty"`
|
||||
}
|
||||
|
||||
func (c Component) ToPackageUrl() *packageurl.PackageURL {
|
||||
return packageurl.NewPackageURL(transformComponentToPurlType(c.PrimaryLanguage), "", c.Name, c.Version, nil, "")
|
||||
}
|
||||
|
||||
type Vulnerabilities struct {
|
||||
@ -85,12 +92,15 @@ type Vulnerability struct {
|
||||
}
|
||||
|
||||
type VulnerabilityWithRemediation struct {
|
||||
VulnerabilityName string `json:"vulnerabilityName,omitempty"`
|
||||
BaseScore float32 `json:"baseScore,omitempty"`
|
||||
Severity string `json:"severity,omitempty"`
|
||||
RemediationStatus string `json:"remediationStatus,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
OverallScore float32 `json:"overallScore,omitempty"`
|
||||
VulnerabilityName string `json:"vulnerabilityName,omitempty"`
|
||||
BaseScore float32 `json:"baseScore,omitempty"`
|
||||
Severity string `json:"severity,omitempty"`
|
||||
RemediationStatus string `json:"remediationStatus,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
OverallScore float32 `json:"overallScore,omitempty"`
|
||||
CweID string `json:"cweId,omitempty"`
|
||||
ExploitabilitySubscore float32 `json:"exploitabilitySubscore,omitempty"`
|
||||
ImpactSubscore float32 `json:"impactSubscore,omitempty"`
|
||||
}
|
||||
|
||||
// Title returns the issue title representation of the contents
|
||||
@ -99,7 +109,7 @@ func (v Vulnerability) Title() string {
|
||||
}
|
||||
|
||||
// ToMarkdown returns the markdown representation of the contents
|
||||
func (v Vulnerability) ToMarkdown() ([]byte, error) {
|
||||
func (v Vulnerability) ToMarkdown(component *Component) ([]byte, error) {
|
||||
vul := reporting.VulnerabilityReport{
|
||||
ArtifactID: v.Name,
|
||||
|
||||
@ -124,9 +134,10 @@ func (v Vulnerability) ToMarkdown() ([]byte, error) {
|
||||
PublishDate: "",
|
||||
Resolution: "",
|
||||
|
||||
Score: float64(v.VulnerabilityWithRemediation.BaseScore),
|
||||
Severity: v.VulnerabilityWithRemediation.Severity,
|
||||
Version: v.Version,
|
||||
Score: float64(v.VulnerabilityWithRemediation.BaseScore),
|
||||
Severity: v.VulnerabilityWithRemediation.Severity,
|
||||
Version: v.Version,
|
||||
PackageURL: component.ToPackageUrl().ToString(),
|
||||
|
||||
// no vulnerability link available, yet
|
||||
VulnerabilityLink: "",
|
||||
@ -137,13 +148,14 @@ func (v Vulnerability) ToMarkdown() ([]byte, error) {
|
||||
}
|
||||
|
||||
// ToTxt returns the textual representation of the contents
|
||||
func (v Vulnerability) ToTxt() string {
|
||||
func (v Vulnerability) ToTxt(component *Component) string {
|
||||
return fmt.Sprintf(`Vulnerability %v
|
||||
Severity: %v
|
||||
Base (NVD) Score: %v
|
||||
Temporal Score: %v
|
||||
Package: %v
|
||||
Installed Version: %v
|
||||
Package URL: %v
|
||||
Description: %v
|
||||
Fix Resolution: %v
|
||||
Link: [%v](%v)`,
|
||||
@ -153,6 +165,7 @@ Link: [%v](%v)`,
|
||||
v.VulnerabilityWithRemediation.OverallScore,
|
||||
v.Name,
|
||||
v.Version,
|
||||
component.ToPackageUrl().ToString(),
|
||||
v.Description,
|
||||
"",
|
||||
"",
|
||||
@ -479,7 +492,7 @@ func (b *Client) apiURL(apiEndpoint string) (*url.URL, error) {
|
||||
}
|
||||
|
||||
func (b *Client) authenticationValid(now time.Time) bool {
|
||||
// //check bearer token timeout
|
||||
// check bearer token timeout
|
||||
expiryTime := b.lastAuthentication.Add(time.Millisecond * time.Duration(b.BearerExpiresInMilliseconds))
|
||||
return now.Sub(expiryTime) < 0
|
||||
}
|
||||
@ -488,3 +501,18 @@ func urlPath(fullUrl string) string {
|
||||
theUrl, _ := url.Parse(fullUrl)
|
||||
return theUrl.Path
|
||||
}
|
||||
|
||||
func transformComponentToPurlType(primaryLanguage string) string {
|
||||
// TODO verify possible relevant values
|
||||
switch primaryLanguage {
|
||||
case "Java":
|
||||
return packageurl.TypeMaven
|
||||
case "Javascript":
|
||||
return packageurl.TypeNPM
|
||||
case "Golang":
|
||||
return packageurl.TypeGolang
|
||||
case "Docker":
|
||||
return packageurl.TypeDocker
|
||||
}
|
||||
return packageurl.TypeGeneric
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package blackduck
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/format"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
@ -13,7 +15,13 @@ import (
|
||||
)
|
||||
|
||||
// CreateSarifResultFile creates a SARIF result from the Vulnerabilities that were brought up by the scan
|
||||
func CreateSarifResultFile(vulns *Vulnerabilities) *format.SARIF {
|
||||
func CreateSarifResultFile(vulns *Vulnerabilities, components *Components) *format.SARIF {
|
||||
// create component lookup map
|
||||
componentLookup := map[string]Component{}
|
||||
for _, comp := range components.Items {
|
||||
componentLookup[fmt.Sprintf("%v/%v", comp.Name, comp.Version)] = comp
|
||||
}
|
||||
|
||||
//Now, we handle the sarif
|
||||
log.Entry().Debug("Creating SARIF file for data transfer")
|
||||
var sarif format.SARIF
|
||||
@ -30,15 +38,16 @@ func CreateSarifResultFile(vulns *Vulnerabilities) *format.SARIF {
|
||||
tool.Driver.InformationUri = "https://community.synopsys.com/s/document-item?bundleId=integrations-detect&topicId=introduction.html&_LANG=enus"
|
||||
|
||||
// Handle results/vulnerabilities
|
||||
collectedRules := []string{}
|
||||
cweIdsForTaxonomies := []string{}
|
||||
if vulns != nil && vulns.Items != nil {
|
||||
for i := 0; i < len(vulns.Items); i++ {
|
||||
v := vulns.Items[i]
|
||||
for _, v := range vulns.Items {
|
||||
component := componentLookup[fmt.Sprintf("%v/%v", v.Name, v.Version)]
|
||||
result := *new(format.Results)
|
||||
id := v.Title()
|
||||
log.Entry().Debugf("Transforming alert %v into SARIF format", id)
|
||||
result.RuleID = id
|
||||
ruleId := v.Title()
|
||||
log.Entry().Debugf("Transforming alert %v into SARIF format", ruleId)
|
||||
result.RuleID = ruleId
|
||||
result.Level = transformToLevel(v.VulnerabilityWithRemediation.Severity)
|
||||
result.RuleIndex = i //Seems very abstract
|
||||
result.Message = new(format.Message)
|
||||
result.Message.Text = v.VulnerabilityWithRemediation.Description
|
||||
result.AnalysisTarget = new(format.ArtifactLocation)
|
||||
@ -46,40 +55,77 @@ func CreateSarifResultFile(vulns *Vulnerabilities) *format.SARIF {
|
||||
result.AnalysisTarget.Index = 0
|
||||
location := format.Location{PhysicalLocation: format.PhysicalLocation{ArtifactLocation: format.ArtifactLocation{URI: v.Name}}}
|
||||
result.Locations = append(result.Locations, location)
|
||||
//TODO add audit and tool related information, maybe fortifyCategory needs to become more general
|
||||
//result.Properties = new(format.SarifProperties)
|
||||
//result.Properties.ToolSeverity
|
||||
//result.Properties.ToolAuditMessage
|
||||
partialFingerprints := new(format.PartialFingerprints)
|
||||
partialFingerprints.PackageURLPlusCVEHash = base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%v+%v", component.ToPackageUrl().ToString(), v.Title())))
|
||||
result.PartialFingerprints = *partialFingerprints
|
||||
cweIdsForTaxonomies = append(cweIdsForTaxonomies, v.VulnerabilityWithRemediation.CweID)
|
||||
|
||||
sarifRule := *new(format.SarifRule)
|
||||
sarifRule.ID = id
|
||||
sarifRule.ShortDescription = new(format.Message)
|
||||
sarifRule.ShortDescription.Text = fmt.Sprintf("%v Package %v", v.VulnerabilityName, v.Name)
|
||||
sarifRule.FullDescription = new(format.Message)
|
||||
sarifRule.FullDescription.Text = v.VulnerabilityWithRemediation.Description
|
||||
sarifRule.DefaultConfiguration = new(format.DefaultConfiguration)
|
||||
sarifRule.DefaultConfiguration.Level = transformToLevel(v.VulnerabilityWithRemediation.Severity)
|
||||
sarifRule.HelpURI = ""
|
||||
markdown, _ := v.ToMarkdown()
|
||||
sarifRule.Help = new(format.Help)
|
||||
sarifRule.Help.Text = v.ToTxt()
|
||||
sarifRule.Help.Markdown = string(markdown)
|
||||
|
||||
ruleProp := *new(format.SarifRuleProperties)
|
||||
ruleProp.Tags = append(ruleProp.Tags, "SECURITY_VULNERABILITY")
|
||||
ruleProp.Tags = append(ruleProp.Tags, v.VulnerabilityWithRemediation.Description)
|
||||
ruleProp.Tags = append(ruleProp.Tags, v.Name)
|
||||
ruleProp.Precision = "very-high"
|
||||
sarifRule.Properties = &ruleProp
|
||||
|
||||
//Finalize: append the result and the rule
|
||||
// append the result
|
||||
sarif.Runs[0].Results = append(sarif.Runs[0].Results, result)
|
||||
tool.Driver.Rules = append(tool.Driver.Rules, sarifRule)
|
||||
|
||||
// only create rule on new CVE
|
||||
if !piperutils.ContainsString(collectedRules, ruleId) {
|
||||
collectedRules = append(collectedRules, ruleId)
|
||||
|
||||
sarifRule := *new(format.SarifRule)
|
||||
sarifRule.ID = ruleId
|
||||
sarifRule.ShortDescription = new(format.Message)
|
||||
sarifRule.ShortDescription.Text = fmt.Sprintf("%v Package %v", v.VulnerabilityName, component.Name)
|
||||
sarifRule.FullDescription = new(format.Message)
|
||||
sarifRule.FullDescription.Text = v.VulnerabilityWithRemediation.Description
|
||||
sarifRule.DefaultConfiguration = new(format.DefaultConfiguration)
|
||||
sarifRule.DefaultConfiguration.Level = transformToLevel(v.VulnerabilityWithRemediation.Severity)
|
||||
sarifRule.HelpURI = ""
|
||||
markdown, _ := v.ToMarkdown(&component)
|
||||
sarifRule.Help = new(format.Help)
|
||||
sarifRule.Help.Text = v.ToTxt(&component)
|
||||
sarifRule.Help.Markdown = string(markdown)
|
||||
|
||||
ruleProp := *new(format.SarifRuleProperties)
|
||||
ruleProp.Tags = append(ruleProp.Tags, "SECURITY_VULNERABILITY")
|
||||
ruleProp.Tags = append(ruleProp.Tags, component.ToPackageUrl().ToString())
|
||||
ruleProp.Tags = append(ruleProp.Tags, v.VulnerabilityWithRemediation.CweID)
|
||||
ruleProp.Precision = "very-high"
|
||||
ruleProp.Impact = fmt.Sprint(v.VulnerabilityWithRemediation.ImpactSubscore)
|
||||
ruleProp.Probability = fmt.Sprint(v.VulnerabilityWithRemediation.ExploitabilitySubscore)
|
||||
ruleProp.SecuritySeverity = fmt.Sprint(v.OverallScore)
|
||||
sarifRule.Properties = &ruleProp
|
||||
|
||||
// append the rule
|
||||
tool.Driver.Rules = append(tool.Driver.Rules, sarifRule)
|
||||
}
|
||||
}
|
||||
}
|
||||
//Finalize: tool
|
||||
sarif.Runs[0].Tool = tool
|
||||
|
||||
// Threadflowlocations is no loger useful: voiding it will make for smaller reports
|
||||
sarif.Runs[0].ThreadFlowLocations = []format.Locations{}
|
||||
|
||||
// Add a conversion object to highlight this isn't native SARIF
|
||||
conversion := new(format.Conversion)
|
||||
conversion.Tool.Driver.Name = "Piper FPR to SARIF converter"
|
||||
conversion.Tool.Driver.InformationUri = "https://github.com/SAP/jenkins-library"
|
||||
conversion.Invocation.ExecutionSuccessful = true
|
||||
convInvocProp := new(format.InvocationProperties)
|
||||
convInvocProp.Platform = runtime.GOOS
|
||||
conversion.Invocation.Properties = convInvocProp
|
||||
sarif.Runs[0].Conversion = conversion
|
||||
|
||||
//handle taxonomies
|
||||
//Only one exists apparently: CWE. It is fixed
|
||||
taxonomy := *new(format.Taxonomies)
|
||||
taxonomy.GUID = "25F72D7E-8A92-459D-AD67-64853F788765"
|
||||
taxonomy.Name = "CWE"
|
||||
taxonomy.Organization = "MITRE"
|
||||
taxonomy.ShortDescription.Text = "The MITRE Common Weakness Enumeration"
|
||||
for key := range cweIdsForTaxonomies {
|
||||
taxa := *new(format.Taxa)
|
||||
taxa.Id = fmt.Sprint(key)
|
||||
taxonomy.Taxa = append(taxonomy.Taxa, taxa)
|
||||
}
|
||||
sarif.Runs[0].Taxonomies = append(sarif.Runs[0].Taxonomies, taxonomy)
|
||||
|
||||
return &sarif
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,20 @@ import (
|
||||
func TestCreateSarifResultFile(t *testing.T) {
|
||||
alerts := []Vulnerability{
|
||||
{Name: "test1", Version: "1.2.3", VulnerabilityWithRemediation: VulnerabilityWithRemediation{VulnerabilityName: "CVE-45456543", Severity: "Critical", Description: "Some vulnerability that can be exploited by peeling the glue off.", BaseScore: 9.8, OverallScore: 10}},
|
||||
{Name: "test2", Version: "1.2.4", VulnerabilityWithRemediation: VulnerabilityWithRemediation{VulnerabilityName: "CVE-45456542", Severity: "Critical", Description: "Some other vulnerability that can be exploited by filling the glass.", BaseScore: 9, OverallScore: 9}},
|
||||
{Name: "test3", Version: "1.2.5", VulnerabilityWithRemediation: VulnerabilityWithRemediation{VulnerabilityName: "CVE-45456541", Severity: "Medium", Description: "Some vulnerability that can be exploited by turning it upside down.", BaseScore: 6.5, OverallScore: 7}},
|
||||
{Name: "test1", Version: "1.2.3", VulnerabilityWithRemediation: VulnerabilityWithRemediation{VulnerabilityName: "CVE-45456542", Severity: "Critical", Description: "Some other vulnerability that can be exploited by filling the glass.", BaseScore: 9, OverallScore: 9}},
|
||||
{Name: "test1", Version: "1.2.3", VulnerabilityWithRemediation: VulnerabilityWithRemediation{VulnerabilityName: "CVE-45456541", Severity: "Medium", Description: "Some vulnerability that can be exploited by turning it upside down.", BaseScore: 6.5, OverallScore: 7}},
|
||||
}
|
||||
vulns := Vulnerabilities{
|
||||
Items: alerts,
|
||||
}
|
||||
components := []Component{
|
||||
{Name: "test1", Version: "1.2.3", ComponentOriginName: "Maven"},
|
||||
}
|
||||
componentList := Components{
|
||||
Items: components,
|
||||
}
|
||||
|
||||
sarif := CreateSarifResultFile(&vulns)
|
||||
sarif := CreateSarifResultFile(&vulns, &componentList)
|
||||
|
||||
assert.Equal(t, "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json", sarif.Schema)
|
||||
assert.Equal(t, "2.1.0", sarif.Version)
|
||||
|
@ -90,6 +90,7 @@ type PartialFingerprints struct {
|
||||
FortifyInstanceID string `json:"fortifyInstanceID,omitempty"`
|
||||
CheckmarxSimilarityID string `json:"checkmarxSimilarityID,omitempty"`
|
||||
PrimaryLocationLineHash string `json:"primaryLocationLineHash,omitempty"`
|
||||
PackageURLPlusCVEHash string `json:"packageUrlPlusCveHash,omitempty"`
|
||||
}
|
||||
|
||||
// SarifProperties adding additional information/context to the finding
|
||||
|
@ -34,7 +34,7 @@ func (g *GitHub) UploadSingleReport(ctx context.Context, scanReport IssueDetail)
|
||||
title := scanReport.Title()
|
||||
markdownReport, _ := scanReport.ToMarkdown()
|
||||
|
||||
log.Entry().Debugf("Creating/updating GitHub issue with title %v in org %v and repo %v", title, g.Owner, g.Repository)
|
||||
log.Entry().Debugf("Creating/updating GitHub issue with title %v in org %v and repo %v", title, &g.Owner, &g.Repository)
|
||||
if err := g.createIssueOrUpdateIssueComment(ctx, title, string(markdownReport)); err != nil {
|
||||
return fmt.Errorf("failed to upload results for '%v' into GitHub issue: %w", title, err)
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ type VulnerabilityReport struct {
|
||||
DirectDependency string
|
||||
Footer string
|
||||
Group string
|
||||
PackageURL string
|
||||
PipelineName string
|
||||
PipelineLink string
|
||||
PublishDate string
|
||||
@ -63,6 +64,7 @@ Pipeline run: [{{ .PipelineName }}]({{ .PipelineLink }})
|
||||
{{if .ArtifactID}}**ArtifactId:** {{ .ArtifactID }}{{- end}}
|
||||
{{if .Group}}**Group:** {{ .Group }}{{- end}}
|
||||
{{if .Version}}**Version:** {{ .Version }}{{- end}}
|
||||
{{if .PackageURL}}**Package URL:** {{ .PackageURL }}{{- end}}
|
||||
{{if .PublishDate}}**Publishing date:** {{.PublishDate }}{{- end}}
|
||||
|
||||
## Description
|
||||
|
@ -35,6 +35,7 @@ func TestVulToMarkdown(t *testing.T) {
|
||||
Score: 7.8,
|
||||
Severity: "high",
|
||||
Version: "1.2.3",
|
||||
PackageURL: "pkg:generic/the.group/theArtifact@1.2.3",
|
||||
VulnerabilityLink: "https://the.link/to/the/vulnerability",
|
||||
VulnerabilityName: "CVE-Test-001",
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ Pipeline run: [thePipelineName](https://the.link.to.the.pipeline)
|
||||
**ArtifactId:** theArtifact
|
||||
**Group:** the.group
|
||||
**Version:** 1.2.3
|
||||
**Package URL:** pkg:generic/the.group/theArtifact@1.2.3
|
||||
**Publishing date:** 2022-06-30
|
||||
|
||||
## Description
|
||||
|
@ -3,9 +3,11 @@ package whitesource
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -189,17 +191,15 @@ func CreateSarifResultFile(scan *Scan, alerts *[]Alert) *format.SARIF {
|
||||
tool.Driver = *new(format.Driver)
|
||||
tool.Driver.Name = scan.AgentName
|
||||
tool.Driver.Version = scan.AgentVersion
|
||||
tool.Driver.InformationUri = "https://whitesource.atlassian.net/wiki/spaces/WD/pages/804814917/Unified+Agent+Overview"
|
||||
tool.Driver.InformationUri = "https://mend.io"
|
||||
|
||||
// Handle results/vulnerabilities
|
||||
for i := 0; i < len(*alerts); i++ {
|
||||
alert := (*alerts)[i]
|
||||
collectedRules := []string{}
|
||||
for _, alert := range *alerts {
|
||||
result := *new(format.Results)
|
||||
id := fmt.Sprintf("%v/%v/%v", alert.Type, alert.Vulnerability.Name, alert.Library.ArtifactID)
|
||||
log.Entry().Debugf("Transforming alert %v into SARIF format", id)
|
||||
result.RuleID = id
|
||||
result.Level = transformToLevel(alert.Vulnerability.Severity, alert.Vulnerability.CVSS3Severity)
|
||||
result.RuleIndex = i //Seems very abstract
|
||||
ruleId := alert.Vulnerability.Name
|
||||
log.Entry().Debugf("Transforming alert %v into SARIF format", ruleId)
|
||||
result.RuleID = ruleId
|
||||
result.Message = new(format.Message)
|
||||
result.Message.Text = alert.Vulnerability.Description
|
||||
artLoc := new(format.ArtifactLocation)
|
||||
@ -208,65 +208,88 @@ func CreateSarifResultFile(scan *Scan, alerts *[]Alert) *format.SARIF {
|
||||
result.AnalysisTarget = artLoc
|
||||
location := format.Location{PhysicalLocation: format.PhysicalLocation{ArtifactLocation: format.ArtifactLocation{URI: alert.Library.Filename}}}
|
||||
result.Locations = append(result.Locations, location)
|
||||
//TODO add audit and tool related information, maybe fortifyCategory needs to become more general
|
||||
//result.Properties = new(format.SarifProperties)
|
||||
//result.Properties.ToolSeverity
|
||||
//result.Properties.ToolAuditMessage
|
||||
|
||||
sarifRule := *new(format.SarifRule)
|
||||
sarifRule.ID = id
|
||||
sd := new(format.Message)
|
||||
sd.Text = fmt.Sprintf("%v Package %v", alert.Vulnerability.Name, alert.Library.ArtifactID)
|
||||
sarifRule.ShortDescription = sd
|
||||
fd := new(format.Message)
|
||||
fd.Text = alert.Vulnerability.Description
|
||||
sarifRule.FullDescription = fd
|
||||
defaultConfig := new(format.DefaultConfiguration)
|
||||
defaultConfig.Level = transformToLevel(alert.Vulnerability.Severity, alert.Vulnerability.CVSS3Severity)
|
||||
sarifRule.DefaultConfiguration = defaultConfig
|
||||
sarifRule.HelpURI = alert.Vulnerability.URL
|
||||
markdown, _ := alert.ToMarkdown()
|
||||
sarifRule.Help = new(format.Help)
|
||||
sarifRule.Help.Text = alert.ToTxt()
|
||||
sarifRule.Help.Markdown = string(markdown)
|
||||
|
||||
ruleProp := *new(format.SarifRuleProperties)
|
||||
ruleProp.Tags = append(ruleProp.Tags, alert.Type)
|
||||
ruleProp.Tags = append(ruleProp.Tags, alert.Description)
|
||||
ruleProp.Tags = append(ruleProp.Tags, alert.Library.ArtifactID)
|
||||
ruleProp.Precision = "very-high"
|
||||
sarifRule.Properties = &ruleProp
|
||||
|
||||
//Finalize: append the result and the rule
|
||||
partialFingerprints := new(format.PartialFingerprints)
|
||||
partialFingerprints.PackageURLPlusCVEHash = base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%v+%v", alert.Library.ToPackageUrl().ToString(), alert.Vulnerability.Name)))
|
||||
result.PartialFingerprints = *partialFingerprints
|
||||
//append the result
|
||||
sarif.Runs[0].Results = append(sarif.Runs[0].Results, result)
|
||||
tool.Driver.Rules = append(tool.Driver.Rules, sarifRule)
|
||||
|
||||
// only create rule on new CVE
|
||||
if !piperutils.ContainsString(collectedRules, ruleId) {
|
||||
collectedRules = append(collectedRules, ruleId)
|
||||
|
||||
sarifRule := *new(format.SarifRule)
|
||||
sarifRule.ID = ruleId
|
||||
sarifRule.Name = alert.Vulnerability.Name
|
||||
sd := new(format.Message)
|
||||
sd.Text = fmt.Sprintf("%v Package %v", alert.Vulnerability.Name, alert.Library.ArtifactID)
|
||||
sarifRule.ShortDescription = sd
|
||||
fd := new(format.Message)
|
||||
fd.Text = alert.Vulnerability.Description
|
||||
sarifRule.FullDescription = fd
|
||||
defaultConfig := new(format.DefaultConfiguration)
|
||||
defaultConfig.Level = transformToLevel(alert.Vulnerability.Severity, alert.Vulnerability.CVSS3Severity)
|
||||
sarifRule.DefaultConfiguration = defaultConfig
|
||||
sarifRule.HelpURI = alert.Vulnerability.URL
|
||||
markdown, _ := alert.ToMarkdown()
|
||||
sarifRule.Help = new(format.Help)
|
||||
sarifRule.Help.Text = alert.ToTxt()
|
||||
sarifRule.Help.Markdown = string(markdown)
|
||||
|
||||
ruleProp := *new(format.SarifRuleProperties)
|
||||
ruleProp.Tags = append(ruleProp.Tags, alert.Type)
|
||||
ruleProp.Tags = append(ruleProp.Tags, alert.Library.ToPackageUrl().ToString())
|
||||
ruleProp.Tags = append(ruleProp.Tags, alert.Vulnerability.URL)
|
||||
ruleProp.SecuritySeverity = fmt.Sprint(consolidateScores(alert.Vulnerability.Score, alert.Vulnerability.CVSS3Score))
|
||||
ruleProp.Precision = "very-high"
|
||||
|
||||
sarifRule.Properties = &ruleProp
|
||||
|
||||
// append the rule
|
||||
tool.Driver.Rules = append(tool.Driver.Rules, sarifRule)
|
||||
}
|
||||
}
|
||||
//Finalize: tool
|
||||
sarif.Runs[0].Tool = tool
|
||||
|
||||
// Threadflowlocations is no loger useful: voiding it will make for smaller reports
|
||||
sarif.Runs[0].ThreadFlowLocations = []format.Locations{}
|
||||
|
||||
// Add a conversion object to highlight this isn't native SARIF
|
||||
conversion := new(format.Conversion)
|
||||
conversion.Tool.Driver.Name = "Piper FPR to SARIF converter"
|
||||
conversion.Tool.Driver.InformationUri = "https://github.com/SAP/jenkins-library"
|
||||
conversion.Invocation.ExecutionSuccessful = true
|
||||
convInvocProp := new(format.InvocationProperties)
|
||||
convInvocProp.Platform = runtime.GOOS
|
||||
conversion.Invocation.Properties = convInvocProp
|
||||
sarif.Runs[0].Conversion = conversion
|
||||
|
||||
return &sarif
|
||||
}
|
||||
|
||||
func transformToLevel(cvss2severity, cvss3severity string) string {
|
||||
switch cvss3severity {
|
||||
cvssseverity := consolidateSeverities(cvss2severity, cvss3severity)
|
||||
switch cvssseverity {
|
||||
case "low":
|
||||
return "warning"
|
||||
case "medium":
|
||||
return "warning"
|
||||
case "high":
|
||||
return "error"
|
||||
}
|
||||
switch cvss2severity {
|
||||
case "low":
|
||||
return "warning"
|
||||
case "medium":
|
||||
return "warning"
|
||||
case "high":
|
||||
case "critical":
|
||||
return "error"
|
||||
}
|
||||
return "none"
|
||||
}
|
||||
|
||||
func consolidateSeverities(cvss2severity, cvss3severity string) string {
|
||||
if len(cvss3severity) > 0 {
|
||||
return cvss3severity
|
||||
}
|
||||
return cvss2severity
|
||||
}
|
||||
|
||||
// WriteSarifFile write a JSON sarif format file for upload into e.g. GCP
|
||||
func WriteSarifFile(sarif *format.SARIF, utils piperutils.FileUtils) ([]piperutils.Path, error) {
|
||||
reportPaths := []piperutils.Path{}
|
||||
@ -333,18 +356,23 @@ func CreateCycloneSBOM(scan *Scan, libraries *[]Library, alerts *[]Alert) ([]byt
|
||||
|
||||
// TODO check whether we can identify library vs. application
|
||||
Component: &cdx.Component{
|
||||
BOMRef: ppurl.ToString(),
|
||||
Type: cdx.ComponentTypeLibrary,
|
||||
Name: scan.Coordinates.ArtifactID,
|
||||
Group: scan.Coordinates.GroupID,
|
||||
Version: scan.Coordinates.Version,
|
||||
BOMRef: ppurl.ToString(),
|
||||
Type: cdx.ComponentTypeLibrary,
|
||||
Name: scan.Coordinates.ArtifactID,
|
||||
Group: scan.Coordinates.GroupID,
|
||||
Version: scan.Coordinates.Version,
|
||||
PackageURL: ppurl.ToString(),
|
||||
},
|
||||
// Use properties to include an internal identifier for this BOM
|
||||
// https://cyclonedx.org/use-cases/#properties--name-value-store
|
||||
Properties: &[]cdx.Property{
|
||||
{
|
||||
Name: "internal:bom-identifier",
|
||||
Value: strings.Join(scan.ScannedProjectNames(), ", "),
|
||||
Name: "internal:ws-product-identifier",
|
||||
Value: scan.ProductToken,
|
||||
},
|
||||
{
|
||||
Name: "internal:ws-project-identifier",
|
||||
Value: strings.Join(scan.ScannedProjectTokens(), ", "),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -379,6 +407,16 @@ func CreateCycloneSBOM(scan *Scan, libraries *[]Library, alerts *[]Alert) ([]byt
|
||||
// Define the vulnerabilities in VEX
|
||||
// https://cyclonedx.org/use-cases/#vulnerability-exploitability
|
||||
purl := alert.Library.ToPackageUrl()
|
||||
advisories := []cdx.Advisory{}
|
||||
for _, fix := range alert.Vulnerability.AllFixes {
|
||||
advisory := cdx.Advisory{
|
||||
Title: fix.Message,
|
||||
URL: alert.Vulnerability.TopFix.URL,
|
||||
}
|
||||
advisories = append(advisories, advisory)
|
||||
}
|
||||
cvss3Score := alert.Vulnerability.CVSS3Score
|
||||
cvssScore := alert.Vulnerability.Score
|
||||
vuln := cdx.Vulnerability{
|
||||
BOMRef: purl.ToString(),
|
||||
ID: alert.Vulnerability.Name,
|
||||
@ -397,26 +435,21 @@ func CreateCycloneSBOM(scan *Scan, libraries *[]Library, alerts *[]Alert) ([]byt
|
||||
},
|
||||
},
|
||||
Recommendation: alert.Vulnerability.FixResolutionText,
|
||||
Detail: alert.Vulnerability.Description,
|
||||
Detail: alert.Vulnerability.URL,
|
||||
Ratings: &[]cdx.VulnerabilityRating{
|
||||
{
|
||||
Score: &alert.Vulnerability.CVSS3Score,
|
||||
Severity: transformToCdxSeverity(alert.Vulnerability.Severity),
|
||||
Score: &cvss3Score,
|
||||
Severity: transformToCdxSeverity(alert.Vulnerability.CVSS3Severity),
|
||||
Method: cdx.ScoringMethodCVSSv3,
|
||||
},
|
||||
{
|
||||
Score: &alert.Vulnerability.Score,
|
||||
Score: &cvssScore,
|
||||
Severity: transformToCdxSeverity(alert.Vulnerability.Severity),
|
||||
Method: cdx.ScoringMethodCVSSv2,
|
||||
},
|
||||
},
|
||||
Advisories: &[]cdx.Advisory{
|
||||
{
|
||||
Title: alert.Vulnerability.TopFix.Vulnerability,
|
||||
URL: alert.Vulnerability.TopFix.Origin,
|
||||
},
|
||||
},
|
||||
Description: alert.Description,
|
||||
Advisories: &advisories,
|
||||
Description: alert.Vulnerability.Description,
|
||||
Created: alert.CreationDate,
|
||||
Published: alert.Vulnerability.PublishDate,
|
||||
Updated: alert.ModifiedDate,
|
||||
|
@ -108,21 +108,29 @@ func TestCreateCycloneSBOM(t *testing.T) {
|
||||
scan := &Scan{
|
||||
AgentName: "Mend Unified Agent",
|
||||
AgentVersion: "3.3.3",
|
||||
scannedProjects: map[string]Project{"testProject": {Name: "testProject", Token: "projectToken-567"}},
|
||||
AggregateProjectName: config.ProjectName,
|
||||
BuildTool: "maven",
|
||||
ProductVersion: config.ProductVersion,
|
||||
ProductToken: "productToken-123",
|
||||
Coordinates: versioning.Coordinates{GroupID: "com.sap", ArtifactID: "myproduct", Version: "1.3.4"},
|
||||
}
|
||||
scan.AppendScannedProject("testProject")
|
||||
|
||||
lib3 := Library{KeyID: 43, Name: "commons-lang", GroupID: "apache-commons", ArtifactID: "commons-lang", Version: "2.4.30", LibType: "Java", Filename: "vul2"}
|
||||
lib4 := Library{KeyID: 45, Name: "commons-lang", GroupID: "apache-commons", ArtifactID: "commons-lang", Version: "3.15", LibType: "Java", Filename: "novul"}
|
||||
lib1 := Library{KeyID: 42, Name: "log4j", GroupID: "apache-logging", ArtifactID: "log4j", Version: "1.14", LibType: "Java", Filename: "vul1", Dependencies: []Library{lib3}}
|
||||
lib2 := Library{KeyID: 44, Name: "log4j", GroupID: "apache-logging", ArtifactID: "log4j", Version: "3.25", LibType: "Java", Filename: "vul3", Dependencies: []Library{lib4}}
|
||||
|
||||
alerts := []Alert{
|
||||
{Library: Library{KeyID: 42, Name: "log4j", GroupID: "apache-logging", ArtifactID: "log4j", Version: "1.14", LibType: "MAVEN_ARTIFACT", Filename: "vul1"}, Vulnerability: Vulnerability{Name: "CVE-2022-001", CVSS3Score: 7.0, Score: 6, Severity: "medium", PublishDate: "01.01.2022"}},
|
||||
{Library: Library{KeyID: 43, Name: "commons-lang", GroupID: "apache-commons", ArtifactID: "commons-lang", Version: "2.4.30", LibType: "MAVEN_ARTIFACT", Filename: "vul2"}, Vulnerability: Vulnerability{Name: "CVE-2022-002", CVSS3Score: 8.0, Severity: "high", PublishDate: "02.01.2022", TopFix: Fix{Message: "this is the top fix"}}},
|
||||
{Library: Library{KeyID: 42, Name: "log4j", GroupID: "apache-logging", ArtifactID: "log4j", Version: "3.25", LibType: "MAVEN_ARTIFACT", Filename: "vul3"}, Vulnerability: Vulnerability{Name: "CVE-2022-003", Score: 6, Severity: "medium", PublishDate: "03.01.2022"}},
|
||||
{Library: lib1, Vulnerability: Vulnerability{Name: "CVE-2022-001", CVSS3Score: 7, Score: 6, CVSS3Severity: "high", Severity: "medium", PublishDate: "01.01.2022"}},
|
||||
{Library: lib3, Vulnerability: Vulnerability{Name: "CVE-2022-002", CVSS3Score: 8, CVSS3Severity: "high", PublishDate: "02.01.2022", TopFix: Fix{Message: "this is the top fix"}}},
|
||||
{Library: lib2, Vulnerability: Vulnerability{Name: "CVE-2022-003", Score: 6, Severity: "medium", PublishDate: "03.01.2022"}},
|
||||
}
|
||||
|
||||
libraries := []Library{
|
||||
{KeyID: 42, Name: "log4j", GroupID: "apache-logging", ArtifactID: "log4j", Version: "1.14", LibType: "MAVEN_ARTIFACT", Filename: "vul1", Dependencies: []Library{{KeyID: 43, Name: "commons-lang", GroupID: "apache-commons", ArtifactID: "commons-lang", Version: "2.4.30", LibType: "MAVEN_ARTIFACT", Filename: "vul2"}}},
|
||||
{KeyID: 44, Name: "log4j", GroupID: "apache-logging", ArtifactID: "log4j", Version: "3.25", LibType: "MAVEN_ARTIFACT", Filename: "vul3", Dependencies: []Library{{KeyID: 45, Name: "commons-lang", GroupID: "apache-commons", ArtifactID: "commons-lang", Version: "3.15", LibType: "MAVEN_ARTIFACT", Filename: "vul2"}}},
|
||||
lib1,
|
||||
lib2,
|
||||
}
|
||||
|
||||
contents, err := CreateCycloneSBOM(scan, &libraries, &alerts)
|
||||
@ -160,9 +168,9 @@ func TestCreateSarifResultFile(t *testing.T) {
|
||||
scan.AgentName = "Some test agent"
|
||||
scan.AgentVersion = "1.2.6"
|
||||
alerts := []Alert{
|
||||
{Library: Library{Filename: "vul1", ArtifactID: "org.some.lib"}, Vulnerability: Vulnerability{CVSS3Score: 7.0, Score: 6}},
|
||||
{Library: Library{Filename: "vul2", ArtifactID: "org.some.lib"}, Vulnerability: Vulnerability{CVSS3Score: 8.0, TopFix: Fix{Message: "this is the top fix"}}},
|
||||
{Library: Library{Filename: "vul3", ArtifactID: "org.some.lib2"}, Vulnerability: Vulnerability{Score: 6}},
|
||||
{Library: Library{Filename: "vul1", ArtifactID: "org.some.lib"}, Vulnerability: Vulnerability{Name: "CVE-2022-001", CVSS3Score: 7.0, Score: 6}},
|
||||
{Library: Library{Filename: "vul2", ArtifactID: "org.some.lib"}, Vulnerability: Vulnerability{Name: "CVE-2022-002", CVSS3Score: 8.0, TopFix: Fix{Message: "this is the top fix"}}},
|
||||
{Library: Library{Filename: "vul3", ArtifactID: "org.some.lib2"}, Vulnerability: Vulnerability{Name: "CVE-2022-003", Score: 6}},
|
||||
}
|
||||
|
||||
sarif := CreateSarifResultFile(scan, &alerts)
|
||||
|
@ -18,6 +18,7 @@ type Scan struct {
|
||||
AggregateProjectName string
|
||||
// ProductVersion is the global version that is used across all Projects (modules) during the scan.
|
||||
BuildTool string
|
||||
ProductToken string
|
||||
ProductVersion string
|
||||
scannedProjects map[string]Project
|
||||
scanTimes map[string]time.Time
|
||||
@ -99,6 +100,20 @@ func (s *Scan) ScannedProjectNames() []string {
|
||||
return projectNames
|
||||
}
|
||||
|
||||
// ScannedProjectTokens returns a sorted list of all scanned project's tokens
|
||||
func (s *Scan) ScannedProjectTokens() []string {
|
||||
projectTokens := []string{}
|
||||
for _, project := range s.ScannedProjects() {
|
||||
if len(project.Token) > 0 {
|
||||
projectTokens = append(projectTokens, project.Token)
|
||||
}
|
||||
}
|
||||
// Sorting helps the list become stable across pipeline runs (and in the unit tests),
|
||||
// as the order in which we travers map keys is not deterministic.
|
||||
sort.Strings(projectTokens)
|
||||
return projectTokens
|
||||
}
|
||||
|
||||
// ScanTime returns the time at which the respective WhiteSource Project was scanned, or the the
|
||||
// zero value of time.Time, if AppendScannedProject() was not called with that name.
|
||||
func (s *Scan) ScanTime(projectName string) time.Time {
|
||||
|
34
pkg/whitesource/testdata/sbom.golden
vendored
34
pkg/whitesource/testdata/sbom.golden
vendored
@ -5,9 +5,11 @@
|
||||
<group>com.sap</group>
|
||||
<name>myproduct</name>
|
||||
<version>1.3.4</version>
|
||||
<purl>pkg:maven/com.sap/myproduct@1.3.4</purl>
|
||||
</component>
|
||||
<properties>
|
||||
<property name="internal:bom-identifier">testProject - 1</property>
|
||||
<property name="internal:ws-product-identifier">productToken-123</property>
|
||||
<property name="internal:ws-project-identifier">projectToken-567</property>
|
||||
</properties>
|
||||
</metadata>
|
||||
<components>
|
||||
@ -55,8 +57,8 @@
|
||||
<references></references>
|
||||
<ratings>
|
||||
<rating>
|
||||
<score>0</score>
|
||||
<severity>medium</severity>
|
||||
<score>7</score>
|
||||
<severity>high</severity>
|
||||
<method>CVSSv3</method>
|
||||
</rating>
|
||||
<rating>
|
||||
@ -65,11 +67,7 @@
|
||||
<method>CVSSv2</method>
|
||||
</rating>
|
||||
</ratings>
|
||||
<advisories>
|
||||
<advisory>
|
||||
<url></url>
|
||||
</advisory>
|
||||
</advisories>
|
||||
<advisories></advisories>
|
||||
<published>01.01.2022</published>
|
||||
<tools>
|
||||
<tool>
|
||||
@ -101,21 +99,17 @@
|
||||
<references></references>
|
||||
<ratings>
|
||||
<rating>
|
||||
<score>0</score>
|
||||
<score>8</score>
|
||||
<severity>high</severity>
|
||||
<method>CVSSv3</method>
|
||||
</rating>
|
||||
<rating>
|
||||
<score>6</score>
|
||||
<severity>high</severity>
|
||||
<score>0</score>
|
||||
<severity>none</severity>
|
||||
<method>CVSSv2</method>
|
||||
</rating>
|
||||
</ratings>
|
||||
<advisories>
|
||||
<advisory>
|
||||
<url></url>
|
||||
</advisory>
|
||||
</advisories>
|
||||
<advisories></advisories>
|
||||
<published>02.01.2022</published>
|
||||
<tools>
|
||||
<tool>
|
||||
@ -148,7 +142,7 @@
|
||||
<ratings>
|
||||
<rating>
|
||||
<score>0</score>
|
||||
<severity>medium</severity>
|
||||
<severity>none</severity>
|
||||
<method>CVSSv3</method>
|
||||
</rating>
|
||||
<rating>
|
||||
@ -157,11 +151,7 @@
|
||||
<method>CVSSv2</method>
|
||||
</rating>
|
||||
</ratings>
|
||||
<advisories>
|
||||
<advisory>
|
||||
<url></url>
|
||||
</advisory>
|
||||
</advisories>
|
||||
<advisories></advisories>
|
||||
<published>03.01.2022</published>
|
||||
<tools>
|
||||
<tool>
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/format"
|
||||
@ -88,41 +89,39 @@ func (a Alert) ContainedIn(assessments *[]format.Assessment) (bool, error) {
|
||||
}
|
||||
|
||||
func transformLibToPurlType(libType string) string {
|
||||
// TODO verify and complete, only maven is proven so far
|
||||
switch libType {
|
||||
case "MAVEN_ARTIFACT":
|
||||
log.Entry().Debugf("LibType reported as %v", libType)
|
||||
switch strings.ToLower(libType) {
|
||||
case "java":
|
||||
return packageurl.TypeMaven
|
||||
case "NODE_ARTIFACT":
|
||||
case "javascript/node.js":
|
||||
return packageurl.TypeNPM
|
||||
case "GOLANG_ARTIFACT":
|
||||
case "javascript/bower":
|
||||
return "bower"
|
||||
case "go":
|
||||
return packageurl.TypeGolang
|
||||
case "DOCKER_ARTIFACT":
|
||||
return packageurl.TypeGolang
|
||||
case "UNKNOWN_ARTIFACT":
|
||||
return packageurl.TypeGeneric
|
||||
case "python":
|
||||
return packageurl.TypePyPi
|
||||
case "debian":
|
||||
return packageurl.TypeDebian
|
||||
case "docker":
|
||||
return packageurl.TypeDocker
|
||||
case "source library":
|
||||
return "src"
|
||||
case ".net":
|
||||
return packageurl.TypeNuget
|
||||
}
|
||||
return packageurl.TypeGeneric
|
||||
}
|
||||
|
||||
func consolidate(cvss2severity, cvss3severity string, cvss2score, cvss3score float64) string {
|
||||
switch cvss3severity {
|
||||
cvssseverity := consolidateSeverities(cvss2severity, cvss3severity)
|
||||
switch cvssseverity {
|
||||
case "low":
|
||||
return "LOW"
|
||||
case "medium":
|
||||
return "MEDIUM"
|
||||
case "high":
|
||||
if cvss3score >= 9 {
|
||||
return "CRITICAL"
|
||||
}
|
||||
return "HIGH"
|
||||
}
|
||||
switch cvss2severity {
|
||||
case "low":
|
||||
return "LOW"
|
||||
case "medium":
|
||||
return "MEDIUM"
|
||||
case "high":
|
||||
if cvss2score >= 9 {
|
||||
if cvss3score >= 9 || cvss2score >= 9 {
|
||||
return "CRITICAL"
|
||||
}
|
||||
return "HIGH"
|
||||
@ -132,10 +131,7 @@ func consolidate(cvss2severity, cvss3severity string, cvss2score, cvss3score flo
|
||||
|
||||
// ToMarkdown returns the markdown representation of the contents
|
||||
func (a Alert) ToMarkdown() ([]byte, error) {
|
||||
score := a.Vulnerability.CVSS3Score
|
||||
if score == 0 {
|
||||
score = a.Vulnerability.Score
|
||||
}
|
||||
score := consolidateScores(a.Vulnerability.Score, a.Vulnerability.CVSS3Score)
|
||||
|
||||
vul := reporting.VulnerabilityReport{
|
||||
ArtifactID: a.Library.ArtifactID,
|
||||
@ -155,6 +151,7 @@ func (a Alert) ToMarkdown() ([]byte, error) {
|
||||
Score: score,
|
||||
Severity: consolidate(a.Vulnerability.Severity, a.Vulnerability.CVSS3Severity, a.Vulnerability.Score, a.Vulnerability.CVSS3Score),
|
||||
Version: a.Library.Version,
|
||||
PackageURL: a.Library.ToPackageUrl().ToString(),
|
||||
VulnerabilityLink: a.Vulnerability.URL,
|
||||
VulnerabilityName: a.Vulnerability.Name,
|
||||
}
|
||||
@ -164,25 +161,22 @@ func (a Alert) ToMarkdown() ([]byte, error) {
|
||||
|
||||
// ToTxt returns the textual representation of the contents
|
||||
func (a Alert) ToTxt() string {
|
||||
score := a.Vulnerability.CVSS3Score
|
||||
if score == 0 {
|
||||
score = a.Vulnerability.Score
|
||||
}
|
||||
score := consolidateScores(a.Vulnerability.Score, a.Vulnerability.CVSS3Score)
|
||||
return fmt.Sprintf(`Vulnerability %v
|
||||
Severity: %v
|
||||
Base (NVD) Score: %v
|
||||
Temporal Score: %v
|
||||
Package: %v
|
||||
Installed Version: %v
|
||||
Package URL: %v
|
||||
Description: %v
|
||||
Fix Resolution: %v
|
||||
Link: [%v](%v)`,
|
||||
a.Vulnerability.Name,
|
||||
a.Vulnerability.Severity,
|
||||
score,
|
||||
score,
|
||||
a.Library.ArtifactID,
|
||||
a.Library.Version,
|
||||
a.Library.ToPackageUrl().ToString(),
|
||||
a.Vulnerability.Description,
|
||||
a.Vulnerability.TopFix.FixResolution,
|
||||
a.Vulnerability.Name,
|
||||
@ -190,6 +184,14 @@ Link: [%v](%v)`,
|
||||
)
|
||||
}
|
||||
|
||||
func consolidateScores(cvss2score, cvss3score float64) float64 {
|
||||
score := cvss3score
|
||||
if score == 0 {
|
||||
score = cvss2score
|
||||
}
|
||||
return score
|
||||
}
|
||||
|
||||
// Library
|
||||
type Library struct {
|
||||
KeyUUID string `json:"keyUuid,omitempty"`
|
||||
|
Loading…
x
Reference in New Issue
Block a user