From 711edd24d08ae35f116da0559a36725f9435162a Mon Sep 17 00:00:00 2001 From: Margarita Date: Sun, 30 Jun 2024 15:27:05 +0300 Subject: [PATCH] AST-31546 Add support to GL-Sca report creation (#788) * AST-31546 Add support to GL-Sca report creation * Revert test * Update result_test.go * Update result_test.go Delete whitespace on row 714 * Revert change * Revert change * Update result_test.go --- internal/commands/result.go | 186 ++++++++++++++++++++-- internal/commands/result_test.go | 83 +++++++--- internal/commands/scan.go | 3 +- internal/commands/util/printer/printer.go | 3 +- internal/wrappers/results-gl-sast.go | 10 +- internal/wrappers/results-gl-sca.go | 107 +++++++++++++ test/integration/result_test.go | 111 ++++++++++++- 7 files changed, 462 insertions(+), 41 deletions(-) create mode 100644 internal/wrappers/results-gl-sca.go diff --git a/internal/commands/result.go b/internal/commands/result.go index c50a4e443..49f6212f0 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -40,7 +40,8 @@ const ( lowLabel = "low" infoLabel = "info" sonarTypeLabel = "_sonar" - glSastTypeLobel = ".gl-sast-report" + glSastTypeLabel = ".gl-sast-report" + glScaTypeLabel = ".gl-sca-report" directoryPermission = 0700 infoSonar = "INFO" lowSonar = "MINOR" @@ -107,7 +108,8 @@ var summaryFormats = []string{ printer.FormatPDF, printer.FormatSummaryMarkdown, printer.FormatSbom, - printer.FormatGL, + printer.FormatGLSast, + printer.FormatGLSca, } var filterResultsListFlagUsage = fmt.Sprintf( @@ -229,7 +231,8 @@ func resultShowSubCommand( printer.FormatSbom, printer.FormatPDF, printer.FormatSummaryMarkdown, - printer.FormatGL, + printer.FormatGLSast, + printer.FormatGLSca, ) resultShowCmd.PersistentFlags().String(commonParams.ReportFormatPdfToEmailFlag, "", pdfToEmailFlagDescription) resultShowCmd.PersistentFlags().String(commonParams.ReportSbomFormatFlag, defaultSbomOption, sbomReportFlagDescription) @@ -1142,10 +1145,15 @@ func createReport(format, jsonRpt := createTargetName(targetFile, targetPath, printer.FormatJSON) return exportJSONResults(jsonRpt, results) } - if printer.IsFormat(format, printer.FormatGL) { - jsonRpt := createTargetName(fmt.Sprintf("%s%s", targetFile, glSastTypeLobel), targetPath, printer.FormatJSON) + if printer.IsFormat(format, printer.FormatGLSast) { + jsonRpt := createTargetName(fmt.Sprintf("%s%s", targetFile, glSastTypeLabel), targetPath, printer.FormatJSON) return exportGlSastResults(jsonRpt, results, summary) } + if printer.IsFormat(format, printer.FormatGLSca) { + jsonRpt := createTargetName(fmt.Sprintf("%s%s", targetFile, glScaTypeLabel), targetPath, printer.FormatJSON) + return exportGlScaResults(jsonRpt, results, summary) + } + if printer.IsFormat(format, printer.FormatSummaryConsole) { return writeConsoleSummary(summary) } @@ -1300,12 +1308,34 @@ func exportGlSastResults(targetFile string, results *wrappers.ScanResultsCollect glSast.Vulnerabilities = []wrappers.GlVulnerabilities{} err := addScanToGlSastReport(summary, glSast) if err != nil { - return errors.Wrapf(err, "%s: failed to add scan to gl sast report", failedListingResults) + return errors.Wrapf(err, "%s: failed to add scan to gl-sast report", failedListingResults) } - convertCxResultToGlVulnerability(results, glSast, summary.BaseURI) + convertCxResultToGlSastVulnerability(results, glSast, summary.BaseURI) resultsJSON, err := json.Marshal(glSast) if err != nil { - return errors.Wrapf(err, "%s: failed to serialize gl sast report ", failedListingResults) + return errors.Wrapf(err, "%s: failed to serialize gl-sast report ", failedListingResults) + } + f, err := os.Create(targetFile) + if err != nil { + return errors.Wrapf(err, "%s: failed to create target file ", failedListingResults) + } + defer f.Close() + _, _ = fmt.Fprintln(f, string(resultsJSON)) + return nil +} + +func exportGlScaResults(targetFile string, results *wrappers.ScanResultsCollection, summary *wrappers.ResultSummary) error { + log.Println("Creating Gl-sca Report: ", targetFile) + glScaResult := &wrappers.GlScaResultsCollection{} + err := addScanToGlScaReport(summary, glScaResult) + if err != nil { + return errors.Wrapf(err, "%s: failed to denerate GL-Sca report ", failedListingResults) + } + convertCxResultToGlScaVulnerability(results, glScaResult) + convertCxResultToGlScaFiles(results, glScaResult) + resultsJSON, err := json.Marshal(glScaResult) + if err != nil { + return errors.Wrapf(err, "%s: failed to serialize GL-Sca report ", failedListingResults) } f, err := os.Create(targetFile) if err != nil { @@ -1313,8 +1343,36 @@ func exportGlSastResults(targetFile string, results *wrappers.ScanResultsCollect } _, _ = fmt.Fprintln(f, string(resultsJSON)) defer f.Close() + + return nil +} + +func addScanToGlScaReport(summary *wrappers.ResultSummary, glScaResult *wrappers.GlScaResultsCollection) error { + createdAt, err := time.Parse(summaryCreatedAtLayout, summary.CreatedAt) + if err != nil { + return err + } + + glScaResult.Schema = wrappers.ScaSchema + glScaResult.Version = wrappers.SchemaVersion + glScaResult.Scan.Analyzer.VendorGlSCA.VendorGlname = wrappers.AnalyzerScaID + glScaResult.Scan.Analyzer.Name = wrappers.AnalyzerScaID + glScaResult.Scan.Analyzer.Name = wrappers.AnalyzerScaID + glScaResult.Scan.Analyzer.ID = wrappers.ScannerID + glScaResult.Scan.Scanner.ID = wrappers.ScannerID + glScaResult.Scan.Scanner.Name = wrappers.AnalyzerScaID + glScaResult.Scan.Scanner.VendorGlSCA.VendorGlname = wrappers.AnalyzerScaID + glScaResult.Scan.Status = commonParams.Success + glScaResult.Scan.Type = wrappers.ScannerType + glScaResult.Scan.StartTime = createdAt.Format(glTimeFormat) + glScaResult.Scan.EndTime = createdAt.Format(glTimeFormat) + glScaResult.Scan.Scanner.Name = wrappers.AnalyzerScaID + glScaResult.Scan.Scanner.VersionGlSca = commonParams.Version + glScaResult.Scan.Analyzer.VersionGlSca = commonParams.Version + return nil } + func addScanToGlSastReport(summary *wrappers.ResultSummary, glSast *wrappers.GlSastResultsCollection) error { createdAt, err := time.Parse(summaryCreatedAtLayout, summary.CreatedAt) if err != nil { @@ -1322,8 +1380,8 @@ func addScanToGlSastReport(summary *wrappers.ResultSummary, glSast *wrappers.GlS } glSast.Scan = wrappers.ScanGlReport{} - glSast.Schema = "https://gitlab.com/gitlab-org/gitlab/-/raw/master/lib/gitlab/ci/parsers/security/validators/schemas/15.0.0/sast-report-format.json" - glSast.Version = "15.0.0" + glSast.Schema = wrappers.SastSchema + glSast.Version = wrappers.SastSchemaVersion glSast.Scan.Analyzer.URL = wrappers.AnalyzerURL glSast.Scan.Analyzer.Name = wrappers.VendorName glSast.Scan.Analyzer.Vendor.Name = wrappers.VendorName @@ -1623,7 +1681,7 @@ func convertCxResultsToSarif(results *wrappers.ScanResultsCollection) *wrappers. return sarif } -func convertCxResultToGlVulnerability(results *wrappers.ScanResultsCollection, glSast *wrappers.GlSastResultsCollection, summaryBaseURI string) { +func convertCxResultToGlSastVulnerability(results *wrappers.ScanResultsCollection, glSast *wrappers.GlSastResultsCollection, summaryBaseURI string) { for _, result := range results.Results { if strings.TrimSpace(result.Type) == commonParams.SastType { glSast = parseGlSastVulnerability(result, glSast, summaryBaseURI) @@ -1631,6 +1689,21 @@ func convertCxResultToGlVulnerability(results *wrappers.ScanResultsCollection, g } } +func convertCxResultToGlScaVulnerability(results *wrappers.ScanResultsCollection, glScaResult *wrappers.GlScaResultsCollection) { + for _, result := range results.Results { + if strings.TrimSpace(result.Type) == commonParams.ScaType { + glScaResult = parseGlscaVulnerability(result, glScaResult) + } + } +} + +func convertCxResultToGlScaFiles(results *wrappers.ScanResultsCollection, glScaResult *wrappers.GlScaResultsCollection) { + for _, result := range results.Results { + if strings.TrimSpace(result.Type) == commonParams.ScaType { + glScaResult = parseGlScaFiles(result, glScaResult) + } + } +} func parseGlSastVulnerability(result *wrappers.ScanResult, glSast *wrappers.GlSastResultsCollection, summaryBaseURI string) *wrappers.GlSastResultsCollection { queryName := result.ScanResultData.QueryName fileName := result.ScanResultData.Nodes[0].FileName @@ -1685,6 +1758,97 @@ func parseGlSastVulnerability(result *wrappers.ScanResult, glSast *wrappers.GlSa }) return glSast } +func parseGlscaVulnerability(result *wrappers.ScanResult, glDependencyResult *wrappers.GlScaResultsCollection) *wrappers.GlScaResultsCollection { + if result.ScanResultData.ScaPackageCollection != nil { + glDependencyResult.Vulnerabilities = append(glDependencyResult.Vulnerabilities, wrappers.GlScaDepVulnerabilities{ + ID: result.ID, + Name: result.VulnerabilityDetails.CveName, + Description: result.Description, + Severity: cases.Title(language.English).String(result.Severity), + Solution: result.ScanResultData.RecommendedVersion, + Identifiers: collectScaPackageData(result), + Links: collectScaPackageLinks(result), + TrackingDep: wrappers.TrackingDep{ + Items: collectScaPackageItemsDep(result), + }, + Flags: make([]string, 0), + LocationDep: wrappers.GlScaDepVulnerabilityLocation{ + File: parseGlDependencyLocation(result), + Dependency: wrappers.ScaDependencyLocation{ + Package: wrappers.PackageName{Name: result.ScanResultData.PackageIdentifier}, + ScaDependencyLocationVersion: "", + Direct: result.ScanResultData.ScaPackageCollection.IsDirectDependency, + ScaDependencyPath: result.ScanResultData.Line, + }, + }, + }) + } + return glDependencyResult +} +func parseGlDependencyLocation(result *wrappers.ScanResult) string { + var location string + if result != nil && result.ScanResultData.ScaPackageCollection != nil && result.ScanResultData.ScaPackageCollection.Locations != nil { + location = *result.ScanResultData.ScaPackageCollection.Locations[0] + } else { + location = "" + } + return (location) +} +func parseGlScaFiles(result *wrappers.ScanResult, glScaResult *wrappers.GlScaResultsCollection) *wrappers.GlScaResultsCollection { + if result.ScanResultData.ScaPackageCollection != nil && result.ScanResultData.ScaPackageCollection.Locations != nil { + glScaResult.ScaDependencyFiles = append(glScaResult.ScaDependencyFiles, wrappers.ScaDependencyFile{ + Path: *result.ScanResultData.ScaPackageCollection.Locations[0], + PackageManager: result.ScanResultData.ScaPackageCollection.ID, + Dependencies: collectScaFileLocations(result), + }) + } + return glScaResult +} +func collectScaFileLocations(result *wrappers.ScanResult) []wrappers.ScaDependencyLocation { + allScaIdentifierLocations := []wrappers.ScaDependencyLocation{} + for _, packageInfo := range result.ScanResultData.PackageData { + allScaIdentifierLocations = append(allScaIdentifierLocations, wrappers.ScaDependencyLocation{ + Package: wrappers.PackageName{ + Name: packageInfo.Type, + }, + ScaDependencyLocationVersion: packageInfo.URL, + Direct: true, + ScaDependencyPath: result.ScanResultData.Line, + }) + } + return allScaIdentifierLocations +} +func collectScaPackageItemsDep(result *wrappers.ScanResult) []wrappers.ItemDep { + allScaPackageItemDep := []wrappers.ItemDep{} + allScaPackageItemDep = append(allScaPackageItemDep, wrappers.ItemDep{ + Signature: []wrappers.SignatureDep{{Algorithm: "SCA-Algorithm ", Value: "NA"}}, + File: result.VulnerabilityDetails.CveName, + EndLine: 0, + StartLine: 0, + }) + return allScaPackageItemDep +} +func collectScaPackageLinks(result *wrappers.ScanResult) []wrappers.LinkDep { + allScaPackageLinks := []wrappers.LinkDep{} + for _, packageInfo := range result.ScanResultData.PackageData { + allScaPackageLinks = append(allScaPackageLinks, wrappers.LinkDep{ + Name: packageInfo.Type, + URL: packageInfo.URL, + }) + } + return allScaPackageLinks +} +func collectScaPackageData(result *wrappers.ScanResult) []wrappers.IdentifierDep { + allIdentifierDep := []wrappers.IdentifierDep{} + for _, packageInfo := range result.ScanResultData.PackageData { + allIdentifierDep = append(allIdentifierDep, wrappers.IdentifierDep{ + Type: packageInfo.Type, + Value: packageInfo.URL, + Name: packageInfo.URL, + }) + } + return allIdentifierDep +} func convertCxResultsToSonar(results *wrappers.ScanResultsCollection) *wrappers.ScanResultsSonar { var sonar = new(wrappers.ScanResultsSonar) diff --git a/internal/commands/result_test.go b/internal/commands/result_test.go index 524a1bd9b..c11b9077a 100644 --- a/internal/commands/result_test.go +++ b/internal/commands/result_test.go @@ -530,32 +530,19 @@ func TestSBOMReportXMLWithProxy(t *testing.T) { func TestRunGetResultsByScanIdGLFormat(t *testing.T) { execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "gl-sast") // Run test for gl-sast report type - os.Remove(fmt.Sprintf("%s.%s", fileName, printer.FormatGL)) + os.Remove(fmt.Sprintf("%s.%s", fileName, printer.FormatGLSast)) } - -func TestRunGetResultsByScanIdGLFormat_NoVulnerabilities_Success(t *testing.T) { - // Execute the command and perform nil assertion - execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK_NO_VULNERABILITIES", "--report-format", "gl-sast") - +func TestRunGetResultsByScanIdGLSastAndAScaFormat(t *testing.T) { + execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "gl-sast,gl-sca") // Run test for gl-sast report type - // Check if the file exists and vulnerabilities is empty, then delete the file - if _, err := os.Stat(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGL)); err == nil { - t.Logf("File exists: %s.%s", fileName, printer.FormatGL) - resultsData, err := os.ReadFile(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGL)) - if err != nil { - t.Logf("Failed to read file: %v", err) - } + os.Remove(fmt.Sprintf("%s.%s", fileName, printer.FormatGLSast)) + os.Remove(fmt.Sprintf("%s.%s", fileName, printer.FormatGLSca)) +} - var results wrappers.GlSastResultsCollection - if err := json.Unmarshal(resultsData, &results); err != nil { - t.Logf("Failed to unmarshal JSON: %v", err) - } - assert.Equal(t, len(results.Vulnerabilities), 0, "No vulnerabilities should be found") - if err := os.Remove(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGL)); err != nil { - t.Logf("Failed to delete file: %v", err) - } - t.Log("File deleted successfully.") - } +func TestRunGetResultsByScanIdGLScaFormat(t *testing.T) { + execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "gl-sca") + // Run test for gl-sca report type + os.Remove(fmt.Sprintf("%s.%s", fileName, printer.FormatGLSca)) } func Test_addPackageInformation(t *testing.T) { @@ -593,6 +580,56 @@ func Test_addPackageInformation(t *testing.T) { assert.Equal(t, expectedFixLink, actualFixLink, "FixLink should match the result ID") } +func TestRunGetResultsByScanIdGLSastFormat_NoVulnerabilities_Success(t *testing.T) { + // Execute the command and perform nil assertion + execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK_NO_VULNERABILITIES", "--report-format", "gl-sast") + + // Run test for gl-sast report type + // Check if the file exists and vulnerabilities is empty, then delete the file + if _, err := os.Stat(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGLSast)); err == nil { + t.Logf("File exists: %s.%s", fileName, printer.FormatGLSast) + resultsData, err := os.ReadFile(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGLSast)) + if err != nil { + t.Logf("Failed to read file: %v", err) + } + + var results wrappers.GlSastResultsCollection + if err := json.Unmarshal(resultsData, &results); err != nil { + t.Logf("Failed to unmarshal JSON: %v", err) + } + assert.Equal(t, len(results.Vulnerabilities), 0, "No vulnerabilities should be found") + if err := os.Remove(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGLSast)); err != nil { + t.Logf("Failed to delete file: %v", err) + } + t.Log("File deleted successfully.") + } +} + +func TestRunGetResultsByScanIdGLScaFormat_NoVulnerabilities_Success(t *testing.T) { + // Execute the command and perform nil assertion + execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK_NO_VULNERABILITIES", "--report-format", "gl-sca") + + // Run test for gl-sca report type + // Check if the file exists and vulnerabilities is empty, then delete the file + if _, err := os.Stat(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGLSca)); err == nil { + t.Logf("File exists: %s.%s", fileName, printer.FormatGLSca) + resultsData, err := os.ReadFile(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGLSca)) + if err != nil { + t.Logf("Failed to read file: %v", err) + } + + var results wrappers.GlScaResultsCollection + if err := json.Unmarshal(resultsData, &results); err != nil { + t.Logf("Failed to unmarshal JSON: %v", err) + } + assert.Equal(t, len(results.Vulnerabilities), 0, "No vulnerabilities should be found") + if err := os.Remove(fmt.Sprintf("%s.%s-report.json", fileName, printer.FormatGLSca)); err != nil { + t.Logf("Failed to delete file: %v", err) + } + t.Log("File deleted successfully.") + } +} + func TestRunGetResultsByScanIdSummaryConsoleFormat_ScsNotScanned_ScsMissingInReport(t *testing.T) { mock.HasScs = false mock.ScsScanPartial = false diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 7c9dea93a..d433a03f3 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -598,7 +598,8 @@ func scanCreateSubCommand( printer.FormatSbom, printer.FormatPDF, printer.FormatSummaryMarkdown, - printer.FormatGL, + printer.FormatGLSast, + printer.FormatGLSca, ) createScanCmd.PersistentFlags().String(commonParams.APIDocumentationFlag, "", apiDocumentationFlagDescription) createScanCmd.PersistentFlags().String(commonParams.ExploitablePathFlag, "", exploitablePathFlagDescription) diff --git a/internal/commands/util/printer/printer.go b/internal/commands/util/printer/printer.go index 13013e21c..0ead320b4 100644 --- a/internal/commands/util/printer/printer.go +++ b/internal/commands/util/printer/printer.go @@ -28,7 +28,8 @@ const ( FormatSummaryMarkdown = "markdown" FormatSbom = "sbom" FormatXML = "xml" - FormatGL = "gl-sast" + FormatGLSast = "gl-sast" + FormatGLSca = "gl-sca" ) func Print(w io.Writer, view interface{}, format string) error { diff --git a/internal/wrappers/results-gl-sast.go b/internal/wrappers/results-gl-sast.go index 3896e583a..5b1928df9 100644 --- a/internal/wrappers/results-gl-sast.go +++ b/internal/wrappers/results-gl-sast.go @@ -1,10 +1,12 @@ package wrappers const ( - AnalyzerName = "CxOne" - AnalyzerID = AnalyzerName + "-SAST" - AnalyzerURL = "https://checkmarx.com/" - VendorName = "Checkmarx" + AnalyzerName = "CxOne" + AnalyzerID = AnalyzerName + "-SAST" + AnalyzerURL = "https://checkmarx.com/" + VendorName = "Checkmarx" + SastSchema = "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/sast-report-format.json" + SastSchemaVersion = "15.0" ) type GlSastResultsCollection struct { diff --git a/internal/wrappers/results-gl-sca.go b/internal/wrappers/results-gl-sca.go new file mode 100644 index 000000000..98d6deea2 --- /dev/null +++ b/internal/wrappers/results-gl-sca.go @@ -0,0 +1,107 @@ +package wrappers + +const ( + AnalyzerScaName = "CxOne" + AnalyzerScaID = AnalyzerScaName + "-SCA" + ScannerID = "SCA" + ScannerType = "dependency_scanning" + ScaSchema = "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dependency-scanning-report-format.json" + SchemaVersion = "15.0.0" +) + +type GlScaResultsCollection struct { + Scan ScanGlScaDepReport `json:"scan"` + Schema string `json:"schema"` + Version string `json:"version"` + Vulnerabilities []GlScaDepVulnerabilities `json:"vulnerabilities"` + ScaDependencyFiles []ScaDependencyFile `json:"dependency_files"` +} + +type GlVendor struct { + VendorGlname string `json:"name"` +} + +type ScanGlScaDepReport struct { + EndTime string `json:"end_time,omitempty"` + Analyzer GlDepAnalyzer `json:"analyzer,omitempty"` + Scanner GlDepScanner `json:"scanner,omitempty"` + StartTime string `json:"start_time,omitempty"` + Status string `json:"status,omitempty"` + Type string `json:"type"` +} + +type GlDepAnalyzer struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + VendorGlSCA GlVendor `json:"vendor"` + VersionGlSca string `json:"version,omitempty"` +} + +type GlDepScanner struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + VersionGlSca string `json:"version,omitempty"` + VendorGlSCA GlVendor `json:"vendor"` +} + +type GlScaDepVulnerabilities struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Severity string `json:"severity"` + Solution interface{} `json:"solution"` + Identifiers []IdentifierDep `json:"identifiers,omitempty"` + Links []LinkDep `json:"links"` + TrackingDep TrackingDep `json:"tracking"` + Flags []string `json:"flags"` + LocationDep GlScaDepVulnerabilityLocation `json:"location,omitempty"` +} + +type IdentifierDep struct { + Type string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` +} + +type LinkDep struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` +} + +type TrackingDep struct { + Items []ItemDep `json:"items"` +} + +type ItemDep struct { + Signature []SignatureDep `json:"signatures"` + File string `json:"file"` + EndLine uint `json:"end_line"` + StartLine uint `json:"start_line"` +} + +type SignatureDep struct { + Algorithm string `json:"algorithm"` + Value string `json:"value"` +} + +type GlScaDepVulnerabilityLocation struct { + File string `json:"file"` + Dependency ScaDependencyLocation `json:"dependency"` +} + +type ScaDependencyLocation struct { + Package PackageName `json:"package"` + ScaDependencyLocationVersion string `json:"version"` + Direct bool `json:"direct"` + ScaDependencyPath uint `json:"iid,omitempty"` +} + +type PackageName struct { + Name string `json:"name"` +} + +type ScaDependencyFile struct { + Path string `json:"path"` + PackageManager string `json:"package_manager"` + Dependencies []ScaDependencyLocation `json:"dependencies"` +} diff --git a/test/integration/result_test.go b/test/integration/result_test.go index cf924ee16..6831326da 100644 --- a/test/integration/result_test.go +++ b/test/integration/result_test.go @@ -23,6 +23,7 @@ import ( const ( fileName = "result-test" resultsDirectory = "output-results-folder/" + fileExtention = "report.json" ) func TestResultsExitCode_OnSendingFakeScanId_ShouldReturnNotFoundError(t *testing.T) { @@ -92,7 +93,6 @@ func TestResultListJson(t *testing.T) { printer.FormatSummaryJSON, printer.FormatPDF, printer.FormatSummaryMarkdown, - printer.FormatGL, }, ",", ), flag(params.TargetFlag), fileName, @@ -126,6 +126,54 @@ func assertResultFilesCreated(t *testing.T) { }() } +func TestResultListForGlReports(t *testing.T) { + + assertRequiredParameter(t, "Please provide a scan ID", "results", "show") + + scanID, _ := getRootScan(t) + + outputBuffer := executeCmdNilAssertion( + t, "Getting results should pass", + "results", + "show", + "--debug", + flag(params.TargetFormatFlag), strings.Join( + []string{ + printer.FormatGLSast, + printer.FormatGLSca, + }, ",", + ), + flag(params.TargetFlag), fileName, + flag(params.ScanIDFlag), scanID, + flag(params.TargetPathFlag), resultsDirectory, + flag(params.SastRedundancyFlag), + ) + + result := wrappers.ScanResultsCollection{} + _ = unmarshall(t, outputBuffer, &result, "Reading results should pass") + + assert.Assert(t, uint(len(result.Results)) == result.TotalCount, "Should have results") + + assertGlResultFilesCreated(t) + + deleteScanAndProject() +} + +func assertGlResultFilesCreated(t *testing.T) { + extensions := []string{printer.FormatGLSast, + printer.FormatGLSca} + + for _, e := range extensions { + _, err := os.Stat(fmt.Sprintf("%s%s.%s-%s", resultsDirectory, fileName, e, fileExtention)) + assert.NilError(t, err, "Report file should exist for extension "+e) + } + + // delete directory in the end + defer func() { + _ = os.RemoveAll(fmt.Sprintf(resultsDirectory)) + }() +} + func TestResultsShowParamFailed(t *testing.T) { args := []string{ "results", @@ -389,6 +437,67 @@ func TestResultsCounterJsonOutput(t *testing.T) { } +func TestResultsCounterGlSastOutput(t *testing.T) { + scanID, _ := getRootScan(t) + _ = executeCmdNilAssertion( + t, "Results show generating gl-sast report with options should pass", + "results", "show", + flag(params.ScanIDFlag), scanID, + flag(params.TargetFormatFlag), printer.FormatGLSast, + flag(params.TargetPathFlag), resultsDirectory, + flag(params.TargetFlag), fileName, + ) + + defer func() { + _ = os.RemoveAll(fmt.Sprintf(resultsDirectory)) + }() + + result := wrappers.ScanResultsCollection{} + + _, err := os.Stat(fmt.Sprintf("%s%s.%s-%s", resultsDirectory, fileName, printer.FormatGLSast, fileExtention)) + + assert.NilError(t, err, "Report file should exist for extension "+printer.FormatGLSast) + + file, err := os.ReadFile(fmt.Sprintf("%s%s.%s-%s", resultsDirectory, fileName, printer.FormatGLSast, fileExtention)) + assert.NilError(t, err, "error reading file") + + err = json.Unmarshal(file, &result) + assert.NilError(t, err, "error unmarshalling file") + + assert.Assert(t, uint(len(result.Results)) == result.TotalCount, "Should have results") + +} + +func TestResultsCounterGlSCAOutput(t *testing.T) { + scanID, _ := getRootScan(t) + _ = executeCmdNilAssertion( + t, "Results show generating gl-sca report with options should pass", + "results", "show", + flag(params.ScanIDFlag), scanID, + flag(params.TargetFormatFlag), printer.FormatGLSca, + flag(params.TargetPathFlag), resultsDirectory, + flag(params.TargetFlag), fileName, + ) + + defer func() { + _ = os.RemoveAll(fmt.Sprintf(resultsDirectory)) + }() + + result := wrappers.ScanResultsCollection{} + + _, err := os.Stat(fmt.Sprintf("%s%s.%s-%s", resultsDirectory, fileName, printer.FormatGLSca, fileExtention)) + + assert.NilError(t, err, "Report file should exist for extension "+printer.FormatGLSca) + + file, err := os.ReadFile(fmt.Sprintf("%s%s.%s-%s", resultsDirectory, fileName, printer.FormatGLSca, fileExtention)) + assert.NilError(t, err, "error reading file") + + err = json.Unmarshal(file, &result) + assert.NilError(t, err, "error unmarshalling file") + + assert.Assert(t, uint(len(result.Results)) == result.TotalCount, "Should have results") +} + func TestResultsGeneratingJsonReportWithSeverityHighAndWithoutNotExploitable(t *testing.T) { scanID, _ := getRootScan(t)