github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/cmd/checkmarxOneExecuteScan.go (about) 1 package cmd 2 3 import ( 4 "archive/zip" 5 "context" 6 "fmt" 7 "io" 8 "math" 9 "os" 10 "path/filepath" 11 "regexp" 12 "sort" 13 "strconv" 14 "strings" 15 "time" 16 17 checkmarxOne "github.com/SAP/jenkins-library/pkg/checkmarxone" 18 piperGithub "github.com/SAP/jenkins-library/pkg/github" 19 piperHttp "github.com/SAP/jenkins-library/pkg/http" 20 "github.com/SAP/jenkins-library/pkg/log" 21 "github.com/SAP/jenkins-library/pkg/piperutils" 22 "github.com/SAP/jenkins-library/pkg/reporting" 23 "github.com/SAP/jenkins-library/pkg/telemetry" 24 "github.com/SAP/jenkins-library/pkg/toolrecord" 25 "github.com/bmatcuk/doublestar" 26 "github.com/google/go-github/v45/github" 27 "github.com/pkg/errors" 28 ) 29 30 type checkmarxOneExecuteScanUtils interface { 31 FileInfoHeader(fi os.FileInfo) (*zip.FileHeader, error) 32 Stat(name string) (os.FileInfo, error) 33 Open(name string) (*os.File, error) 34 WriteFile(filename string, data []byte, perm os.FileMode) error 35 MkdirAll(path string, perm os.FileMode) error 36 PathMatch(pattern, name string) (bool, error) 37 GetWorkspace() string 38 GetIssueService() *github.IssuesService 39 GetSearchService() *github.SearchService 40 } 41 42 type checkmarxOneExecuteScanHelper struct { 43 ctx context.Context 44 config checkmarxOneExecuteScanOptions 45 sys checkmarxOne.System 46 influx *checkmarxOneExecuteScanInflux 47 utils checkmarxOneExecuteScanUtils 48 Project *checkmarxOne.Project 49 Group *checkmarxOne.Group 50 App *checkmarxOne.Application 51 reports []piperutils.Path 52 } 53 54 type checkmarxOneExecuteScanUtilsBundle struct { 55 workspace string 56 issues *github.IssuesService 57 search *github.SearchService 58 } 59 60 func checkmarxOneExecuteScan(config checkmarxOneExecuteScanOptions, _ *telemetry.CustomData, influx *checkmarxOneExecuteScanInflux) { 61 // TODO: Setup connection with Splunk, influxDB? 62 cx1sh, err := Authenticate(config, influx) 63 if err != nil { 64 log.Entry().WithError(err).Fatalf("failed to create Cx1 client: %s", err) 65 } 66 67 err = runStep(config, influx, &cx1sh) 68 if err != nil { 69 log.Entry().WithError(err).Fatalf("Failed to run CheckmarxOne scan.") 70 } 71 influx.step_data.fields.checkmarxOne = true 72 } 73 74 func runStep(config checkmarxOneExecuteScanOptions, influx *checkmarxOneExecuteScanInflux, cx1sh *checkmarxOneExecuteScanHelper) error { 75 err := error(nil) 76 cx1sh.Project, err = cx1sh.GetProjectByName() 77 if err != nil && err.Error() != "project not found" { 78 return fmt.Errorf("failed to get project: %s", err) 79 } 80 81 cx1sh.Group, err = cx1sh.GetGroup() // used when creating a project and when generating a SARIF report 82 if err != nil { 83 log.Entry().WithError(err).Warnf("failed to get group") 84 } 85 86 if cx1sh.Project == nil { 87 cx1sh.App, err = cx1sh.GetApplication() // read application name from piper config (optional) and get ID from CxONE API 88 if err != nil { 89 log.Entry().WithError(err).Warnf("Failed to get application - will attempt to create the project on the Tenant level") 90 } 91 cx1sh.Project, err = cx1sh.CreateProject() // requires groups, repoUrl, mainBranch, origin, tags, criticality 92 if err != nil { 93 return fmt.Errorf("failed to create project: %s", err) 94 } 95 } else { 96 cx1sh.Project, err = cx1sh.GetProjectByID(cx1sh.Project.ProjectID) 97 if err != nil { 98 return fmt.Errorf("failed to get project by ID: %s", err) 99 } else { 100 if len(cx1sh.Project.Applications) > 0 { 101 appId := cx1sh.Project.Applications[0] 102 cx1sh.App, err = cx1sh.GetApplicationByID(cx1sh.Project.Applications[0]) 103 if err != nil { 104 return fmt.Errorf("failed to retrieve information for project's assigned application %v", appId) 105 } 106 } 107 } 108 } 109 110 err = cx1sh.SetProjectPreset() 111 if err != nil { 112 return fmt.Errorf("failed to set preset: %s", err) 113 } 114 115 scans, err := cx1sh.GetLastScans(10) 116 if err != nil { 117 log.Entry().WithError(err).Warnf("failed to get last 10 scans") 118 } 119 120 if config.VerifyOnly { 121 if len(scans) > 0 { 122 results, err := cx1sh.ParseResults(&scans[0]) // incl report-gen 123 if err != nil { 124 return fmt.Errorf("failed to get scan results: %s", err) 125 } 126 127 err = cx1sh.CheckCompliance(&scans[0], &results) 128 if err != nil { 129 log.SetErrorCategory(log.ErrorCompliance) 130 return fmt.Errorf("project %v not compliant: %s", cx1sh.Project.Name, err) 131 } 132 133 return nil 134 } else { 135 log.Entry().Warnf("Cannot load scans for project %v, verification only mode aborted", cx1sh.Project.Name) 136 } 137 } 138 139 incremental, err := cx1sh.IncrementalOrFull(scans) // requires: scan list 140 if err != nil { 141 return fmt.Errorf("failed to determine incremental or full scan configuration: %s", err) 142 } 143 144 zipFile, err := cx1sh.ZipFiles() 145 if err != nil { 146 return fmt.Errorf("failed to create zip file: %s", err) 147 } 148 149 uploadLink, err := cx1sh.UploadScanContent(zipFile) // POST /api/uploads + PUT /{uploadLink} 150 if err != nil { 151 return fmt.Errorf("failed to get upload URL: %s", err) 152 } 153 154 // TODO : The step structure should allow to enable different scanners: SAST, KICKS, SCA 155 scan, err := cx1sh.CreateScanRequest(incremental, uploadLink) 156 if err != nil { 157 return fmt.Errorf("failed to create scan: %s", err) 158 } 159 160 // TODO: how to provide other scan parameters like engineConfiguration? 161 // TODO: potential to persist file exclusions for git? 162 err = cx1sh.PollScanStatus(scan) 163 if err != nil { 164 return fmt.Errorf("failed while polling scan status: %s", err) 165 } 166 167 results, err := cx1sh.ParseResults(scan) // incl report-gen 168 if err != nil { 169 return fmt.Errorf("failed to get scan results: %s", err) 170 } 171 err = cx1sh.CheckCompliance(scan, &results) 172 if err != nil { 173 log.SetErrorCategory(log.ErrorCompliance) 174 return fmt.Errorf("project %v not compliant: %s", cx1sh.Project.Name, err) 175 } 176 // TODO: upload logs to Splunk, influxDB? 177 return nil 178 179 } 180 181 func Authenticate(config checkmarxOneExecuteScanOptions, influx *checkmarxOneExecuteScanInflux) (checkmarxOneExecuteScanHelper, error) { 182 client := &piperHttp.Client{} 183 184 ctx, ghClient, err := piperGithub.NewClientBuilder(config.GithubToken, config.GithubAPIURL).Build() 185 if err != nil { 186 log.Entry().WithError(err).Warning("Failed to get GitHub client") 187 } 188 sys, err := checkmarxOne.NewSystemInstance(client, config.ServerURL, config.IamURL, config.Tenant, config.APIKey, config.ClientID, config.ClientSecret) 189 if err != nil { 190 return checkmarxOneExecuteScanHelper{}, fmt.Errorf("failed to create Checkmarx One client talking to URLs %v and %v with tenant %v: %s", config.ServerURL, config.IamURL, config.Tenant, err) 191 } 192 influx.step_data.fields.checkmarxOne = false 193 194 utils := newcheckmarxOneExecuteScanUtilsBundle("./", ghClient) 195 196 return checkmarxOneExecuteScanHelper{ctx, config, sys, influx, utils, nil, nil, nil, []piperutils.Path{}}, nil 197 } 198 199 func (c *checkmarxOneExecuteScanHelper) GetProjectByName() (*checkmarxOne.Project, error) { 200 if len(c.config.ProjectName) == 0 { 201 log.Entry().Fatalf("No project name set in the configuration") 202 } 203 204 // get the Project, if it exists 205 projects, err := c.sys.GetProjectsByName(c.config.ProjectName) 206 if err != nil { 207 return nil, fmt.Errorf("error when trying to load project: %s", err) 208 } 209 210 for _, p := range projects { 211 if p.Name == c.config.ProjectName { 212 return &p, nil 213 } 214 } 215 return nil, fmt.Errorf("project not found") 216 } 217 218 func (c *checkmarxOneExecuteScanHelper) GetProjectByID(projectId string) (*checkmarxOne.Project, error) { 219 project, err := c.sys.GetProjectByID(projectId) 220 return &project, err 221 } 222 223 func (c *checkmarxOneExecuteScanHelper) GetGroup() (*checkmarxOne.Group, error) { 224 if len(c.config.GroupName) > 0 { 225 group, err := c.sys.GetGroupByName(c.config.GroupName) 226 if err != nil { 227 return nil, fmt.Errorf("Failed to get Checkmarx One group by Name %v: %s", c.config.GroupName, err) 228 } 229 return &group, nil 230 } 231 return nil, fmt.Errorf("No group name specified in configuration") 232 } 233 234 func (c *checkmarxOneExecuteScanHelper) GetApplication() (*checkmarxOne.Application, error) { 235 if len(c.config.ApplicationName) > 0 { 236 app, err := c.sys.GetApplicationByName(c.config.ApplicationName) 237 if err != nil { 238 return nil, fmt.Errorf("Failed to get Checkmarx One application by Name %v: %s", c.config.ApplicationName, err) 239 } 240 241 return &app, nil 242 } 243 return nil, fmt.Errorf("No application name specified in configuration") 244 } 245 246 func (c *checkmarxOneExecuteScanHelper) GetApplicationByID(applicationId string) (*checkmarxOne.Application, error) { 247 app, err := c.sys.GetApplicationByID(applicationId) 248 if err != nil { 249 return nil, fmt.Errorf("Failed to get Checkmarx One application by Name %v: %s", c.config.ApplicationName, err) 250 } 251 252 return &app, nil 253 } 254 255 func (c *checkmarxOneExecuteScanHelper) CreateProject() (*checkmarxOne.Project, error) { 256 if len(c.config.Preset) == 0 { 257 return nil, fmt.Errorf("Preset is required to create a project") 258 } 259 260 var project checkmarxOne.Project 261 var err error 262 var groupIDs []string = []string{} 263 if c.Group != nil { 264 groupIDs = []string{c.Group.GroupID} 265 } 266 267 if c.App != nil { 268 project, err = c.sys.CreateProjectInApplication(c.config.ProjectName, c.App.ApplicationID, groupIDs) 269 } else { 270 project, err = c.sys.CreateProject(c.config.ProjectName, groupIDs) 271 } 272 273 if err != nil { 274 return nil, fmt.Errorf("Error when trying to create project: %s", err) 275 } 276 log.Entry().Infof("Project %v created", project.ProjectID) 277 278 // new project, set the defaults per pipeline config 279 err = c.sys.SetProjectPreset(project.ProjectID, c.config.Preset, true) 280 if err != nil { 281 return nil, fmt.Errorf("Unable to set preset for project %v to %v: %s", project.ProjectID, c.config.Preset, err) 282 } 283 log.Entry().Infof("Project preset updated to %v", c.config.Preset) 284 285 if len(c.config.LanguageMode) != 0 { 286 err = c.sys.SetProjectLanguageMode(project.ProjectID, c.config.LanguageMode, true) 287 if err != nil { 288 289 return nil, fmt.Errorf("Unable to set languageMode for project %v to %v: %s", project.ProjectID, c.config.LanguageMode, err) 290 } 291 log.Entry().Infof("Project languageMode updated to %v", c.config.LanguageMode) 292 } 293 294 return &project, nil 295 } 296 297 func (c *checkmarxOneExecuteScanHelper) SetProjectPreset() error { 298 projectConf, err := c.sys.GetProjectConfiguration(c.Project.ProjectID) 299 300 if err != nil { 301 return fmt.Errorf("Failed to retrieve current project configuration: %s", err) 302 } 303 304 currentPreset := "" 305 for _, conf := range projectConf { 306 if conf.Key == "scan.config.sast.presetName" { 307 currentPreset = conf.Value 308 break 309 } 310 } 311 312 if c.config.Preset == "" { 313 if currentPreset == "" { 314 return fmt.Errorf("must specify the preset in either the pipeline yaml or in the CheckmarxOne project configuration") 315 } else { 316 log.Entry().Infof("Pipeline yaml does not specify a preset, will use project configuration (%v).", currentPreset) 317 } 318 c.config.Preset = currentPreset 319 } else if currentPreset != c.config.Preset { 320 log.Entry().Infof("Project configured preset (%v) does not match pipeline yaml (%v) - updating project configuration.", currentPreset, c.config.Preset) 321 c.sys.SetProjectPreset(c.Project.ProjectID, c.config.Preset, true) 322 } else { 323 log.Entry().Infof("Project is already configured to use pipeline preset %v", currentPreset) 324 } 325 return nil 326 } 327 328 func (c *checkmarxOneExecuteScanHelper) GetLastScans(count int) ([]checkmarxOne.Scan, error) { 329 scans, err := c.sys.GetLastScansByStatus(c.Project.ProjectID, count, []string{"Completed"}) 330 if err != nil { 331 return []checkmarxOne.Scan{}, fmt.Errorf("Failed to get last %d Completed scans for project %v: %s", count, c.Project.ProjectID, err) 332 } 333 return scans, nil 334 } 335 336 func (c *checkmarxOneExecuteScanHelper) IncrementalOrFull(scans []checkmarxOne.Scan) (bool, error) { 337 incremental := c.config.Incremental 338 fullScanCycle, err := strconv.Atoi(c.config.FullScanCycle) 339 if err != nil { 340 log.SetErrorCategory(log.ErrorConfiguration) 341 return false, fmt.Errorf("invalid configuration value for fullScanCycle %v, must be a positive int", c.config.FullScanCycle) 342 } 343 344 coherentIncrementalScans := c.getNumCoherentIncrementalScans(scans) 345 346 if c.config.IsOptimizedAndScheduled { 347 incremental = false 348 } else if incremental && c.config.FullScansScheduled && fullScanCycle > 0 && (coherentIncrementalScans+1) >= fullScanCycle { 349 incremental = false 350 } 351 352 return incremental, nil 353 } 354 355 func (c *checkmarxOneExecuteScanHelper) ZipFiles() (*os.File, error) { 356 zipFile, err := c.zipWorkspaceFiles(c.config.FilterPattern, c.utils) 357 if err != nil { 358 return nil, fmt.Errorf("Failed to zip workspace files") 359 } 360 return zipFile, nil 361 } 362 363 func (c *checkmarxOneExecuteScanHelper) UploadScanContent(zipFile *os.File) (string, error) { 364 uploadUri, err := c.sys.UploadProjectSourceCode(c.Project.ProjectID, zipFile.Name()) 365 if err != nil { 366 return "", fmt.Errorf("Failed to upload source code for project %v: %s", c.Project.ProjectID, err) 367 } 368 369 log.Entry().Debugf("Source code uploaded for project %v", c.Project.Name) 370 err = os.Remove(zipFile.Name()) 371 if err != nil { 372 log.Entry().WithError(err).Warnf("Failed to delete zipped source code for project %v", c.Project.Name) 373 } 374 return uploadUri, nil 375 } 376 377 func (c *checkmarxOneExecuteScanHelper) CreateScanRequest(incremental bool, uploadLink string) (*checkmarxOne.Scan, error) { 378 sastConfig := checkmarxOne.ScanConfiguration{} 379 sastConfig.ScanType = "sast" 380 381 sastConfig.Values = make(map[string]string, 0) 382 sastConfig.Values["incremental"] = strconv.FormatBool(incremental) 383 sastConfig.Values["presetName"] = c.config.Preset // always set, either coming from config or coming from Cx1 configuration 384 sastConfigString := fmt.Sprintf("incremental %v, preset %v", strconv.FormatBool(incremental), c.config.Preset) 385 386 if len(c.config.LanguageMode) > 0 { 387 sastConfig.Values["languageMode"] = c.config.LanguageMode 388 sastConfigString = sastConfigString + fmt.Sprintf(", languageMode %v", c.config.LanguageMode) 389 } 390 391 branch := c.config.Branch 392 if len(c.config.PullRequestName) > 0 { 393 branch = fmt.Sprintf("%v-%v", c.config.PullRequestName, c.config.Branch) 394 } 395 396 sastConfigString = fmt.Sprintf("Cx1 Branch name %v, ", branch) + sastConfigString 397 398 log.Entry().Infof("Will run a scan with the following configuration: %v", sastConfigString) 399 400 configs := []checkmarxOne.ScanConfiguration{sastConfig} 401 // add more engines 402 403 scan, err := c.sys.ScanProjectZip(c.Project.ProjectID, uploadLink, branch, configs) 404 405 if err != nil { 406 return nil, fmt.Errorf("Failed to run scan on project %v: %s", c.Project.Name, err) 407 } 408 409 log.Entry().Debugf("Scanning project %v: %v ", c.Project.Name, scan.ScanID) 410 411 return &scan, nil 412 } 413 414 func (c *checkmarxOneExecuteScanHelper) PollScanStatus(scan *checkmarxOne.Scan) error { 415 statusDetails := "Scan phase: New" 416 pastStatusDetails := statusDetails 417 log.Entry().Info(statusDetails) 418 status := "New" 419 for { 420 scan_refresh, err := c.sys.GetScan(scan.ScanID) 421 422 if err != nil { 423 return fmt.Errorf("Error while polling scan %v: %s", scan.ScanID, err) 424 } 425 426 status = scan_refresh.Status 427 workflow, err := c.sys.GetScanWorkflow(scan.ScanID) 428 if err != nil { 429 return fmt.Errorf("Error while getting workflow for scan %v: %s", scan.ScanID, err) 430 } 431 432 statusDetails = workflow[len(workflow)-1].Info 433 434 if pastStatusDetails != statusDetails { 435 log.Entry().Info(statusDetails) 436 pastStatusDetails = statusDetails 437 } 438 439 if status == "Completed" || status == "Canceled" || status == "Failed" { 440 break 441 } 442 443 if pastStatusDetails != statusDetails { 444 log.Entry().Info(statusDetails) 445 pastStatusDetails = statusDetails 446 } 447 448 log.Entry().Debug("Polling for status: sleeping...") 449 450 time.Sleep(10 * time.Second) 451 } 452 if status == "Canceled" { 453 log.SetErrorCategory(log.ErrorCustom) 454 return fmt.Errorf("Scan %v canceled via web interface", scan.ScanID) 455 } 456 if status == "Failed" { 457 return fmt.Errorf("Checkmarx One scan failed with the following error: %v", statusDetails) 458 } 459 return nil 460 } 461 462 func (c *checkmarxOneExecuteScanHelper) CheckCompliance(scan *checkmarxOne.Scan, detailedResults *map[string]interface{}) error { 463 464 links := []piperutils.Path{{Target: (*detailedResults)["DeepLink"].(string), Name: "Checkmarx One Web UI"}} 465 466 insecure := false 467 var insecureResults []string 468 var neutralResults []string 469 470 if c.config.VulnerabilityThresholdEnabled { 471 insecure, insecureResults, neutralResults = c.enforceThresholds(detailedResults) 472 scanReport := checkmarxOne.CreateCustomReport(detailedResults, insecureResults, neutralResults) 473 474 if insecure && c.config.CreateResultIssue && len(c.config.GithubToken) > 0 && len(c.config.GithubAPIURL) > 0 && len(c.config.Owner) > 0 && len(c.config.Repository) > 0 { 475 log.Entry().Debug("Creating/updating GitHub issue with check results") 476 gh := reporting.GitHub{ 477 Owner: &c.config.Owner, 478 Repository: &c.config.Repository, 479 Assignees: &c.config.Assignees, 480 IssueService: c.utils.GetIssueService(), 481 SearchService: c.utils.GetSearchService(), 482 } 483 if err := gh.UploadSingleReport(c.ctx, scanReport); err != nil { 484 return fmt.Errorf("failed to upload scan results into GitHub: %s", err) 485 } 486 } 487 488 paths, err := checkmarxOne.WriteCustomReports(scanReport, c.Project.Name, c.Project.ProjectID) 489 if err != nil { 490 // do not fail until we have a better idea to handle it 491 log.Entry().Warning("failed to write HTML/MarkDown report file ...", err) 492 } else { 493 c.reports = append(c.reports, paths...) 494 } 495 } 496 497 piperutils.PersistReportsAndLinks("checkmarxOneExecuteScan", c.utils.GetWorkspace(), c.utils, c.reports, links) 498 499 c.reportToInflux(detailedResults) 500 501 if insecure { 502 if c.config.VulnerabilityThresholdResult == "FAILURE" { 503 log.SetErrorCategory(log.ErrorCompliance) 504 return fmt.Errorf("the project is not compliant - see report for details") 505 } 506 log.Entry().Errorf("Checkmarx One scan result set to %v, some results are not meeting defined thresholds. For details see the archived report.", c.config.VulnerabilityThresholdResult) 507 } else { 508 log.Entry().Infoln("Checkmarx One scan finished successfully") 509 } 510 return nil 511 } 512 513 func (c *checkmarxOneExecuteScanHelper) GetReportPDF(scan *checkmarxOne.Scan) error { 514 if c.config.GeneratePdfReport { 515 pdfReportName := c.createReportName(c.utils.GetWorkspace(), "Cx1_SASTReport_%v.pdf") 516 err := c.downloadAndSaveReport(pdfReportName, scan, "pdf") 517 if err != nil { 518 return fmt.Errorf("Report download failed: %s", err) 519 } else { 520 c.reports = append(c.reports, piperutils.Path{Target: pdfReportName, Mandatory: true}) 521 } 522 } else { 523 log.Entry().Debug("Report generation is disabled via configuration") 524 } 525 526 return nil 527 } 528 529 func (c *checkmarxOneExecuteScanHelper) GetReportSARIF(scan *checkmarxOne.Scan, scanmeta *checkmarxOne.ScanMetadata, results *[]checkmarxOne.ScanResult) error { 530 if c.config.ConvertToSarif { 531 log.Entry().Info("Calling conversion to SARIF function.") 532 sarif, err := checkmarxOne.ConvertCxJSONToSarif(c.sys, c.config.ServerURL, results, scanmeta, scan) 533 if err != nil { 534 return fmt.Errorf("Failed to generate SARIF: %s", err) 535 } 536 paths, err := checkmarxOne.WriteSarif(sarif) 537 if err != nil { 538 return fmt.Errorf("Failed to write SARIF: %s", err) 539 } 540 c.reports = append(c.reports, paths...) 541 } 542 return nil 543 } 544 545 func (c *checkmarxOneExecuteScanHelper) GetReportJSON(scan *checkmarxOne.Scan) error { 546 jsonReportName := c.createReportName(c.utils.GetWorkspace(), "Cx1_SASTReport_%v.json") 547 err := c.downloadAndSaveReport(jsonReportName, scan, "json") 548 if err != nil { 549 return fmt.Errorf("Report download failed: %s", err) 550 } else { 551 c.reports = append(c.reports, piperutils.Path{Target: jsonReportName, Mandatory: true}) 552 } 553 return nil 554 } 555 556 func (c *checkmarxOneExecuteScanHelper) GetHeaderReportJSON(detailedResults *map[string]interface{}) error { 557 // This is for the SAP-piper-format short-form JSON report 558 jsonReport := checkmarxOne.CreateJSONHeaderReport(detailedResults) 559 paths, err := checkmarxOne.WriteJSONHeaderReport(jsonReport) 560 if err != nil { 561 return fmt.Errorf("Failed to write JSON header report: %s", err) 562 } else { 563 // add JSON report to archiving list 564 c.reports = append(c.reports, paths...) 565 } 566 return nil 567 } 568 569 func (c *checkmarxOneExecuteScanHelper) ParseResults(scan *checkmarxOne.Scan) (map[string]interface{}, error) { 570 var detailedResults map[string]interface{} 571 572 scanmeta, err := c.sys.GetScanMetadata(scan.ScanID) 573 if err != nil { 574 return detailedResults, fmt.Errorf("Unable to fetch scan metadata for scan %v: %s", scan.ScanID, err) 575 } 576 577 totalResultCount := uint64(0) 578 579 scansummary, err := c.sys.GetScanSummary(scan.ScanID) 580 if err != nil { 581 /* TODO: scansummary throws a 404 for 0-result scans, once the bug is fixed put this code back. */ 582 // return detailedResults, fmt.Errorf("Unable to fetch scan summary for scan %v: %s", scan.ScanID, err) 583 } else { 584 totalResultCount = scansummary.TotalCount() 585 } 586 587 results, err := c.sys.GetScanResults(scan.ScanID, totalResultCount) 588 if err != nil { 589 return detailedResults, fmt.Errorf("Unable to fetch scan results for scan %v: %s", scan.ScanID, err) 590 } 591 592 detailedResults, err = c.getDetailedResults(scan, &scanmeta, &results) 593 if err != nil { 594 return detailedResults, fmt.Errorf("Unable to fetch detailed results for scan %v: %s", scan.ScanID, err) 595 } 596 597 err = c.GetReportJSON(scan) 598 if err != nil { 599 log.Entry().WithError(err).Warnf("Failed to get JSON report") 600 } 601 err = c.GetReportPDF(scan) 602 if err != nil { 603 log.Entry().WithError(err).Warnf("Failed to get PDF report") 604 } 605 err = c.GetReportSARIF(scan, &scanmeta, &results) 606 if err != nil { 607 log.Entry().WithError(err).Warnf("Failed to get SARIF report") 608 } 609 err = c.GetHeaderReportJSON(&detailedResults) 610 if err != nil { 611 log.Entry().WithError(err).Warnf("Failed to generate JSON Header report") 612 } 613 614 // create toolrecord 615 toolRecordFileName, err := c.createToolRecordCx(&detailedResults) 616 if err != nil { 617 // do not fail until the framework is well established 618 log.Entry().Warning("TR_CHECKMARXONE: Failed to create toolrecord file ...", err) 619 } else { 620 c.reports = append(c.reports, piperutils.Path{Target: toolRecordFileName}) 621 } 622 623 return detailedResults, nil 624 } 625 626 func (c *checkmarxOneExecuteScanHelper) createReportName(workspace, reportFileNameTemplate string) string { 627 regExpFileName := regexp.MustCompile(`[^\w\d]`) 628 timeStamp, _ := time.Now().Local().MarshalText() 629 return filepath.Join(workspace, fmt.Sprintf(reportFileNameTemplate, regExpFileName.ReplaceAllString(string(timeStamp), "_"))) 630 } 631 632 func (c *checkmarxOneExecuteScanHelper) downloadAndSaveReport(reportFileName string, scan *checkmarxOne.Scan, reportType string) error { 633 report, err := c.generateAndDownloadReport(scan, reportType) 634 if err != nil { 635 return errors.Wrap(err, "failed to download the report") 636 } 637 log.Entry().Debugf("Saving report to file %v...", reportFileName) 638 return c.utils.WriteFile(reportFileName, report, 0o700) 639 } 640 641 func (c *checkmarxOneExecuteScanHelper) generateAndDownloadReport(scan *checkmarxOne.Scan, reportType string) ([]byte, error) { 642 var finalStatus checkmarxOne.ReportStatus 643 644 report, err := c.sys.RequestNewReport(scan.ScanID, scan.ProjectID, scan.Branch, reportType) 645 if err != nil { 646 return []byte{}, errors.Wrap(err, "failed to request new report") 647 } 648 for { 649 finalStatus, err = c.sys.GetReportStatus(report) 650 if err != nil { 651 return []byte{}, errors.Wrap(err, "failed to get report status") 652 } 653 654 if finalStatus.Status == "completed" { 655 break 656 } else if finalStatus.Status == "failed" { 657 return []byte{}, fmt.Errorf("report generation failed") 658 } 659 time.Sleep(10 * time.Second) 660 } 661 if finalStatus.Status == "completed" { 662 return c.sys.DownloadReport(finalStatus.ReportURL) 663 } 664 665 return []byte{}, fmt.Errorf("unexpected status %v recieved", finalStatus.Status) 666 } 667 668 func (c *checkmarxOneExecuteScanHelper) getNumCoherentIncrementalScans(scans []checkmarxOne.Scan) int { 669 count := 0 670 for _, scan := range scans { 671 inc, err := scan.IsIncremental() 672 if !inc && err == nil { 673 break 674 } 675 count++ 676 } 677 return count 678 } 679 680 func (c *checkmarxOneExecuteScanHelper) getDetailedResults(scan *checkmarxOne.Scan, scanmeta *checkmarxOne.ScanMetadata, results *[]checkmarxOne.ScanResult) (map[string]interface{}, error) { 681 // this converts the JSON format results from Cx1 into the "resultMap" structure used in other parts of this step (influx etc) 682 683 resultMap := map[string]interface{}{} 684 resultMap["InitiatorName"] = scan.Initiator 685 resultMap["Owner"] = "Cx1 Gap: no project owner" // TODO: check for functionality 686 resultMap["ScanId"] = scan.ScanID 687 resultMap["ProjectId"] = c.Project.ProjectID 688 resultMap["ProjectName"] = c.Project.Name 689 690 resultMap["Group"] = "" 691 resultMap["GroupFullPathOnReportDate"] = "" 692 693 if c.App != nil { 694 resultMap["Application"] = c.App.ApplicationID 695 resultMap["ApplicationFullPathOnReportDate"] = c.App.Name 696 } else { 697 resultMap["Application"] = "" 698 resultMap["ApplicationFullPathOnReportDate"] = "" 699 } 700 701 resultMap["ScanStart"] = scan.CreatedAt 702 703 scanCreated, err := time.Parse(time.RFC3339, scan.CreatedAt) 704 if err != nil { 705 log.Entry().Warningf("Failed to parse string %v into time: %s", scan.CreatedAt, err) 706 resultMap["ScanTime"] = "Error parsing scan.CreatedAt" 707 } else { 708 scanFinished, err := time.Parse(time.RFC3339, scan.UpdatedAt) 709 if err != nil { 710 log.Entry().Warningf("Failed to parse string %v into time: %s", scan.UpdatedAt, err) 711 resultMap["ScanTime"] = "Error parsing scan.UpdatedAt" 712 } else { 713 difference := scanFinished.Sub(scanCreated) 714 resultMap["ScanTime"] = difference.String() 715 } 716 } 717 718 resultMap["LinesOfCodeScanned"] = scanmeta.LOC 719 resultMap["FilesScanned"] = scanmeta.FileCount 720 resultMap["ToolVersion"] = "Cx1 Gap: No API for this" 721 722 if scanmeta.IsIncremental { 723 resultMap["ScanType"] = "Incremental" 724 } else { 725 resultMap["ScanType"] = "Full" 726 } 727 728 resultMap["Preset"] = scanmeta.PresetName 729 resultMap["DeepLink"] = fmt.Sprintf("%v/projects/%v/overview?branch=%v", c.config.ServerURL, c.Project.ProjectID, scan.Branch) 730 resultMap["ReportCreationTime"] = time.Now().String() 731 resultMap["High"] = map[string]int{} 732 resultMap["Medium"] = map[string]int{} 733 resultMap["Low"] = map[string]int{} 734 resultMap["Information"] = map[string]int{} 735 736 if len(*results) > 0 { 737 for _, result := range *results { 738 key := "Information" 739 switch result.Severity { 740 case "HIGH": 741 key = "High" 742 case "MEDIUM": 743 key = "Medium" 744 case "LOW": 745 key = "Low" 746 case "INFORMATION": 747 default: 748 key = "Information" 749 } 750 751 var submap map[string]int 752 if resultMap[key] == nil { 753 submap = map[string]int{} 754 resultMap[key] = submap 755 } else { 756 submap = resultMap[key].(map[string]int) 757 } 758 submap["Issues"]++ 759 760 auditState := "ToVerify" 761 switch result.State { 762 case "NOT_EXPLOITABLE": 763 auditState = "NotExploitable" 764 case "CONFIRMED": 765 auditState = "Confirmed" 766 case "URGENT", "URGENT ": 767 auditState = "Urgent" 768 case "PROPOSED_NOT_EXPLOITABLE": 769 auditState = "ProposedNotExploitable" 770 case "TO_VERIFY": 771 default: 772 auditState = "ToVerify" 773 } 774 submap[auditState]++ 775 776 if auditState != "NotExploitable" { 777 submap["NotFalsePositive"]++ 778 } 779 780 } 781 782 // if the flag is switched on, build the list of Low findings per query 783 if c.config.VulnerabilityThresholdLowPerQuery { 784 var lowPerQuery = map[string]map[string]int{} 785 786 for _, result := range *results { 787 if result.Severity != "LOW" { 788 continue 789 } 790 key := result.Data.QueryName 791 var submap map[string]int 792 if lowPerQuery[key] == nil { 793 submap = map[string]int{} 794 lowPerQuery[key] = submap 795 } else { 796 submap = lowPerQuery[key] 797 } 798 submap["Issues"]++ 799 auditState := "ToVerify" 800 switch result.State { 801 case "NOT_EXPLOITABLE": 802 auditState = "NotExploitable" 803 case "CONFIRMED": 804 auditState = "Confirmed" 805 case "URGENT", "URGENT ": 806 auditState = "Urgent" 807 case "PROPOSED_NOT_EXPLOITABLE": 808 auditState = "ProposedNotExploitable" 809 case "TO_VERIFY": 810 default: 811 auditState = "ToVerify" 812 } 813 submap[auditState]++ 814 815 if auditState != "NotExploitable" { 816 submap["NotFalsePositive"]++ 817 } 818 } 819 820 resultMap["LowPerQuery"] = lowPerQuery 821 } 822 } 823 return resultMap, nil 824 } 825 826 func (c *checkmarxOneExecuteScanHelper) zipWorkspaceFiles(filterPattern string, utils checkmarxOneExecuteScanUtils) (*os.File, error) { 827 zipFileName := filepath.Join(utils.GetWorkspace(), "workspace.zip") 828 patterns := piperutils.Trim(strings.Split(filterPattern, ",")) 829 sort.Strings(patterns) 830 zipFile, err := os.Create(zipFileName) 831 if err != nil { 832 return zipFile, errors.Wrap(err, "failed to create archive of project sources") 833 } 834 defer zipFile.Close() 835 836 err = c.zipFolder(utils.GetWorkspace(), zipFile, patterns, utils) 837 if err != nil { 838 return nil, errors.Wrap(err, "failed to compact folder") 839 } 840 return zipFile, nil 841 } 842 843 func (c *checkmarxOneExecuteScanHelper) zipFolder(source string, zipFile io.Writer, patterns []string, utils checkmarxOneExecuteScanUtils) error { 844 archive := zip.NewWriter(zipFile) 845 defer archive.Close() 846 847 log.Entry().Infof("Zipping %v into workspace.zip", source) 848 849 info, err := utils.Stat(source) 850 if err != nil { 851 return nil 852 } 853 854 var baseDir string 855 if info.IsDir() { 856 baseDir = filepath.Base(source) 857 } 858 859 fileCount := 0 860 err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error { 861 if err != nil { 862 return err 863 } 864 865 if !info.Mode().IsRegular() || info.Size() == 0 { 866 return nil 867 } 868 869 noMatch, err := c.isFileNotMatchingPattern(patterns, path, info, utils) 870 if err != nil || noMatch { 871 return err 872 } 873 874 fileName := strings.TrimPrefix(path, baseDir) 875 writer, err := archive.Create(fileName) 876 if err != nil { 877 return err 878 } 879 880 file, err := utils.Open(path) 881 if err != nil { 882 return err 883 } 884 defer file.Close() 885 _, err = io.Copy(writer, file) 886 fileCount++ 887 return err 888 }) 889 log.Entry().Infof("Zipped %d files", fileCount) 890 err = c.handleZeroFilesZipped(source, err, fileCount) 891 return err 892 } 893 894 func (c *checkmarxOneExecuteScanHelper) adaptHeader(info os.FileInfo, header *zip.FileHeader) { 895 if info.IsDir() { 896 header.Name += "/" 897 } else { 898 header.Method = zip.Deflate 899 } 900 } 901 902 func (c *checkmarxOneExecuteScanHelper) handleZeroFilesZipped(source string, err error, fileCount int) error { 903 if err == nil && fileCount == 0 { 904 log.SetErrorCategory(log.ErrorConfiguration) 905 err = fmt.Errorf("filterPattern matched no files or workspace directory '%s' was empty", source) 906 } 907 return err 908 } 909 910 // isFileNotMatchingPattern checks if file path does not match one of the patterns. 911 // If it matches a negative pattern (starting with '!') then true is returned. 912 // 913 // If it is a directory, false is returned. 914 // If no patterns are provided, false is returned. 915 func (c *checkmarxOneExecuteScanHelper) isFileNotMatchingPattern(patterns []string, path string, info os.FileInfo, utils checkmarxOneExecuteScanUtils) (bool, error) { 916 if len(patterns) == 0 || info.IsDir() { 917 return false, nil 918 } 919 920 for _, pattern := range patterns { 921 negative := false 922 if strings.HasPrefix(pattern, "!") { 923 pattern = strings.TrimLeft(pattern, "!") 924 negative = true 925 } 926 match, err := utils.PathMatch(pattern, path) 927 if err != nil { 928 return false, errors.Wrapf(err, "Pattern %v could not get executed", pattern) 929 } 930 931 if match { 932 return negative, nil 933 } 934 } 935 return true, nil 936 } 937 938 func (c *checkmarxOneExecuteScanHelper) createToolRecordCx(results *map[string]interface{}) (string, error) { 939 workspace := c.utils.GetWorkspace() 940 record := toolrecord.New(c.utils, workspace, "checkmarxOne", c.config.ServerURL) 941 942 // Project 943 err := record.AddKeyData("project", 944 (*results)["ProjectId"].(string), 945 (*results)["ProjectName"].(string), 946 "") 947 if err != nil { 948 return "", err 949 } 950 // Scan 951 err = record.AddKeyData("scanid", 952 (*results)["ScanId"].(string), 953 (*results)["ScanId"].(string), 954 (*results)["DeepLink"].(string)) 955 if err != nil { 956 return "", err 957 } 958 err = record.Persist() 959 if err != nil { 960 return "", err 961 } 962 return record.GetFileName(), nil 963 } 964 965 func (c *checkmarxOneExecuteScanHelper) enforceThresholds(results *map[string]interface{}) (bool, []string, []string) { 966 neutralResults := []string{} 967 insecureResults := []string{} 968 insecure := false 969 970 cxHighThreshold := c.config.VulnerabilityThresholdHigh 971 cxMediumThreshold := c.config.VulnerabilityThresholdMedium 972 cxLowThreshold := c.config.VulnerabilityThresholdLow 973 cxLowThresholdPerQuery := c.config.VulnerabilityThresholdLowPerQuery 974 cxLowThresholdPerQueryMax := c.config.VulnerabilityThresholdLowPerQueryMax 975 highValue := (*results)["High"].(map[string]int)["NotFalsePositive"] 976 mediumValue := (*results)["Medium"].(map[string]int)["NotFalsePositive"] 977 lowValue := (*results)["Low"].(map[string]int)["NotFalsePositive"] 978 var unit string 979 highViolation := "" 980 mediumViolation := "" 981 lowViolation := "" 982 if c.config.VulnerabilityThresholdUnit == "percentage" { 983 unit = "%" 984 highAudited := (*results)["High"].(map[string]int)["Issues"] - (*results)["High"].(map[string]int)["NotFalsePositive"] 985 highOverall := (*results)["High"].(map[string]int)["Issues"] 986 if highOverall == 0 { 987 highAudited = 1 988 highOverall = 1 989 } 990 mediumAudited := (*results)["Medium"].(map[string]int)["Issues"] - (*results)["Medium"].(map[string]int)["NotFalsePositive"] 991 mediumOverall := (*results)["Medium"].(map[string]int)["Issues"] 992 if mediumOverall == 0 { 993 mediumAudited = 1 994 mediumOverall = 1 995 } 996 lowAudited := (*results)["Low"].(map[string]int)["Confirmed"] + (*results)["Low"].(map[string]int)["NotExploitable"] 997 lowOverall := (*results)["Low"].(map[string]int)["Issues"] 998 if lowOverall == 0 { 999 lowAudited = 1 1000 lowOverall = 1 1001 } 1002 highValue = int(float32(highAudited) / float32(highOverall) * 100.0) 1003 mediumValue = int(float32(mediumAudited) / float32(mediumOverall) * 100.0) 1004 lowValue = int(float32(lowAudited) / float32(lowOverall) * 100.0) 1005 1006 if highValue < cxHighThreshold { 1007 insecure = true 1008 highViolation = fmt.Sprintf("<-- %v %v deviation", cxHighThreshold-highValue, unit) 1009 } 1010 if mediumValue < cxMediumThreshold { 1011 insecure = true 1012 mediumViolation = fmt.Sprintf("<-- %v %v deviation", cxMediumThreshold-mediumValue, unit) 1013 } 1014 // if the flag is switched on, calculate the Low findings threshold per query 1015 if cxLowThresholdPerQuery { 1016 if (*results)["LowPerQuery"] != nil { 1017 lowPerQueryMap := (*results)["LowPerQuery"].(map[string]map[string]int) 1018 1019 for lowQuery, resultsLowQuery := range lowPerQueryMap { 1020 lowAuditedPerQuery := resultsLowQuery["Confirmed"] + resultsLowQuery["NotExploitable"] 1021 lowOverallPerQuery := resultsLowQuery["Issues"] 1022 lowAuditedRequiredPerQuery := int(math.Ceil(float64(lowOverallPerQuery) * float64(cxLowThreshold) / 100.0)) 1023 if lowAuditedPerQuery < lowAuditedRequiredPerQuery && lowAuditedPerQuery < cxLowThresholdPerQueryMax { 1024 insecure = true 1025 msgSeperator := "|" 1026 if lowViolation == "" { 1027 msgSeperator = "<--" 1028 } 1029 lowViolation += fmt.Sprintf(" %v query: %v, audited: %v, required: %v ", msgSeperator, lowQuery, lowAuditedPerQuery, lowAuditedRequiredPerQuery) 1030 } 1031 } 1032 } 1033 } else { // calculate the Low findings threshold in total 1034 if lowValue < cxLowThreshold { 1035 insecure = true 1036 lowViolation = fmt.Sprintf("<-- %v %v deviation", cxLowThreshold-lowValue, unit) 1037 } 1038 } 1039 1040 } 1041 if c.config.VulnerabilityThresholdUnit == "absolute" { 1042 unit = " findings" 1043 if highValue > cxHighThreshold { 1044 insecure = true 1045 highViolation = fmt.Sprintf("<-- %v%v deviation", highValue-cxHighThreshold, unit) 1046 } 1047 if mediumValue > cxMediumThreshold { 1048 insecure = true 1049 mediumViolation = fmt.Sprintf("<-- %v%v deviation", mediumValue-cxMediumThreshold, unit) 1050 } 1051 if lowValue > cxLowThreshold { 1052 insecure = true 1053 lowViolation = fmt.Sprintf("<-- %v%v deviation", lowValue-cxLowThreshold, unit) 1054 } 1055 } 1056 1057 highText := fmt.Sprintf("High %v%v %v", highValue, unit, highViolation) 1058 mediumText := fmt.Sprintf("Medium %v%v %v", mediumValue, unit, mediumViolation) 1059 lowText := fmt.Sprintf("Low %v%v %v", lowValue, unit, lowViolation) 1060 if len(highViolation) > 0 { 1061 insecureResults = append(insecureResults, highText) 1062 log.Entry().Error(highText) 1063 } else { 1064 neutralResults = append(neutralResults, highText) 1065 log.Entry().Info(highText) 1066 } 1067 if len(mediumViolation) > 0 { 1068 insecureResults = append(insecureResults, mediumText) 1069 log.Entry().Error(mediumText) 1070 } else { 1071 neutralResults = append(neutralResults, mediumText) 1072 log.Entry().Info(mediumText) 1073 } 1074 if len(lowViolation) > 0 { 1075 insecureResults = append(insecureResults, lowText) 1076 log.Entry().Error(lowText) 1077 } else { 1078 neutralResults = append(neutralResults, lowText) 1079 log.Entry().Info(lowText) 1080 } 1081 1082 return insecure, insecureResults, neutralResults 1083 } 1084 1085 func (c *checkmarxOneExecuteScanHelper) reportToInflux(results *map[string]interface{}) { 1086 1087 c.influx.checkmarxOne_data.fields.high_issues = (*results)["High"].(map[string]int)["Issues"] 1088 c.influx.checkmarxOne_data.fields.high_not_false_postive = (*results)["High"].(map[string]int)["NotFalsePositive"] 1089 c.influx.checkmarxOne_data.fields.high_not_exploitable = (*results)["High"].(map[string]int)["NotExploitable"] 1090 c.influx.checkmarxOne_data.fields.high_confirmed = (*results)["High"].(map[string]int)["Confirmed"] 1091 c.influx.checkmarxOne_data.fields.high_urgent = (*results)["High"].(map[string]int)["Urgent"] 1092 c.influx.checkmarxOne_data.fields.high_proposed_not_exploitable = (*results)["High"].(map[string]int)["ProposedNotExploitable"] 1093 c.influx.checkmarxOne_data.fields.high_to_verify = (*results)["High"].(map[string]int)["ToVerify"] 1094 c.influx.checkmarxOne_data.fields.medium_issues = (*results)["Medium"].(map[string]int)["Issues"] 1095 c.influx.checkmarxOne_data.fields.medium_not_false_postive = (*results)["Medium"].(map[string]int)["NotFalsePositive"] 1096 c.influx.checkmarxOne_data.fields.medium_not_exploitable = (*results)["Medium"].(map[string]int)["NotExploitable"] 1097 c.influx.checkmarxOne_data.fields.medium_confirmed = (*results)["Medium"].(map[string]int)["Confirmed"] 1098 c.influx.checkmarxOne_data.fields.medium_urgent = (*results)["Medium"].(map[string]int)["Urgent"] 1099 c.influx.checkmarxOne_data.fields.medium_proposed_not_exploitable = (*results)["Medium"].(map[string]int)["ProposedNotExploitable"] 1100 c.influx.checkmarxOne_data.fields.medium_to_verify = (*results)["Medium"].(map[string]int)["ToVerify"] 1101 c.influx.checkmarxOne_data.fields.low_issues = (*results)["Low"].(map[string]int)["Issues"] 1102 c.influx.checkmarxOne_data.fields.low_not_false_postive = (*results)["Low"].(map[string]int)["NotFalsePositive"] 1103 c.influx.checkmarxOne_data.fields.low_not_exploitable = (*results)["Low"].(map[string]int)["NotExploitable"] 1104 c.influx.checkmarxOne_data.fields.low_confirmed = (*results)["Low"].(map[string]int)["Confirmed"] 1105 c.influx.checkmarxOne_data.fields.low_urgent = (*results)["Low"].(map[string]int)["Urgent"] 1106 c.influx.checkmarxOne_data.fields.low_proposed_not_exploitable = (*results)["Low"].(map[string]int)["ProposedNotExploitable"] 1107 c.influx.checkmarxOne_data.fields.low_to_verify = (*results)["Low"].(map[string]int)["ToVerify"] 1108 c.influx.checkmarxOne_data.fields.information_issues = (*results)["Information"].(map[string]int)["Issues"] 1109 c.influx.checkmarxOne_data.fields.information_not_false_postive = (*results)["Information"].(map[string]int)["NotFalsePositive"] 1110 c.influx.checkmarxOne_data.fields.information_not_exploitable = (*results)["Information"].(map[string]int)["NotExploitable"] 1111 c.influx.checkmarxOne_data.fields.information_confirmed = (*results)["Information"].(map[string]int)["Confirmed"] 1112 c.influx.checkmarxOne_data.fields.information_urgent = (*results)["Information"].(map[string]int)["Urgent"] 1113 c.influx.checkmarxOne_data.fields.information_proposed_not_exploitable = (*results)["Information"].(map[string]int)["ProposedNotExploitable"] 1114 c.influx.checkmarxOne_data.fields.information_to_verify = (*results)["Information"].(map[string]int)["ToVerify"] 1115 c.influx.checkmarxOne_data.fields.initiator_name = (*results)["InitiatorName"].(string) 1116 c.influx.checkmarxOne_data.fields.owner = (*results)["Owner"].(string) 1117 c.influx.checkmarxOne_data.fields.scan_id = (*results)["ScanId"].(string) 1118 c.influx.checkmarxOne_data.fields.project_id = (*results)["ProjectId"].(string) 1119 c.influx.checkmarxOne_data.fields.projectName = (*results)["ProjectName"].(string) 1120 c.influx.checkmarxOne_data.fields.group = (*results)["Group"].(string) 1121 c.influx.checkmarxOne_data.fields.group_full_path_on_report_date = (*results)["GroupFullPathOnReportDate"].(string) 1122 c.influx.checkmarxOne_data.fields.scan_start = (*results)["ScanStart"].(string) 1123 c.influx.checkmarxOne_data.fields.scan_time = (*results)["ScanTime"].(string) 1124 c.influx.checkmarxOne_data.fields.lines_of_code_scanned = (*results)["LinesOfCodeScanned"].(int) 1125 c.influx.checkmarxOne_data.fields.files_scanned = (*results)["FilesScanned"].(int) 1126 c.influx.checkmarxOne_data.fields.tool_version = (*results)["ToolVersion"].(string) 1127 1128 c.influx.checkmarxOne_data.fields.scan_type = (*results)["ScanType"].(string) 1129 c.influx.checkmarxOne_data.fields.preset = (*results)["Preset"].(string) 1130 c.influx.checkmarxOne_data.fields.deep_link = (*results)["DeepLink"].(string) 1131 c.influx.checkmarxOne_data.fields.report_creation_time = (*results)["ReportCreationTime"].(string) 1132 } 1133 1134 // Utils Bundle 1135 // various utilities to set up or work with the workspace and prepare data to send to Cx1 1136 1137 func (c *checkmarxOneExecuteScanUtilsBundle) PathMatch(pattern, name string) (bool, error) { 1138 return doublestar.PathMatch(pattern, name) 1139 } 1140 1141 func (c *checkmarxOneExecuteScanUtilsBundle) GetWorkspace() string { 1142 return c.workspace 1143 } 1144 1145 func (c *checkmarxOneExecuteScanUtilsBundle) WriteFile(filename string, data []byte, perm os.FileMode) error { 1146 return os.WriteFile(filename, data, perm) 1147 } 1148 1149 func (c *checkmarxOneExecuteScanUtilsBundle) MkdirAll(path string, perm os.FileMode) error { 1150 return os.MkdirAll(path, perm) 1151 } 1152 1153 func (c *checkmarxOneExecuteScanUtilsBundle) FileInfoHeader(fi os.FileInfo) (*zip.FileHeader, error) { 1154 return zip.FileInfoHeader(fi) 1155 } 1156 1157 func (c *checkmarxOneExecuteScanUtilsBundle) Stat(name string) (os.FileInfo, error) { 1158 return os.Stat(name) 1159 } 1160 1161 func (c *checkmarxOneExecuteScanUtilsBundle) Open(name string) (*os.File, error) { 1162 return os.Open(name) 1163 } 1164 1165 func (c *checkmarxOneExecuteScanUtilsBundle) CreateIssue(ghCreateIssueOptions *piperGithub.CreateIssueOptions) error { 1166 _, err := piperGithub.CreateIssue(ghCreateIssueOptions) 1167 return err 1168 } 1169 1170 func (c *checkmarxOneExecuteScanUtilsBundle) GetIssueService() *github.IssuesService { 1171 return c.issues 1172 } 1173 1174 func (c *checkmarxOneExecuteScanUtilsBundle) GetSearchService() *github.SearchService { 1175 return c.search 1176 } 1177 1178 func newcheckmarxOneExecuteScanUtilsBundle(workspace string, client *github.Client) checkmarxOneExecuteScanUtils { 1179 utils := checkmarxOneExecuteScanUtilsBundle{ 1180 workspace: workspace, 1181 } 1182 if client != nil { 1183 utils.issues = client.Issues 1184 utils.search = client.Search 1185 } 1186 return &utils 1187 }