1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-09-16 09:26:22 +02:00

feat(fortifyExecuteScan): implement a system to limit the number of API calls upon request failures (#3818)

* feat(fortifyExecuteScan): add a max number of retries for API calls in SARIF conversion

* feat(checkmarxExecuteScan): implement max number of retries on API call for descriptions in SARIF processing

* feat(checkmarx/fortify): extra logging line when failing an API request in SARIF conversion

* fix(fortifyExecuteScan): panic if undefined projectversion in sarif

* fix(fortifyExecuteScan): logging improvement

* fix(fortifyExecuteScan): wrong if condition caused crash

* fix(fortifyExecuteScan): do not log if retries hit -1, adjust logging

* fix(SARIF): commenting API calls for Checkmarx until a solution can be found for the API issues

* feat(SARIF): add omitempty to extensions
This commit is contained in:
xgoffin
2022-06-09 10:32:08 +02:00
committed by GitHub
parent 92837fde18
commit 5edb0d2566
5 changed files with 80 additions and 57 deletions

View File

@@ -153,32 +153,40 @@ func Parse(sys System, data []byte, scanID int) (format.SARIF, error) {
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 cweIdsForTaxonomies := make(map[string]int) //use a map to avoid duplicates
cweCounter := 0 cweCounter := 0
var apiDescription string //maxretries := 5
//CxXML files contain a CxXMLResults > Query object, which represents a broken rule or type of vuln //CxXML files contain a CxXMLResults > Query object, which represents a broken rule or type of vuln
//This Query object contains a list of Result objects, each representing an occurence //This Query object contains a list of Result objects, each representing an occurence
//Each Result object contains a ResultPath, which represents the exact location of the occurence (the "Snippet") //Each Result object contains a ResultPath, which represents the exact location of the occurence (the "Snippet")
log.Entry().Debug("[SARIF] Now handling results.") log.Entry().Debug("[SARIF] Now handling results.")
for i := 0; i < len(cxxml.Query); i++ { for i := 0; i < len(cxxml.Query); i++ {
descriptionFetched := false
//add cweid to array //add cweid to array
cweIdsForTaxonomies[cxxml.Query[i].CweID] = cweCounter cweIdsForTaxonomies[cxxml.Query[i].CweID] = cweCounter
cweCounter = cweCounter + 1 cweCounter = cweCounter + 1
for j := 0; j < len(cxxml.Query[i].Result); j++ { for j := 0; j < len(cxxml.Query[i].Result); j++ {
var apiDescription string
result := *new(format.Results) result := *new(format.Results)
// COMMENTED UNTIL CHECKMARX API WORK AS INTENDED
// For rules later, fetch description // For rules later, fetch description
if !descriptionFetched { /*if maxretries == 0 { // Don't spam logfile: only enter the loop if maxretries is positive, and only display the error if it hits 0
log.Entry().Error("request failed: maximum number of retries reached, descriptions will no longer be fetched")
maxretries = maxretries - 1
} else if maxretries > 0 {
if sys != nil { if sys != nil {
apiShortDescription, err := sys.GetShortDescription(scanID, cxxml.Query[i].Result[j].Path.PathID) apiShortDescription, err := sys.GetShortDescription(scanID, cxxml.Query[i].Result[j].Path.PathID)
if err != nil { if err != nil {
maxretries = maxretries - 1
log.Entry().Debug("request failed: remaining retries ", maxretries)
log.Entry().Error(err) log.Entry().Error(err)
} else { } else {
descriptionFetched = true
apiDescription = apiShortDescription.Text apiDescription = apiShortDescription.Text
} }
} else {
maxretries = maxretries - 1
log.Entry().Debug("request failed: no system instance, remaining retries ", maxretries)
} }
} }*/
//General //General
result.RuleID = "checkmarx-" + cxxml.Query[i].ID result.RuleID = "checkmarx-" + cxxml.Query[i].ID
@@ -186,13 +194,13 @@ func Parse(sys System, data []byte, scanID int) (format.SARIF, error) {
result.Level = "none" result.Level = "none"
msg := new(format.Message) msg := new(format.Message)
//msg.Text = cxxml.Query[i].Name + ": " + cxxml.Query[i].Categories //msg.Text = cxxml.Query[i].Name + ": " + cxxml.Query[i].Categories
msg.Text = cxxml.Query[i].Name if apiDescription != "" {
msg.Text = apiDescription
} else {
msg.Text = cxxml.Query[i].Name
}
result.Message = msg result.Message = msg
//analysisTarget := new(format.ArtifactLocation)
//analysisTarget.URI = cxxml.Query[i].Result[j].FileName
//analysisTarget.Index = index
//result.AnalysisTarget = analysisTarget
if cxxml.Query[i].Name != "" { if cxxml.Query[i].Name != "" {
msg := new(format.Message) msg := new(format.Message)
msg.Text = cxxml.Query[i].Name msg.Text = cxxml.Query[i].Name
@@ -200,22 +208,6 @@ func Parse(sys System, data []byte, scanID int) (format.SARIF, error) {
//Locations //Locations
for k := 0; k < len(cxxml.Query[i].Result[j].Path.PathNode); k++ { for k := 0; k < len(cxxml.Query[i].Result[j].Path.PathNode); k++ {
loc := *new(format.Location) 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.ArtifactLocation.URI = cxxml.Query[i].Result[j].FileName
loc.PhysicalLocation.Region.StartLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line 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.EndLine = cxxml.Query[i].Result[j].Path.PathNode[k].Line
@@ -223,9 +215,6 @@ func Parse(sys System, data []byte, scanID int) (format.SARIF, error) {
snip := new(format.SnippetSarif) snip := new(format.SnippetSarif)
snip.Text = cxxml.Query[i].Result[j].Path.PathNode[k].Snippet.Line.Code snip.Text = cxxml.Query[i].Result[j].Path.PathNode[k].Snippet.Line.Code
loc.PhysicalLocation.Region.Snippet = snip 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
result.Locations = append(result.Locations, loc) result.Locations = append(result.Locations, loc)
//Related Locations //Related Locations
@@ -309,14 +298,21 @@ func Parse(sys System, data []byte, scanID int) (format.SARIF, error) {
rule.Help.Text = rule.HelpURI rule.Help.Text = rule.HelpURI
rule.ShortDescription = new(format.Message) rule.ShortDescription = new(format.Message)
rule.ShortDescription.Text = cxxml.Query[i].Name rule.ShortDescription.Text = cxxml.Query[i].Name
if apiDescription != "" { rule.Properties = new(format.SarifRuleProperties)
/*if apiDescription != "" {
rule.FullDescription = new(format.Message) rule.FullDescription = new(format.Message)
rule.FullDescription.Text = apiDescription rule.FullDescription.Text = apiDescription
} else if cxxml.Query[i].Categories != "" { } else */if cxxml.Query[i].Categories != "" {
rule.FullDescription = new(format.Message) rule.FullDescription = new(format.Message)
rule.FullDescription.Text = cxxml.Query[i].Categories rule.FullDescription.Text = cxxml.Query[i].Categories
//split categories on ;
cats := strings.Split(cxxml.Query[i].Categories, ";")
for cat := 0; cat < len(cats); cat++ {
rule.Properties.Tags = append(rule.Properties.Tags, cats[cat])
}
} }
rule.Properties = new(format.SarifRuleProperties)
if cxxml.Query[i].CweID != "" { if cxxml.Query[i].CweID != "" {
rule.Properties.Tags = append(rule.Properties.Tags, "external/cwe/cwe-"+cxxml.Query[i].CweID) rule.Properties.Tags = append(rule.Properties.Tags, "external/cwe/cwe-"+cxxml.Query[i].CweID)
} }

View File

@@ -121,7 +121,7 @@ func TestParse(t *testing.T) {
assert.Equal(t, len(sarif.Runs[0].Tool.Driver.Rules), 2) assert.Equal(t, len(sarif.Runs[0].Tool.Driver.Rules), 2)
assert.Equal(t, sarif.Runs[0].Results[2].Properties.ToolState, "Confirmed") assert.Equal(t, sarif.Runs[0].Results[2].Properties.ToolState, "Confirmed")
assert.Equal(t, sarif.Runs[0].Results[2].Properties.ToolAuditMessage, "Changed status to Confirmed \n Dummy comment") assert.Equal(t, sarif.Runs[0].Results[2].Properties.ToolAuditMessage, "Changed status to Confirmed \n Dummy comment")
assert.Equal(t, "This is a dummy short description.", sarif.Runs[0].Tool.Driver.Rules[0].FullDescription.Text) //assert.Equal(t, "This is a dummy short description.", sarif.Runs[0].Tool.Driver.Rules[0].FullDescription.Text)
}) })
t.Run("Missing sys", func(t *testing.T) { t.Run("Missing sys", func(t *testing.T) {

View File

@@ -103,7 +103,7 @@ type SarifProperties struct {
// Tool these structs are relevant to the Tool object // Tool these structs are relevant to the Tool object
type Tool struct { type Tool struct {
Driver Driver `json:"driver"` Driver Driver `json:"driver"`
Extensions []Driver `json:"extensions"` Extensions []Driver `json:"extensions,omitempty"`
} }
// Driver meta information for the scan and tool context // Driver meta information for the scan and tool context

View File

@@ -542,17 +542,21 @@ func Parse(sys System, project *models.Project, projectVersion *models.ProjectVe
log.Entry().Debug("Querying Fortify SSC for batch audit data") log.Entry().Debug("Querying Fortify SSC for batch audit data")
oneRequestPerIssueMode := false oneRequestPerIssueMode := false
var auditData []*models.ProjectVersionIssue var auditData []*models.ProjectVersionIssue
if sys != nil { maxretries := 5 // Maximum number of requests allowed to fail before stopping them
if sys != nil && projectVersion != nil {
auditData, err = sys.GetAllIssueDetails(projectVersion.ID) auditData, err = sys.GetAllIssueDetails(projectVersion.ID)
if err != nil { if err != nil || len(auditData) == 0 { // It's reasonable to admit that with a length of 0, something went wrong
log.Entry().WithError(err).Error("failed to get all audit data, defaulting to one-request-per-issue basis") log.Entry().WithError(err).Error("failed to get all audit data, defaulting to one-request-per-issue basis")
oneRequestPerIssueMode = true oneRequestPerIssueMode = true
// We do not lower maxretries here in case a "real" bug happened
} else { } else {
log.Entry().Debug("Request successful, data frame size: ", len(auditData), " audits") log.Entry().Debug("Request successful, data frame size: ", len(auditData), " audits")
} }
} else { } else {
log.Entry().Error("no system instance found, lookup impossible") log.Entry().Error("no system instance or project version found, lookup impossible")
oneRequestPerIssueMode = true oneRequestPerIssueMode = true
maxretries = 1 // Set to 1 if the sys instance isn't defined: chances are it couldn't be created, we'll live a chance if there was an unknown bug
log.Entry().Debug("request failed: remaining retries ", maxretries)
} }
//Now, we handle the sarif //Now, we handle the sarif
@@ -785,17 +789,12 @@ func Parse(sys System, project *models.Project, projectVersion *models.ProjectVe
prop.Confidence = fvdl.Vulnerabilities.Vulnerability[i].InstanceInfo.Confidence prop.Confidence = fvdl.Vulnerabilities.Vulnerability[i].InstanceInfo.Confidence
prop.InstanceID = fvdl.Vulnerabilities.Vulnerability[i].InstanceInfo.InstanceID prop.InstanceID = fvdl.Vulnerabilities.Vulnerability[i].InstanceInfo.InstanceID
//Get the audit data //Get the audit data
if sys != nil { if err := integrateAuditData(prop, fvdl.Vulnerabilities.Vulnerability[i].InstanceInfo.InstanceID, sys, project, projectVersion, auditData, filterSet, oneRequestPerIssueMode, maxretries); err != nil {
if err := integrateAuditData(prop, fvdl.Vulnerabilities.Vulnerability[i].InstanceInfo.InstanceID, sys, project, projectVersion, auditData, filterSet, oneRequestPerIssueMode); err != nil { log.Entry().Debug(err)
log.Entry().Debug(err) maxretries = maxretries - 1
prop.Audited = false if maxretries >= 0 {
prop.ToolState = "Unknown" log.Entry().Debug("request failed: remaining retries ", maxretries)
prop.ToolAuditMessage = "Error fetching audit state"
} }
} else {
prop.Audited = false
prop.ToolState = "Unknown"
prop.ToolAuditMessage = "Cannot fetch audit state"
} }
result.Properties = prop result.Properties = prop
@@ -1157,16 +1156,25 @@ func Parse(sys System, project *models.Project, projectVersion *models.ProjectVe
return sarif, nil return sarif, nil
} }
func integrateAuditData(ruleProp *format.SarifProperties, issueInstanceID string, sys System, project *models.Project, projectVersion *models.ProjectVersion, auditData []*models.ProjectVersionIssue, filterSet *models.FilterSet, oneRequestPerIssue bool) error { func integrateAuditData(ruleProp *format.SarifProperties, issueInstanceID string, sys System, project *models.Project, projectVersion *models.ProjectVersion, auditData []*models.ProjectVersionIssue, filterSet *models.FilterSet, oneRequestPerIssue bool, maxretries int) error {
// Set default values // Set default values
ruleProp.Audited = false ruleProp.Audited = false
ruleProp.FortifyCategory = "Unknown" ruleProp.FortifyCategory = "Unknown"
ruleProp.ToolSeverity = "Unknown" ruleProp.ToolSeverity = "Unknown"
ruleProp.ToolState = "Unreviewed" ruleProp.ToolState = "Unknown"
ruleProp.ToolAuditMessage = "Error fetching audit state" // We set this as default for the error phase, then reset it to nothing
ruleProp.ToolSeverityIndex = 0 ruleProp.ToolSeverityIndex = 0
ruleProp.ToolStateIndex = 0 ruleProp.ToolStateIndex = 0
// These default values allow for the property bag to be filled even if an error happens later. They all should be overwritten by a normal course of the progrma. // These default values allow for the property bag to be filled even if an error happens later. They all should be overwritten by a normal course of the progrma.
if maxretries == 0 {
// Max retries reached, we stop there to avoid a longer execution time
err := errors.New("request failed: maximum number of retries reached, placeholder values will be set from now on for audit data")
return err
} else if maxretries < 0 {
return nil // Avoid spamming logfile
}
if sys == nil { if sys == nil {
ruleProp.ToolAuditMessage = "Cannot fetch audit state: no sys instance"
err := errors.New("no system instance, lookup impossible for " + issueInstanceID) err := errors.New("no system instance, lookup impossible for " + issueInstanceID)
return err return err
} }
@@ -1174,6 +1182,8 @@ func integrateAuditData(ruleProp *format.SarifProperties, issueInstanceID string
err := errors.New("project or projectVersion is undefined: lookup aborted for " + issueInstanceID) err := errors.New("project or projectVersion is undefined: lookup aborted for " + issueInstanceID)
return err return err
} }
// Reset the audit message
ruleProp.ToolAuditMessage = ""
var data []*models.ProjectVersionIssue var data []*models.ProjectVersionIssue
var err error var err error
if oneRequestPerIssue { if oneRequestPerIssue {

View File

@@ -385,7 +385,7 @@ If you are concerned about leaking system data via NFC on an Android device, you
assert.Equal(t, len(sarif.Runs[0].Results), 2) assert.Equal(t, len(sarif.Runs[0].Results), 2)
assert.Equal(t, len(sarif.Runs[0].Tool.Driver.Rules), 1) assert.Equal(t, len(sarif.Runs[0].Tool.Driver.Rules), 1)
assert.Equal(t, sarif.Runs[0].Results[0].Properties.ToolState, "Unknown") assert.Equal(t, sarif.Runs[0].Results[0].Properties.ToolState, "Unknown")
assert.Equal(t, sarif.Runs[0].Results[0].Properties.ToolAuditMessage, "Cannot fetch audit state") assert.Equal(t, sarif.Runs[0].Results[0].Properties.ToolAuditMessage, "Cannot fetch audit state: no sys instance")
}) })
} }
@@ -441,7 +441,7 @@ func TestIntegrateAuditData(t *testing.T) {
project := models.Project{} project := models.Project{}
projectVersion := models.ProjectVersion{ID: 11037} projectVersion := models.ProjectVersion{ID: 11037}
auditData, _ := sys.GetAllIssueDetails(projectVersion.ID) auditData, _ := sys.GetAllIssueDetails(projectVersion.ID)
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, auditData, filterSet, false) err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, auditData, filterSet, false, 5)
assert.NoError(t, err, "error") assert.NoError(t, err, "error")
assert.Equal(t, ruleProp.Audited, true) assert.Equal(t, ruleProp.Audited, true)
assert.Equal(t, ruleProp.ToolState, "Exploitable") assert.Equal(t, ruleProp.ToolState, "Exploitable")
@@ -456,7 +456,7 @@ func TestIntegrateAuditData(t *testing.T) {
ruleProp := *new(format.SarifProperties) ruleProp := *new(format.SarifProperties)
projectVersion := models.ProjectVersion{ID: 11037} projectVersion := models.ProjectVersion{ID: 11037}
auditData, _ := sys.GetAllIssueDetails(projectVersion.ID) auditData, _ := sys.GetAllIssueDetails(projectVersion.ID)
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, nil, &projectVersion, auditData, filterSet, false) err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, nil, &projectVersion, auditData, filterSet, false, 5)
assert.Error(t, err, "project or projectVersion is undefined: lookup aborted for 11037") assert.Error(t, err, "project or projectVersion is undefined: lookup aborted for 11037")
}) })
@@ -464,7 +464,7 @@ func TestIntegrateAuditData(t *testing.T) {
ruleProp := *new(format.SarifProperties) ruleProp := *new(format.SarifProperties)
project := models.Project{} project := models.Project{}
auditData, _ := sys.GetAllIssueDetails(11037) auditData, _ := sys.GetAllIssueDetails(11037)
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, nil, auditData, filterSet, false) err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, nil, auditData, filterSet, false, 5)
assert.Error(t, err, "project or projectVersion is undefined: lookup aborted for 11037") assert.Error(t, err, "project or projectVersion is undefined: lookup aborted for 11037")
}) })
@@ -473,7 +473,7 @@ func TestIntegrateAuditData(t *testing.T) {
project := models.Project{} project := models.Project{}
projectVersion := models.ProjectVersion{ID: 11037} projectVersion := models.ProjectVersion{ID: 11037}
auditData, _ := sys.GetAllIssueDetails(projectVersion.ID) auditData, _ := sys.GetAllIssueDetails(projectVersion.ID)
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", nil, &project, &projectVersion, auditData, filterSet, false) err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", nil, &project, &projectVersion, auditData, filterSet, false, 5)
assert.Error(t, err, "no system instance, lookup impossible for DUMMYDUMMYDUMMY") assert.Error(t, err, "no system instance, lookup impossible for DUMMYDUMMYDUMMY")
}) })
@@ -482,7 +482,7 @@ func TestIntegrateAuditData(t *testing.T) {
project := models.Project{} project := models.Project{}
projectVersion := models.ProjectVersion{ID: 11037} projectVersion := models.ProjectVersion{ID: 11037}
auditData, _ := sys.GetAllIssueDetails(projectVersion.ID) auditData, _ := sys.GetAllIssueDetails(projectVersion.ID)
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, auditData, nil, false) err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, auditData, nil, false, 5)
assert.Error(t, err, "no filter set defined, category will be missing from 11037") assert.Error(t, err, "no filter set defined, category will be missing from 11037")
}) })
@@ -490,7 +490,7 @@ func TestIntegrateAuditData(t *testing.T) {
ruleProp := *new(format.SarifProperties) ruleProp := *new(format.SarifProperties)
project := models.Project{} project := models.Project{}
projectVersion := models.ProjectVersion{ID: 11037} projectVersion := models.ProjectVersion{ID: 11037}
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, nil, filterSet, false) err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, nil, filterSet, false, 5)
assert.Error(t, err, "not exactly 1 issue found for instance ID 11037, found 0") assert.Error(t, err, "not exactly 1 issue found for instance ID 11037, found 0")
}) })
@@ -498,7 +498,7 @@ func TestIntegrateAuditData(t *testing.T) {
ruleProp := *new(format.SarifProperties) ruleProp := *new(format.SarifProperties)
project := models.Project{} project := models.Project{}
projectVersion := models.ProjectVersion{ID: 11037} projectVersion := models.ProjectVersion{ID: 11037}
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, nil, filterSet, true) err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, nil, filterSet, true, 5)
assert.NoError(t, err, "error") assert.NoError(t, err, "error")
assert.Equal(t, ruleProp.Audited, true) assert.Equal(t, ruleProp.Audited, true)
assert.Equal(t, ruleProp.ToolState, "Exploitable") assert.Equal(t, ruleProp.ToolState, "Exploitable")
@@ -509,4 +509,21 @@ func TestIntegrateAuditData(t *testing.T) {
assert.Equal(t, ruleProp.FortifyCategory, "Audit All") assert.Equal(t, ruleProp.FortifyCategory, "Audit All")
}) })
t.Run("Max retries set to 0: error raised", func(t *testing.T) {
ruleProp := *new(format.SarifProperties)
project := models.Project{}
projectVersion := models.ProjectVersion{ID: 11037}
auditData, _ := sys.GetAllIssueDetails(11037)
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, auditData, filterSet, false, 0)
assert.Error(t, err, "request failed: maximum number of retries reached, placeholder values will be set from now on for audit data")
})
t.Run("Max retries set to -1: fail silently", func(t *testing.T) {
ruleProp := *new(format.SarifProperties)
project := models.Project{}
projectVersion := models.ProjectVersion{ID: 11037}
auditData, _ := sys.GetAllIssueDetails(11037)
err := integrateAuditData(&ruleProp, "DUMMYDUMMYDUMMY", sys, &project, &projectVersion, auditData, filterSet, false, -1)
assert.NoError(t, err)
})
} }