You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	Fix issue with not generating sarif file when projectName was specified (#4199)
* Fixed bug in generating sarif file in whitesource step --------- Co-authored-by: sumeet patil <sumeet.patil@sap.com>
This commit is contained in:
		| @@ -587,100 +587,177 @@ func checkPolicyViolations(ctx context.Context, config *ScanOptions, scan *ws.Sc | ||||
| } | ||||
|  | ||||
| func checkSecurityViolations(ctx context.Context, config *ScanOptions, scan *ws.Scan, sys whitesource, utils whitesourceUtils, influx *whitesourceExecuteScanInflux) ([]piperutils.Path, error) { | ||||
| 	var reportPaths []piperutils.Path | ||||
| 	// Check for security vulnerabilities and fail the build if cvssSeverityLimit threshold is crossed | ||||
| 	// convert config.CvssSeverityLimit to float64 | ||||
| 	cvssSeverityLimit, err := strconv.ParseFloat(config.CvssSeverityLimit, 64) | ||||
| 	if err != nil { | ||||
| 		log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 		return reportPaths, fmt.Errorf("failed to parse parameter cvssSeverityLimit (%s) "+ | ||||
| 		return []piperutils.Path{}, fmt.Errorf("failed to parse parameter cvssSeverityLimit (%s) "+ | ||||
| 			"as floating point number: %w", config.CvssSeverityLimit, err) | ||||
| 	} | ||||
|  | ||||
| 	// inhale assessments from file system | ||||
| 	assessments := readAssessmentsFromFile(config.AssessmentFile, utils) | ||||
|  | ||||
| 	vulnerabilitiesCount := 0 | ||||
| 	var allOccurredErrors []string | ||||
| 	allAlerts := []ws.Alert{} | ||||
| 	allAssessedAlerts := []ws.Alert{} | ||||
| 	allLibraries := []ws.Library{} | ||||
|  | ||||
| 	if config.ProjectToken != "" { | ||||
| 		project := ws.Project{Name: config.ProjectName, Token: config.ProjectToken} | ||||
| 		// ToDo: see if HTML report generation is really required here | ||||
| 		// we anyway need to do some refactoring here since config.ProjectToken != "" essentially indicates an aggregated project | ||||
| 		if _, _, _, err := checkProjectSecurityViolations(config, cvssSeverityLimit, project, sys, assessments, influx); err != nil { | ||||
| 			return reportPaths, err | ||||
| 		} | ||||
|  | ||||
| 		vulnerabilitiesCount, allAlerts, allAssessedAlerts, allLibraries, allOccurredErrors = collectVulnsAndLibsForProject( | ||||
| 			config, | ||||
| 			cvssSeverityLimit, | ||||
| 			project, | ||||
| 			sys, | ||||
| 			assessments, | ||||
| 			influx, | ||||
| 		) | ||||
|  | ||||
| 		log.Entry().Debugf("Collected %v libraries for project %v", len(allLibraries), project.Name) | ||||
|  | ||||
| 	} else { | ||||
| 		vulnerabilitiesCount := 0 | ||||
| 		var errorsOccured []string | ||||
| 		allAlerts := []ws.Alert{} | ||||
| 		allAssessedAlerts := []ws.Alert{} | ||||
| 		allLibraries := []ws.Library{} | ||||
| 		for _, project := range scan.ScannedProjects() { | ||||
| 			// collect errors and aggregate vulnerabilities from all projects | ||||
| 			vulCount, alerts, assessedAlerts, err := checkProjectSecurityViolations(config, cvssSeverityLimit, project, sys, assessments, influx) | ||||
| 			if err != nil { | ||||
| 				errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 			vulCount, alerts, assessedAlerts, libraries, occurredErrors := collectVulnsAndLibsForProject( | ||||
| 				config, | ||||
| 				cvssSeverityLimit, | ||||
| 				project, | ||||
| 				sys, | ||||
| 				assessments, | ||||
| 				influx, | ||||
| 			) | ||||
| 			if len(occurredErrors) != 0 { | ||||
| 				allOccurredErrors = append(allOccurredErrors, occurredErrors...) | ||||
| 			} | ||||
|  | ||||
| 			allAlerts = append(allAlerts, alerts...) | ||||
| 			allAssessedAlerts = append(allAssessedAlerts, assessedAlerts...) | ||||
| 			vulnerabilitiesCount += vulCount | ||||
|  | ||||
| 			// collect all libraries detected in all related projects and errors | ||||
| 			libraries, err := sys.GetProjectHierarchy(project.Token, true) | ||||
| 			if err != nil { | ||||
| 				errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 			} | ||||
| 			log.Entry().Debugf("Collected %v libraries for project %v", len(libraries), project.Name) | ||||
| 			allLibraries = append(allLibraries, libraries...) | ||||
| 		} | ||||
| 		log.Entry().Debugf("Aggregated %v alerts for scanned projects", len(allAlerts)) | ||||
| 	} | ||||
|  | ||||
| 		if config.CreateResultIssue && vulnerabilitiesCount > 0 && len(config.GithubToken) > 0 && len(config.GithubAPIURL) > 0 && len(config.Owner) > 0 && len(config.Repository) > 0 { | ||||
| 			log.Entry().Debugf("Creating result issues for %v alert(s)", vulnerabilitiesCount) | ||||
| 			issueDetails := make([]reporting.IssueDetail, len(allAlerts)) | ||||
| 			piperutils.CopyAtoB(allAlerts, issueDetails) | ||||
| 			gh := reporting.GitHub{ | ||||
| 				Owner:         &config.Owner, | ||||
| 				Repository:    &config.Repository, | ||||
| 				Assignees:     &config.Assignees, | ||||
| 				IssueService:  utils.GetIssueService(), | ||||
| 				SearchService: utils.GetSearchService(), | ||||
| 			} | ||||
| 			if err := gh.UploadMultipleReports(ctx, &issueDetails); err != nil { | ||||
| 				errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 			} | ||||
| 	reportPaths, errors := reportGitHubIssuesAndCreateReports( | ||||
| 		ctx, | ||||
| 		config, | ||||
| 		utils, | ||||
| 		scan, | ||||
| 		allAlerts, | ||||
| 		allLibraries, | ||||
| 		allAssessedAlerts, | ||||
| 		cvssSeverityLimit, | ||||
| 		vulnerabilitiesCount, | ||||
| 	) | ||||
|  | ||||
| 	allOccurredErrors = append(allOccurredErrors, errors...) | ||||
|  | ||||
| 	if len(allOccurredErrors) > 0 { | ||||
| 		if vulnerabilitiesCount > 0 { | ||||
| 			log.SetErrorCategory(log.ErrorCompliance) | ||||
| 		} | ||||
| 		return reportPaths, fmt.Errorf(strings.Join(allOccurredErrors, ": ")) | ||||
| 	} | ||||
|  | ||||
| 	return reportPaths, nil | ||||
| } | ||||
|  | ||||
| func collectVulnsAndLibsForProject( | ||||
| 	config *ScanOptions, | ||||
| 	cvssSeverityLimit float64, | ||||
| 	project ws.Project, | ||||
| 	sys whitesource, | ||||
| 	assessments *[]format.Assessment, | ||||
| 	influx *whitesourceExecuteScanInflux, | ||||
| ) ( | ||||
| 	int, | ||||
| 	[]ws.Alert, | ||||
| 	[]ws.Alert, | ||||
| 	[]ws.Library, | ||||
| 	[]string, | ||||
| ) { | ||||
| 	var errorsOccurred []string | ||||
| 	vulCount, alerts, assessedAlerts, err := checkProjectSecurityViolations(config, cvssSeverityLimit, project, sys, assessments, influx) | ||||
| 	if err != nil { | ||||
| 		errorsOccurred = append(errorsOccurred, fmt.Sprint(err)) | ||||
| 	} | ||||
|  | ||||
| 	// collect all libraries detected in all related projects and errors | ||||
| 	libraries, err := sys.GetProjectHierarchy(project.Token, true) | ||||
| 	if err != nil { | ||||
| 		errorsOccurred = append(errorsOccurred, fmt.Sprint(err)) | ||||
| 	} | ||||
| 	log.Entry().Debugf("Collected %v libraries for project %v", len(libraries), project.Name) | ||||
|  | ||||
| 	return vulCount, alerts, assessedAlerts, libraries, errorsOccurred | ||||
| } | ||||
|  | ||||
| func reportGitHubIssuesAndCreateReports( | ||||
| 	ctx context.Context, | ||||
| 	config *ScanOptions, | ||||
| 	utils whitesourceUtils, | ||||
| 	scan *ws.Scan, | ||||
| 	allAlerts []ws.Alert, | ||||
| 	allLibraries []ws.Library, | ||||
| 	allAssessedAlerts []ws.Alert, | ||||
| 	cvssSeverityLimit float64, | ||||
| 	vulnerabilitiesCount int, | ||||
| ) ([]piperutils.Path, []string) { | ||||
| 	errorsOccured := make([]string, 0) | ||||
| 	reportPaths := make([]piperutils.Path, 0) | ||||
|  | ||||
| 	if config.CreateResultIssue && vulnerabilitiesCount > 0 && len(config.GithubToken) > 0 && len(config.GithubAPIURL) > 0 && len(config.Owner) > 0 && len(config.Repository) > 0 { | ||||
| 		log.Entry().Debugf("Creating result issues for %v alert(s)", vulnerabilitiesCount) | ||||
| 		issueDetails := make([]reporting.IssueDetail, len(allAlerts)) | ||||
| 		piperutils.CopyAtoB(allAlerts, issueDetails) | ||||
| 		gh := reporting.GitHub{ | ||||
| 			Owner:         &config.Owner, | ||||
| 			Repository:    &config.Repository, | ||||
| 			Assignees:     &config.Assignees, | ||||
| 			IssueService:  utils.GetIssueService(), | ||||
| 			SearchService: utils.GetSearchService(), | ||||
| 		} | ||||
|  | ||||
| 		scanReport := ws.CreateCustomVulnerabilityReport(config.ProductName, scan, &allAlerts, cvssSeverityLimit) | ||||
| 		paths, err := ws.WriteCustomVulnerabilityReports(config.ProductName, scan, scanReport, utils) | ||||
| 		if err != nil { | ||||
| 		if err := gh.UploadMultipleReports(ctx, &issueDetails); err != nil { | ||||
| 			errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 		} | ||||
| 		reportPaths = append(reportPaths, paths...) | ||||
|  | ||||
| 		sarif := ws.CreateSarifResultFile(scan, &allAlerts) | ||||
| 		paths, err = ws.WriteSarifFile(sarif, utils) | ||||
| 		if err != nil { | ||||
| 			errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 		} | ||||
| 		reportPaths = append(reportPaths, paths...) | ||||
|  | ||||
| 		sbom, err := ws.CreateCycloneSBOM(scan, &allLibraries, &allAlerts, &allAssessedAlerts) | ||||
| 		if err != nil { | ||||
| 			errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 		} | ||||
| 		paths, err = ws.WriteCycloneSBOM(sbom, utils) | ||||
| 		if err != nil { | ||||
| 			errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 		} | ||||
| 		reportPaths = append(reportPaths, paths...) | ||||
|  | ||||
| 		if len(errorsOccured) > 0 { | ||||
| 			if vulnerabilitiesCount > 0 { | ||||
| 				log.SetErrorCategory(log.ErrorCompliance) | ||||
| 			} | ||||
| 			return reportPaths, fmt.Errorf(strings.Join(errorsOccured, ": ")) | ||||
| 		} | ||||
| 	} | ||||
| 	return reportPaths, nil | ||||
|  | ||||
| 	scanReport := ws.CreateCustomVulnerabilityReport(config.ProductName, scan, &allAlerts, cvssSeverityLimit) | ||||
| 	paths, err := ws.WriteCustomVulnerabilityReports(config.ProductName, scan, scanReport, utils) | ||||
| 	if err != nil { | ||||
| 		errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 	} | ||||
|  | ||||
| 	reportPaths = append(reportPaths, paths...) | ||||
|  | ||||
| 	sarif := ws.CreateSarifResultFile(scan, &allAlerts) | ||||
| 	paths, err = ws.WriteSarifFile(sarif, utils) | ||||
| 	if err != nil { | ||||
| 		errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 	} | ||||
|  | ||||
| 	reportPaths = append(reportPaths, paths...) | ||||
|  | ||||
| 	sbom, err := ws.CreateCycloneSBOM(scan, &allLibraries, &allAlerts, &allAssessedAlerts) | ||||
| 	if err != nil { | ||||
| 		errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 	} | ||||
|  | ||||
| 	paths, err = ws.WriteCycloneSBOM(sbom, utils) | ||||
| 	if err != nil { | ||||
| 		errorsOccured = append(errorsOccured, fmt.Sprint(err)) | ||||
| 	} | ||||
|  | ||||
| 	reportPaths = append(reportPaths, paths...) | ||||
|  | ||||
| 	return reportPaths, errorsOccured | ||||
| } | ||||
|  | ||||
| // read assessments from file and expose them to match alerts and filter them before processing | ||||
|   | ||||
| @@ -595,7 +595,7 @@ func TestCheckSecurityViolations(t *testing.T) { | ||||
|  | ||||
| 		reportPaths, err := checkSecurityViolations(ctx, &config, scan, systemMock, utilsMock, &influx) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, 0, len(reportPaths)) | ||||
| 		assert.Equal(t, 3, len(reportPaths)) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error - wrong limit", func(t *testing.T) { | ||||
| @@ -651,7 +651,7 @@ func TestCheckSecurityViolations(t *testing.T) { | ||||
|  | ||||
| 		reportPaths, err := checkSecurityViolations(ctx, &config, scan, systemMock, utilsMock, &influx) | ||||
| 		assert.Contains(t, fmt.Sprint(err), "1 Open Source Software Security vulnerabilities") | ||||
| 		assert.Equal(t, 0, len(reportPaths)) | ||||
| 		assert.Equal(t, 3, len(reportPaths)) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user