diff --git a/cmd/whitesourceExecuteScan.go b/cmd/whitesourceExecuteScan.go index 1f00d7d767..7a195f0d0a 100644 --- a/cmd/whitesourceExecuteScan.go +++ b/cmd/whitesourceExecuteScan.go @@ -524,13 +524,6 @@ func checkPolicyViolations(ctx context.Context, config *ScanOptions, scan *ws.Sc return piperutils.Path{}, fmt.Errorf("failed to retrieve project policy alerts from WhiteSource: %w", err) } - // TODO add ignored alerts to list of all alerts - _, err = sys.GetProjectIgnoredAlertsByType(project.Token, "REJECTED_BY_POLICY_RESOURCE") - if err != nil { - return piperutils.Path{}, fmt.Errorf("failed to retrieve project policy ignored alerts from WhiteSource: %w", err) - } - // alerts = append(alerts, ignoredAlerts...) - policyViolationCount += len(alerts) allAlerts = append(allAlerts, alerts...) } @@ -766,7 +759,11 @@ func reportGitHubIssuesAndCreateReports( reportPaths = append(reportPaths, paths...) - sarif := ws.CreateSarifResultFile(scan, &allAlerts) + combinedAlerts := make([]ws.Alert, 0, len(allAlerts)+len(allAssessedAlerts)) + combinedAlerts = append(combinedAlerts, allAlerts...) + combinedAlerts = append(combinedAlerts, allAssessedAlerts...) + + sarif := ws.CreateSarifResultFile(scan, &combinedAlerts) paths, err = ws.WriteSarifFile(sarif, utils) if err != nil { errorsOccured = append(errorsOccured, fmt.Sprint(err)) @@ -816,18 +813,15 @@ func readAssessmentsFromFile(assessmentFilePath string, utils whitesourceUtils) // checkSecurityViolations checks security violations and returns an error if the configured severity limit is crossed. Besides the potential error the list of unassessed and assessed alerts are being returned to allow generating reports and issues from the data. func checkProjectSecurityViolations(config *ScanOptions, cvssSeverityLimit float64, project ws.Project, sys whitesource, assessments *[]format.Assessment, influx *whitesourceExecuteScanInflux) (int, []ws.Alert, []ws.Alert, error) { // get project alerts (vulnerabilities) - assessedAlerts := []ws.Alert{} alerts, err := sys.GetProjectAlertsByType(project.Token, "SECURITY_VULNERABILITY") if err != nil { - return 0, alerts, assessedAlerts, fmt.Errorf("failed to retrieve project alerts from WhiteSource: %w", err) + return 0, alerts, []ws.Alert{}, fmt.Errorf("failed to retrieve project alerts from WhiteSource: %w", err) } - // TODO add ignored alerts to list of all alerts - _, err = sys.GetProjectIgnoredAlertsByType(project.Token, "SECURITY_VULNERABILITY") + assessedAlerts, err := sys.GetProjectIgnoredAlertsByType(project.Token, "SECURITY_VULNERABILITY") if err != nil { - return 0, alerts, assessedAlerts, fmt.Errorf("failed to retrieve project ignored alerts from WhiteSource: %w", err) + return 0, alerts, []ws.Alert{}, fmt.Errorf("failed to retrieve project ignored alerts from WhiteSource: %w", err) } - // alerts = append(alerts, ignoredAlerts...) // filter alerts related to existing assessments filteredAlerts := []ws.Alert{} @@ -915,13 +909,6 @@ func aggregateVersionWideVulnerabilities(config *ScanOptions, utils whitesourceU return errors.Wrapf(err, "failed to get project alerts by type") } - // TODO add ignored alerts to list of all alerts - _, err = sys.GetProjectIgnoredAlertsByType(project.Token, "SECURITY_VULNERABILITY") - if err != nil { - return errors.Wrapf(err, "failed to get project ignored alerts by type") - } - // alerts = append(alerts, ignoredAlerts...) - log.Entry().Infof("Found project: %s with %v vulnerabilities.", project.Name, len(alerts)) versionWideAlerts = append(versionWideAlerts, alerts...) } diff --git a/pkg/blackduck/blackduck.go b/pkg/blackduck/blackduck.go index 34bf0229b3..029a29362b 100644 --- a/pkg/blackduck/blackduck.go +++ b/pkg/blackduck/blackduck.go @@ -143,6 +143,7 @@ type VulnerabilityWithRemediation struct { ExploitabilitySubscore float32 `json:"exploitabilitySubscore,omitempty"` ImpactSubscore float32 `json:"impactSubscore,omitempty"` RelatedVulnerability string `json:"relatedVulnerability,omitempty"` + RemidiatedBy string `json:"remediationCreatedBy,omitempty"` } // Title returns the issue title representation of the contents diff --git a/pkg/blackduck/reporting.go b/pkg/blackduck/reporting.go index cc3aec3647..960c0c3357 100644 --- a/pkg/blackduck/reporting.go +++ b/pkg/blackduck/reporting.go @@ -6,6 +6,7 @@ import ( "fmt" "path/filepath" "runtime" + "strings" "github.com/SAP/jenkins-library/pkg/format" "github.com/SAP/jenkins-library/pkg/log" @@ -70,12 +71,17 @@ func CreateSarifResultFile(vulns *Vulnerabilities, projectName, projectVersion, PackageURLPlusCVEHash: base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%v+%v", v.Component.ToPackageUrl().ToString(), v.CweID))), }, Properties: &format.SarifProperties{ - Audited: isAudited, - ToolSeverity: v.Severity, - ToolSeverityIndex: severityIndex[v.Severity], - ToolAuditMessage: v.VulnerabilityWithRemediation.RemediationComment, - ToolState: v.RemediationStatus, - UnifiedAuditState: unifiedStatusValue, + Audited: isAudited, + ToolSeverity: v.Severity, + ToolSeverityIndex: severityIndex[v.Severity], + ToolState: v.RemediationStatus, + ToolAuditMessage: v.VulnerabilityWithRemediation.RemediationComment, + UnifiedAuditState: unifiedStatusValue, + UnifiedSeverity: strings.ToLower(v.Severity), + UnifiedCriticality: v.BaseScore, + UnifiedAuditUser: v.VulnerabilityWithRemediation.RemidiatedBy, + AuditRequirement: format.AUDIT_REQUIREMENT_GROUP_1_DESC, + AuditRequirementIndex: format.AUDIT_REQUIREMENT_GROUP_1_INDEX, }, } diff --git a/pkg/blackduck/reporting_test.go b/pkg/blackduck/reporting_test.go index 82018853d1..e0c86bc35e 100644 --- a/pkg/blackduck/reporting_test.go +++ b/pkg/blackduck/reporting_test.go @@ -32,6 +32,7 @@ func TestCreateSarifResultFile(t *testing.T) { BaseScore: 9.8, OverallScore: 10, RemediationStatus: "IGNORED", RemediationComment: "CWE-45456543 Auto-remediated: CWE-45456543 is related to CVE-1, but the CWE team has determined that this component version is not affected.", + RemidiatedBy: "technical_user", }, }, { @@ -60,6 +61,7 @@ func TestCreateSarifResultFile(t *testing.T) { Description: "Some vulnerability that can be exploited by turning it upside down.", BaseScore: 6.5, OverallScore: 7, + RemediationStatus: "IGNORED", }, }, { @@ -110,6 +112,13 @@ func TestCreateSarifResultFile(t *testing.T) { // Test correctness of audit information assert.Equal(t, true, sarif.Runs[0].Results[0].Properties.Audited) assert.Equal(t, "IGNORED", sarif.Runs[0].Results[0].Properties.ToolState) + assert.Equal(t, alerts[0].BaseScore, sarif.Runs[0].Results[0].Properties.UnifiedCriticality) + assert.Equal(t, "critical", sarif.Runs[0].Results[0].Properties.UnifiedSeverity) + assert.Equal(t, "new", sarif.Runs[0].Results[1].Properties.UnifiedAuditState) + assert.Equal(t, "notRelevant", sarif.Runs[0].Results[0].Properties.UnifiedAuditState) + assert.Equal(t, "technical_user", sarif.Runs[0].Results[0].Properties.UnifiedAuditUser) + assert.Equal(t, format.AUDIT_REQUIREMENT_GROUP_1_DESC, sarif.Runs[0].Results[0].Properties.AuditRequirement) + assert.Equal(t, format.AUDIT_REQUIREMENT_GROUP_1_INDEX, sarif.Runs[0].Results[0].Properties.AuditRequirementIndex) assert.Equal(t, "CWE-45456543 Auto-remediated: CWE-45456543 is related to CVE-1, but the CWE team has determined that this component version is not affected.", sarif.Runs[0].Results[0].Properties.ToolAuditMessage, diff --git a/pkg/format/sarif.go b/pkg/format/sarif.go index bedae05d47..7eab9f1fa6 100644 --- a/pkg/format/sarif.go +++ b/pkg/format/sarif.go @@ -96,17 +96,20 @@ type PartialFingerprints struct { // SarifProperties adding additional information/context to the finding type SarifProperties struct { // common - RuleGUID string `json:"ruleGUID,omitempty"` - InstanceID string `json:"instanceID,omitempty"` - Audited bool `json:"audited"` - ToolSeverity string `json:"toolSeverity"` - ToolSeverityIndex int `json:"toolSeverityIndex"` - ToolState string `json:"toolState"` - ToolStateIndex int `json:"toolStateIndex"` - ToolAuditMessage string `json:"toolAuditMessage"` - UnifiedAuditState string `json:"unifiedAuditState"` - AuditRequirement string `json:"auditRequirement"` - AuditRequirementIndex int `json:"auditRequirementIndex"` + RuleGUID string `json:"ruleGUID,omitempty"` + InstanceID string `json:"instanceID,omitempty"` + Audited bool `json:"audited"` + ToolSeverity string `json:"toolSeverity"` + ToolSeverityIndex int `json:"toolSeverityIndex"` + ToolState string `json:"toolState"` + ToolStateIndex int `json:"toolStateIndex"` + ToolAuditMessage string `json:"toolAuditMessage"` + UnifiedAuditState string `json:"unifiedAuditState,omitempty"` + UnifiedSeverity string `json:"unifiedSeverity,omitempty"` + UnifiedCriticality float32 `json:"unifiedCriticality,omitempty"` + UnifiedAuditUser string `json:"unifiedAuditUser,omitempty"` + AuditRequirement string `json:"auditRequirement"` + AuditRequirementIndex int `json:"auditRequirementIndex"` // specific InstanceSeverity string `json:"instanceSeverity"` diff --git a/pkg/whitesource/reporting.go b/pkg/whitesource/reporting.go index b1c7cc8555..56e5cefa0d 100644 --- a/pkg/whitesource/reporting.go +++ b/pkg/whitesource/reporting.go @@ -40,7 +40,7 @@ func CreateCustomVulnerabilityReport(productName string, scan *Scan, alerts *[]A {Description: "Filtered project names", Details: strings.Join(projectNames, ", ")}, }, Overview: []reporting.OverviewRow{ - {Description: "Total number of vulnerabilities", Details: fmt.Sprint(len((*alerts)))}, + {Description: "Total number of vulnerabilities", Details: fmt.Sprint(len(*alerts))}, {Description: "Total number of high/critical vulnerabilities with CVSS score >= 7.0", Details: fmt.Sprint(severe)}, }, SuccessfulScan: severe == 0, @@ -295,9 +295,13 @@ func getAuditInformation(alert Alert) *format.SarifProperties { } return &format.SarifProperties{ - Audited: isAudited, - ToolAuditMessage: auditMessage, - UnifiedAuditState: unifiedAuditState, + Audited: isAudited, + ToolAuditMessage: auditMessage, + UnifiedAuditState: unifiedAuditState, + AuditRequirement: format.AUDIT_REQUIREMENT_GROUP_1_DESC, + AuditRequirementIndex: format.AUDIT_REQUIREMENT_GROUP_1_INDEX, + UnifiedSeverity: alert.Vulnerability.CVSS3Severity, + UnifiedCriticality: float32(alert.Vulnerability.CVSS3Score), } } diff --git a/pkg/whitesource/reporting_test.go b/pkg/whitesource/reporting_test.go index c859ab8bac..94abeb6d9d 100644 --- a/pkg/whitesource/reporting_test.go +++ b/pkg/whitesource/reporting_test.go @@ -349,9 +349,11 @@ func TestGetAuditInformation(t *testing.T) { Status: "OPEN", }, expected: &format.SarifProperties{ - Audited: false, - ToolAuditMessage: "", - UnifiedAuditState: "new", + Audited: false, + ToolAuditMessage: "", + UnifiedAuditState: "new", + AuditRequirement: format.AUDIT_REQUIREMENT_GROUP_1_DESC, + AuditRequirementIndex: format.AUDIT_REQUIREMENT_GROUP_1_INDEX, }, }, { @@ -359,11 +361,19 @@ func TestGetAuditInformation(t *testing.T) { alert: Alert{ Status: "IGNORE", Comments: "Not relevant alert", + Vulnerability: Vulnerability{ + CVSS3Score: 9.3, + CVSS3Severity: "critical", + }, }, expected: &format.SarifProperties{ - Audited: true, - ToolAuditMessage: "Not relevant alert", - UnifiedAuditState: "notRelevant", + Audited: true, + ToolAuditMessage: "Not relevant alert", + UnifiedAuditState: "notRelevant", + UnifiedSeverity: "critical", + UnifiedCriticality: 9.3, + AuditRequirement: format.AUDIT_REQUIREMENT_GROUP_1_DESC, + AuditRequirementIndex: format.AUDIT_REQUIREMENT_GROUP_1_INDEX, }, }, { @@ -373,13 +383,15 @@ func TestGetAuditInformation(t *testing.T) { Comments: "Some comment", }, expected: &format.SarifProperties{ - Audited: false, - ToolAuditMessage: "", - UnifiedAuditState: "new", + Audited: false, + ToolAuditMessage: "", + UnifiedAuditState: "new", + AuditRequirement: format.AUDIT_REQUIREMENT_GROUP_1_DESC, + AuditRequirementIndex: format.AUDIT_REQUIREMENT_GROUP_1_INDEX, }, }, { - name: "Audited alert", + name: "Not audited alert", alert: Alert{ Assessment: &format.Assessment{ Status: format.NotRelevant, @@ -389,16 +401,18 @@ func TestGetAuditInformation(t *testing.T) { Comments: "New alert", }, expected: &format.SarifProperties{ - Audited: true, - ToolAuditMessage: string(format.FixedByDevTeam), - UnifiedAuditState: "notRelevant", + Audited: true, + ToolAuditMessage: string(format.FixedByDevTeam), + UnifiedAuditState: "notRelevant", + AuditRequirement: format.AUDIT_REQUIREMENT_GROUP_1_DESC, + AuditRequirementIndex: format.AUDIT_REQUIREMENT_GROUP_1_INDEX, }, }, } for _, test := range tt { t.Run(test.name, func(t *testing.T) { - assert.Equal(t, getAuditInformation(test.alert), test.expected) + assert.Equal(t, test.expected, getAuditInformation(test.alert)) }) } }