From c11110d79112c96cd20bd47796691866c9245b52 Mon Sep 17 00:00:00 2001 From: xgoffin <86716549+xgoffin@users.noreply.github.com> Date: Thu, 16 Jun 2022 15:24:23 +0200 Subject: [PATCH] feat(sarif): add a "conversion" object to SARIF files (#3837) * feat(fortifyExecuteScan): add conversion object * feat(checkmarxExecuteScan): add conversion object --- pkg/checkmarx/cxxml_to_sarif.go | 13 +++++++++++++ pkg/format/sarif.go | 27 +++++++++++++++++---------- pkg/fortify/fpr_to_sarif.go | 22 ++++++++++++++++++++-- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/pkg/checkmarx/cxxml_to_sarif.go b/pkg/checkmarx/cxxml_to_sarif.go index 63ab00231..025392dcc 100644 --- a/pkg/checkmarx/cxxml_to_sarif.go +++ b/pkg/checkmarx/cxxml_to_sarif.go @@ -3,9 +3,11 @@ package checkmarx import ( "bytes" "encoding/xml" + "fmt" "io/ioutil" "strconv" "strings" + "time" "github.com/SAP/jenkins-library/pkg/format" "github.com/SAP/jenkins-library/pkg/log" @@ -136,6 +138,8 @@ func Parse(sys System, data []byte, scanID int) (format.SARIF, error) { reader := bytes.NewReader(data) decoder := xml.NewDecoder(reader) + start := time.Now() // For the conversion start time + var cxxml CxXMLResults err := decoder.Decode(&cxxml) if err != nil { @@ -350,5 +354,14 @@ func Parse(sys System, data []byte, scanID int) (format.SARIF, error) { } sarif.Runs[0].Taxonomies = append(sarif.Runs[0].Taxonomies, taxonomy) + // Add a conversion object to highlight this isn't native SARIF + conversion := new(format.Conversion) + conversion.Tool.Driver.Name = "Piper Checkmarx XML to SARIF converter" + conversion.Tool.Driver.InformationUri = "https://github.com/SAP/jenkins-library" + conversion.Invocation.ExecutionSuccessful = true + conversion.Invocation.StartTimeUtc = fmt.Sprintf("%s", start.Format("2006-01-02T15:04:05.000Z")) // "YYYY-MM-DDThh:mm:ss.sZ" on 2006-01-02 15:04:05 + conversion.Invocation.Account = cxxml.InitiatorName + sarif.Runs[0].Conversion = conversion + return sarif, nil } diff --git a/pkg/format/sarif.go b/pkg/format/sarif.go index f47f0d00a..42d726706 100644 --- a/pkg/format/sarif.go +++ b/pkg/format/sarif.go @@ -11,13 +11,14 @@ type SARIF struct { type Runs struct { Results []Results `json:"results"` Tool Tool `json:"tool"` - Invocations []Invocations `json:"invocations,omitempty"` + Invocations []Invocation `json:"invocations,omitempty"` OriginalUriBaseIds *OriginalUriBaseIds `json:"originalUriBaseIds,omitempty"` Artifacts []Artifact `json:"artifacts,omitempty"` AutomationDetails AutomationDetails `json:"automationDetails,omitempty"` ColumnKind string `json:"columnKind,omitempty" default:"utf16CodeUnits"` ThreadFlowLocations []Locations `json:"threadFlowLocations,omitempty"` Taxonomies []Taxonomies `json:"taxonomies,omitempty"` + Conversion *Conversion `json:"conversion,omitempty"` } // Results these structs are relevant to the Results object @@ -109,7 +110,7 @@ type Tool struct { // Driver meta information for the scan and tool context type Driver struct { Name string `json:"name"` - Version string `json:"version"` + Version string `json:"version,omitempty"` GUID string `json:"guid,omitempty"` InformationUri string `json:"informationUri,omitempty"` Rules []SarifRule `json:"rules,omitempty"` @@ -231,15 +232,15 @@ type SarifRuleProperties struct { SecuritySeverity string `json:"security-severity,omitempty"` //used by GHAS to defined the tag (low,medium,high) } -// Invocations These structs are relevant to the Invocations object -type Invocations struct { - CommandLine string `json:"commandLine"` - StartTimeUtc string `json:"startTimeUtc"` - ToolExecutionNotifications []ToolExecutionNotifications `json:"toolExecutionNotifications"` +// Invocation These structs are relevant to the Invocation object +type Invocation struct { + CommandLine string `json:"commandLine,omitempty"` + StartTimeUtc string `json:"startTimeUtc,omitempty"` + ToolExecutionNotifications []ToolExecutionNotifications `json:"toolExecutionNotifications,omitempty"` ExecutionSuccessful bool `json:"executionSuccessful"` - Machine string `json:"machine"` - Account string `json:"account"` - Properties InvocationProperties `json:"properties"` + Machine string `json:"machine,omitempty"` + Account string `json:"account,omitempty"` + Properties *InvocationProperties `json:"properties,omitempty"` } // ToolExecutionNotifications @@ -302,3 +303,9 @@ type Taxonomies struct { type Taxa struct { Id string `json:"id"` } + +// Conversion object +type Conversion struct { + Tool Tool `json:"tool,omitempty"` + Invocation Invocation `json:"invocation,omitempty"` +} diff --git a/pkg/fortify/fpr_to_sarif.go b/pkg/fortify/fpr_to_sarif.go index 8993ebd36..41e313ddb 100644 --- a/pkg/fortify/fpr_to_sarif.go +++ b/pkg/fortify/fpr_to_sarif.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strconv" "strings" + "time" "github.com/piper-validation/fortify-client-go/models" @@ -532,6 +533,8 @@ func Parse(sys System, project *models.Project, projectVersion *models.ProjectVe reader := bytes.NewReader(data) decoder := xml.NewDecoder(reader) + start := time.Now() // For the conversion start time + var fvdl FVDL err := decoder.Decode(&fvdl) if err != nil { @@ -990,7 +993,7 @@ func Parse(sys System, project *models.Project, projectVersion *models.ProjectVe //handle invocations object log.Entry().Debug("[SARIF] Now handling invocation.") - invocation := *new(format.Invocations) + invocation := *new(format.Invocation) for i := 0; i < len(fvdl.EngineData.Properties); i++ { //i selects the properties type if fvdl.EngineData.Properties[i].PropertiesType == "Fortify" { // This is the correct type, now iterate on props for j := 0; j < len(fvdl.EngineData.Properties[i].Property); j++ { @@ -1014,7 +1017,9 @@ func Parse(sys System, project *models.Project, projectVersion *models.ProjectVe invocation.ExecutionSuccessful = true //fvdl doesn't seem to plan for this setting invocation.Machine = fvdl.EngineData.MachineInfo.Hostname invocation.Account = fvdl.EngineData.MachineInfo.Username - invocation.Properties.Platform = fvdl.EngineData.MachineInfo.Platform + invocProp := new(format.InvocationProperties) + invocProp.Platform = fvdl.EngineData.MachineInfo.Platform + invocation.Properties = invocProp sarif.Runs[0].Invocations = append(sarif.Runs[0].Invocations, invocation) //handle originalUriBaseIds @@ -1139,6 +1144,19 @@ func Parse(sys System, project *models.Project, projectVersion *models.ProjectVe // Threadflowlocations is no loger useful: voiding it will make for smaller reports sarif.Runs[0].ThreadFlowLocations = []format.Locations{} + // Add a conversion object to highlight this isn't native SARIF + conversion := new(format.Conversion) + conversion.Tool.Driver.Name = "Piper FPR to SARIF converter" + conversion.Tool.Driver.InformationUri = "https://github.com/SAP/jenkins-library" + conversion.Invocation.ExecutionSuccessful = true + conversion.Invocation.StartTimeUtc = fmt.Sprintf("%s", start.Format("2006-01-02T15:04:05.000Z")) // "YYYY-MM-DDThh:mm:ss.sZ" on 2006-01-02 15:04:05 + conversion.Invocation.Machine = fvdl.EngineData.MachineInfo.Hostname + conversion.Invocation.Account = fvdl.EngineData.MachineInfo.Username + convInvocProp := new(format.InvocationProperties) + convInvocProp.Platform = fvdl.EngineData.MachineInfo.Platform + conversion.Invocation.Properties = convInvocProp + sarif.Runs[0].Conversion = conversion + //handle taxonomies //Only one exists apparently: CWE. It is fixed taxonomy := *new(format.Taxonomies)