1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-18 05:18:24 +02:00

feat(checkmarxExecuteScan): improvements to SARIF file generation (#3781)

* feat(checkmarxExecuteScan): respect SARIF standard more closely

* fix(checkmarxExecuteScan): edge case where message would be empty in SARIF

* fix(checkmarxExecuteScan): better message handling to ensure field is populated

* feat(checkmarxExecuteScan): SARIF file readability

* feat(checkmarxExecuteScan): include the helpURL as part of the Help object

* fix(sarif): remove wrong structure addition

* feat(checkmarxExecuteScan): safer handling of version in SARIF file

* feat(checkmarxExecuteScan): add CWE number to tags
This commit is contained in:
xgoffin 2022-05-19 14:57:13 +02:00 committed by GitHub
parent 1d850c0acc
commit 1fde2ce677
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 18 deletions

View File

@ -149,7 +149,7 @@ func Parse(data []byte) (format.SARIF, error) {
checkmarxRun.ColumnKind = "utf16CodeUnits"
sarif.Runs = append(sarif.Runs, checkmarxRun)
rulesArray := []format.SarifRule{}
baseURL := "https://" + strings.Split(cxxml.DeepLink, "/")[2] + "CxWebClient/ScanQueryDescription.aspx?"
baseURL := "https://" + strings.Split(cxxml.DeepLink, "/")[2] + "/CxWebClient/ScanQueryDescription.aspx?"
cweIdsForTaxonomies := make(map[string]int) //use a map to avoid duplicates
cweCounter := 0
@ -165,15 +165,18 @@ func Parse(data []byte) (format.SARIF, error) {
result := *new(format.Results)
//General
result.RuleID = cxxml.Query[i].ID
result.RuleID = "checkmarx-" + cxxml.Query[i].ID
result.RuleIndex = cweIdsForTaxonomies[cxxml.Query[i].CweID]
result.Level = "none"
msg := new(format.Message)
msg.Text = cxxml.Query[i].Categories
//msg.Text = cxxml.Query[i].Name + ": " + cxxml.Query[i].Categories
msg.Text = cxxml.Query[i].Name
result.Message = msg
analysisTarget := new(format.ArtifactLocation)
analysisTarget.URI = cxxml.Query[i].Result[j].FileName
result.AnalysisTarget = analysisTarget
//analysisTarget := new(format.ArtifactLocation)
//analysisTarget.URI = cxxml.Query[i].Result[j].FileName
//analysisTarget.Index = index
//result.AnalysisTarget = analysisTarget
if cxxml.Query[i].Name != "" {
msg := new(format.Message)
msg.Text = cxxml.Query[i].Name
@ -181,14 +184,32 @@ func Parse(data []byte) (format.SARIF, error) {
//Locations
for k := 0; k < len(cxxml.Query[i].Result[j].Path.PathNode); k++ {
loc := *new(format.Location)
/*index := 0
//Check if that artifact has been added
added := false
for file := 0; file < len(sarif.Runs[0].Artifacts); file++ {
if sarif.Runs[0].Artifacts[file].Location.Uri == cxxml.Query[i].Result[j].FileName {
added = true
index = file
break
}
}
if !added {
artifact := format.Artifact{Location: format.SarifLocation{Uri: cxxml.Query[i].Result[j].FileName}}
sarif.Runs[0].Artifacts = append(sarif.Runs[0].Artifacts, artifact)
index = len(sarif.Runs[0].Artifacts) - 1
}
loc.PhysicalLocation.ArtifactLocation.Index = index */
loc.PhysicalLocation.ArtifactLocation.URI = cxxml.Query[i].Result[j].FileName
loc.PhysicalLocation.Region.StartLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line
loc.PhysicalLocation.Region.EndLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line
loc.PhysicalLocation.Region.StartColumn = cxxml.Query[i].Result[j].Path.PathNode[k].Column
snip := new(format.SnippetSarif)
snip.Text = cxxml.Query[i].Result[j].Path.PathNode[k].Snippet.Line.Code
loc.PhysicalLocation.Region.Snippet = snip
loc.PhysicalLocation.ContextRegion.StartLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line
loc.PhysicalLocation.ContextRegion.EndLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line
loc.PhysicalLocation.ContextRegion.Snippet = snip
//loc.PhysicalLocation.ContextRegion.StartLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line
//loc.PhysicalLocation.ContextRegion.EndLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line
//loc.PhysicalLocation.ContextRegion.Snippet = snip
result.Locations = append(result.Locations, loc)
//Related Locations
@ -203,6 +224,9 @@ func Parse(data []byte) (format.SARIF, error) {
}
result.PartialFingerprints.CheckmarxSimilarityID = cxxml.Query[i].Result[j].Path.SimilarityID
result.PartialFingerprints.PrimaryLocationLineHash = cxxml.Query[i].Result[j].Path.SimilarityID
//Properties
props := new(format.SarifProperties)
props.Audited = false
@ -258,9 +282,25 @@ func Parse(data []byte) (format.SARIF, error) {
//handle the rules array
rule := *new(format.SarifRule)
rule.ID = cxxml.Query[i].ID
rule.Name = cxxml.Query[i].Name
rule.ID = "checkmarx-" + cxxml.Query[i].ID
words := strings.Split(cxxml.Query[i].Name, "_")
for w := 0; w < len(words); w++ {
words[w] = strings.Title(strings.ToLower(words[w]))
}
rule.Name = strings.Join(words, "")
rule.HelpURI = baseURL + "queryID=" + cxxml.Query[i].ID + "&queryVersionCode=" + cxxml.Query[i].QueryVersionCode + "&queryTitle=" + cxxml.Query[i].Name
rule.Help = new(format.Help)
rule.Help.Text = rule.HelpURI
rule.ShortDescription = new(format.Message)
rule.ShortDescription.Text = cxxml.Query[i].Name
if cxxml.Query[i].Categories != "" {
rule.FullDescription = new(format.Message)
rule.FullDescription.Text = cxxml.Query[i].Categories
}
rule.Properties = new(format.SarifRuleProperties)
if cxxml.Query[i].CweID != "" {
rule.Properties.Tags = append(rule.Properties.Tags, "external/cwe/cwe-"+cxxml.Query[i].CweID)
}
rulesArray = append(rulesArray, rule)
}
@ -269,7 +309,13 @@ func Parse(data []byte) (format.SARIF, error) {
tool := *new(format.Tool)
tool.Driver = *new(format.Driver)
tool.Driver.Name = "Checkmarx SCA"
tool.Driver.Version = cxxml.CheckmarxVersion
versionData := strings.Split(cxxml.CheckmarxVersion, "V ")
if len(versionData) > 1 { // Safety check
tool.Driver.Version = strings.Split(cxxml.CheckmarxVersion, "V ")[1]
} else {
tool.Driver.Version = cxxml.CheckmarxVersion // Safe case
}
tool.Driver.InformationUri = "https://checkmarx.atlassian.net/wiki/spaces/KC/pages/1170245301/Navigating+Scan+Results+v9.0.0+to+v9.2.0"
tool.Driver.Rules = rulesArray
sarif.Runs[0].Tool = tool

View File

@ -11,7 +11,7 @@ func TestParse(t *testing.T) {
//Use a test CXXML doc
testCxxml := `
<?xml version="1.0" encoding="utf-8"?>
<CxXMLResults InitiatorName="Test" Owner="Tester" ScanId="1111111" ProjectId="11037" ProjectName="test-project" TeamFullPathOnReportDate="CxServer" DeepLink="https://cxtext.test/CxWebClient/ViewerMain.aspx?scanid=1111111&amp;projectid=11037" ScanStart="Monday, March 7, 2022 1:58:49 PM" Preset="Checkmarx Default" ScanTime="00h:00m:22s" LinesOfCodeScanned="2682" FilesScanned="15" ReportCreationTime="Monday, March 7, 2022 1:59:25 PM" Team="SecurityTesting" CheckmarxVersion="9.4.3" ScanComments="Scan From Golang Script" ScanType="Incremental" SourceOrigin="LocalPath" Visibility="Public">
<CxXMLResults InitiatorName="Test" Owner="Tester" ScanId="1111111" ProjectId="11037" ProjectName="test-project" TeamFullPathOnReportDate="CxServer" DeepLink="https://cxtext.test/CxWebClient/ViewerMain.aspx?scanid=1111111&amp;projectid=11037" ScanStart="Monday, March 7, 2022 1:58:49 PM" Preset="Checkmarx Default" ScanTime="00h:00m:22s" LinesOfCodeScanned="2682" FilesScanned="15" ReportCreationTime="Monday, March 7, 2022 1:59:25 PM" Team="SecurityTesting" CheckmarxVersion="V 9.4.3" ScanComments="Scan From Golang Script" ScanType="Incremental" SourceOrigin="LocalPath" Visibility="Public">
<Query id="2415" categories="Dummy Categories" cweId="79" name="Dummy Vuln 1" group="JavaScript_High_Risk" Severity="High" Language="JavaScript" LanguageHash="9095271965336651" LanguageChangeDate="2022-01-16T00:00:00.0000000" SeverityIndex="3" QueryPath="JavaScript\Cx\JavaScript High Risk\Dummy Vuln 1:4" QueryVersionCode="14383421">
<Result NodeId="143834211111" FileName="test/any.ts" Status="Recurrent" Line="7" Column="46" FalsePositive="False" Severity="High" AssignToUser="" state="0" Remark="" DeepLink="https://cxtext.test/CxWebClient/ViewerMain.aspx?" SeverityIndex="3" StatusIndex="1" DetectionDate="3/7/2022 12:21:30 PM">
<Path ResultId="11037" PathId="4" SimilarityId="-1754124988" SourceMethod="function" DestinationMethod="function">

View File

@ -56,8 +56,8 @@ type PhysicalLocation struct {
// ArtifactLocation describing the path of the artifact
type ArtifactLocation struct {
URI string `json:"uri"`
URIBaseId string `json:"uriBaseId"`
Index int `json:"index"`
URIBaseId string `json:"uriBaseId,omitempty"`
Index int `json:"index,omitempty"`
}
// Region where the finding was detected
@ -265,9 +265,9 @@ type SrcRoot struct {
// Artifact These structs are relevant to the artifacts object
type Artifact struct {
Location SarifLocation `json:"location"`
Length int `json:"length"`
MimeType string `json:"mimeType"`
Encoding string `json:"encoding"`
Length int `json:"length,omitempty"`
MimeType string `json:"mimeType,omitempty"`
Encoding string `json:"encoding,omitempty"`
}
// SarifLocation