Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AST-25406 Gl-SASt report #564

Closed
wants to merge 16 commits into from
Closed
107 changes: 106 additions & 1 deletion internal/commands/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"text/template"
"time"
Expand Down Expand Up @@ -778,6 +779,10 @@ func createReport(format,
jsonRpt := createTargetName(targetFile, targetPath, "json")
return exportJSONResults(jsonRpt, results)
}
if printer.IsFormat(format, printer.FormatGL) {
jsonRpt := createTargetName("gl-sast-report", targetPath, "json")
return exportGlSastResults(jsonRpt, results, summary)
}
if printer.IsFormat(format, printer.FormatSummaryConsole) {
return writeConsoleSummary(summary)
}
Expand Down Expand Up @@ -915,7 +920,28 @@ func exportSarifResults(targetFile string, results *wrappers.ScanResultsCollecti
_ = f.Close()
return nil
}

func exportGlSastResults(targetFile string, results *wrappers.ScanResultsCollection, summary *wrappers.ResultSummary) error {
var err error
var resultsJSON []byte
log.Println("Creating gl-sast Report: ", targetFile)
var glSastResults = convertCxResultsToGLSast(results)
glSastResults = addStatus(summary, glSastResults)
resultsJSON, err = json.Marshal(glSastResults)
if err != nil {
return errors.Wrapf(err, "%s: failed to serialize results response ", failedGettingAll)
}
f, err := os.Create(targetFile)
if err != nil {
return errors.Wrapf(err, "%s: failed to create target file ", failedGettingAll)
}
_, _ = fmt.Fprintln(f, string(resultsJSON))
defer f.Close()
return nil
}
func addStatus(summary *wrappers.ResultSummary, glSastResults *wrappers.GlSastResultsCollection) *wrappers.GlSastResultsCollection {
glSastResults.Scan.Status = summary.Status
return glSastResults
}
func exportSonarResults(targetFile string, results *wrappers.ScanResultsCollection) error {
var err error
var resultsJSON []byte
Expand Down Expand Up @@ -1143,6 +1169,85 @@ func convertCxResultsToSarif(results *wrappers.ScanResultsCollection) *wrappers.
sarif.Runs = append(sarif.Runs, createSarifRun(results))
return sarif
}
func convertCxResultsToGLSast(results *wrappers.ScanResultsCollection) *wrappers.GlSastResultsCollection {
var glSast = new(wrappers.GlSastResultsCollection)
glSast.Scan = wrappers.ScanGlReport{}
glSast = setConstValueGlReport(glSast)
glVulnra := convertCxResultToGlVulnerability(results, glSast)
glSast.Vulnerabilities = glVulnra
return glSast
}

func convertCxResultToGlVulnerability(results *wrappers.ScanResultsCollection, glSast *wrappers.GlSastResultsCollection) []wrappers.GlVulnerabilities {
for _, result := range results.Results {
engineType := strings.TrimSpace(result.Type)
if engineType == commonParams.SastType {
glSast = parseGlSastVulnerability(result, glSast)
} /*else if engineType == commonParams.KicsType {
// Add code for KicsType if required.
} else if engineType == commonParams.ScaType {
// Add code for ScaType if required.
}*/
}
return glSast.Vulnerabilities
}

func parseGlSastVulnerability(result *wrappers.ScanResult, glSast *wrappers.GlSastResultsCollection) *wrappers.GlSastResultsCollection {
queryName := result.ScanResultData.QueryName
fileName := result.ScanResultData.Nodes[0].FileName
lineNumber := strconv.FormatUint(uint64(result.ScanResultData.Nodes[0].Line), 10)
startLine := result.ScanResultData.Nodes[0].Line
endLine := result.ScanResultData.Nodes[0].Line + result.ScanResultData.Nodes[0].Length

glSast.Vulnerabilities = append(glSast.Vulnerabilities, wrappers.GlVulnerabilities{
ID: queryName + ":" + fileName + ":" + lineNumber,
Category: wrappers.VendorName + "-" + result.Type,
Name: queryName,
Message: queryName + "@" + fileName + " : " + lineNumber,
Description: result.Description,
CVE: queryName + ":" + fileName + ":" + lineNumber,
Severity: result.Severity,
Confidence: result.Severity,
Solution: "",
Scanner: wrappers.GlScanner{
ID: wrappers.VendorName + "-" + result.Type,
Name: wrappers.VendorName + "-" + result.Type,
},
Links: nil,
Tracking: wrappers.Tracking{Items: wrappers.Item{
Signatures: wrappers.Signature{
Algorithm: result.Type + "-Algorithm ",
Value: "NA"},
File: fileName,
EndLine: endLine,
StartLine: startLine},
},
Flags: wrappers.Flag{
Type: "",
Origin: result.Type,
Description: result.Description,
},
Location: wrappers.Location{
File: fileName,
StartLine: startLine,
EndLine: endLine,
Class: fileName,
},
})
return glSast
}

func setConstValueGlReport(glSast *wrappers.GlSastResultsCollection) *wrappers.GlSastResultsCollection {
glSast.Schema = "https://gitlab.com/gitlab-org/gitlab/-/blob/8a42b7e8ab41ec2920f02fb4b36f244bbbb4bfb8/lib/gitlab/ci/parsers/security/validators/schemas/14.1.2/sast-report-format.json"
glSast.Version = "14.1.2"
glSast.Scan.Analyzer.URL = wrappers.AnalyzerURL
glSast.Scan.Analyzer.Name = wrappers.VendorName
glSast.Scan.Analyzer.Vendor.Name = wrappers.VendorName
glSast.Scan.Analyzer.ID = wrappers.AnalyzerID
glSast.Scan.Scanner.ID = wrappers.AnalyzerID
glSast.Scan.Scanner.Name = wrappers.VendorName
return glSast
}

func convertCxResultsToSonar(results *wrappers.ScanResultsCollection) *wrappers.ScanResultsSonar {
var sonar = new(wrappers.ScanResultsSonar)
Expand Down
30 changes: 30 additions & 0 deletions internal/commands/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,33 @@ func TestSBOMReportXMLWithProxy(t *testing.T) {
// Remove generated json file
os.Remove(fmt.Sprintf("%s.%s", fileName+"_"+printer.FormatSbom, printer.FormatXML))
}

func TestRunGetResultsByScanIdGLFormat(t *testing.T) {
execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "gl-sast")
// Run test for gl-sast
os.Remove(fmt.Sprintf("%s.%s", fileName, printer.FormatGL))
}

func TestGLReportJson(t *testing.T) {
execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "gl-sast")
_, err := os.Stat(fmt.Sprintf("%s.%s", fileName+"_"+printer.FormatSbom, printer.FormatJSON))
assert.NilError(t, err, "Report file should exist for extension "+printer.FormatJSON)
// Remove generated json file
os.Remove(fmt.Sprintf("%s.%s", fileName+"_"+printer.FormatSbom, printer.FormatGL))
}
func TestRunGetResultsGeneratingGLReporWithOptions(t *testing.T) {
cmd := createASTTestCommand()
err := executeTestCommand(cmd,
"results", "show",
"--report-format", "gl-sast",
"--scan-id", "MOCK",
"--output-name", fileName,
"--report-pdf-options", "Iac-Security,Sast,Sca,ScanSummary")
defer func() {
os.Remove(fmt.Sprintf("%s.%s", fileName, printer.FormatGL))
fmt.Println("test file removed!")
}()
assert.NilError(t, err)
_, err = os.Stat(fmt.Sprintf("%s.%s", fileName, printer.FormatGL))
assert.NilError(t, err, "report file should exist: "+fileName+printer.FormatGL)
}
1 change: 1 addition & 0 deletions internal/commands/util/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
FormatSummaryMarkdown = "markdown"
FormatSbom = "sbom"
FormatXML = "xml"
FormatGL = "gl-sast"
)

func Print(w io.Writer, view interface{}, format string) error {
Expand Down
111 changes: 111 additions & 0 deletions internal/wrappers/results-gl-sast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package wrappers

const (
AnalyzerName = "CxOne"
AnalyzerID = AnalyzerName + "-SAST"
AnalyzerURL = "https://checkmarx.company.com/"
VendorName = "Checkmarx"
)

type GlSastResultsCollection struct {
Scan ScanGlReport `json:"scan"`
Schema string `json:"schema"`
Version string `json:"version"`
Vulnerabilities []GlVulnerabilities `json:"vulnerabilities"`
}
type GlVulnerabilities struct {
ID string `json:"id"`
Category string `json:"category"`
Name string `json:"name"`
Message string `json:"message"`
Description string `json:"description"`
CVE string `json:"cve"`
Severity string `json:"severity"`
Confidence string `json:"confidence"`
Solution string `json:"solution"`
Scanner GlScanner `json:"scanner"`
Identifiers []Identifier `json:"identifiers"`
Links []string `json:"links"`
Tracking Tracking `json:"tracking"`
Flags Flag `json:"flags"`
Location Location `json:"location"`
}
type Identifier struct {
Type string `json:"type"`
Name string `json:"name"`
URL string `json:"url"`
Value string `json:"value"`
}
type Flag struct {
Type string `json:"type"`
Origin string `json:"origin"`
Description string `json:"description"`
}
type Location struct {
File string `json:"file"`
StartLine uint `json:"start_line"`
EndLine uint `json:"end_line"`
Class string `json:"class"`
}

type Tracking struct {
Items Item `json:"items"`
}
type Item struct {
Signatures Signature `json:"signatures"`
File string `json:"file"`
EndLine uint `json:"end_line"`
StartLine uint `json:"start_line"`
}
type Signature struct {
Algorithm string `json:"algorithm"`
Value string `json:"value"`
}
type ScanGlReport struct {
EndTime string `json:"end_time"`
Analyzer Analyzer `json:"analyzer"`
Scanner GlScanner `json:"scanner"`
StartTime string `json:"start_time"`
Status string `json:"status"`
Type string `json:"type"`
}

type Analyzer struct {
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
Vendor Vendor `json:"vendor"`
Version string `json:"version"`
}
type GlScanner struct {
ID string `json:"id"`
Name string `json:"name"`
}
type Vendor struct {
Name string `json:"name"`
}
type GLSastIdentifiers struct {
Type string `json:"type"`
Name string `json:"name"`
URL string `json:"url"`
Value string `json:"value"`
}
type GlSastTracking struct {
Items []GlSastTrackingItems `json:"items"`
}

type GlSastTrackingItems struct {
Signatures GlSastTrackingItemsSignatures `json:"signatures"`
File string `json:"file"`
EndLine string `json:"end_line"`
StartLine string `json:"start_line"`
}
type GlSastTrackingItemsSignatures struct {
Algorithm string `json:"algorithm"`
Value string `json:"value"`
}
type GlSastFlags struct {
Type string `json:"type"`
Origin string `json:"origin"`
Description string `json:"description"`
}
Loading