2023-05-05 14:05:58 +02:00
package cmd
import (
"archive/zip"
"context"
2024-06-03 10:01:50 +02:00
"encoding/json"
2023-05-05 14:05:58 +02:00
"fmt"
"io"
2024-06-03 10:01:50 +02:00
"maps"
2023-05-05 14:05:58 +02:00
"math"
2024-11-27 15:54:19 +01:00
"net/url"
2023-05-05 14:05:58 +02:00
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"time"
checkmarxOne "github.com/SAP/jenkins-library/pkg/checkmarxone"
piperGithub "github.com/SAP/jenkins-library/pkg/github"
piperHttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
2025-09-01 09:35:22 +02:00
"github.com/SAP/jenkins-library/pkg/orchestrator"
2023-05-05 14:05:58 +02:00
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/reporting"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/toolrecord"
"github.com/bmatcuk/doublestar"
2025-01-22 14:06:49 +01:00
"github.com/google/go-github/v68/github"
2023-05-05 14:05:58 +02:00
)
type checkmarxOneExecuteScanUtils interface {
FileInfoHeader ( fi os . FileInfo ) ( * zip . FileHeader , error )
Stat ( name string ) ( os . FileInfo , error )
Open ( name string ) ( * os . File , error )
WriteFile ( filename string , data [] byte , perm os . FileMode ) error
MkdirAll ( path string , perm os . FileMode ) error
PathMatch ( pattern , name string ) ( bool , error )
GetWorkspace () string
GetIssueService () * github . IssuesService
GetSearchService () * github . SearchService
}
type checkmarxOneExecuteScanHelper struct {
ctx context . Context
config checkmarxOneExecuteScanOptions
sys checkmarxOne . System
influx * checkmarxOneExecuteScanInflux
utils checkmarxOneExecuteScanUtils
Project * checkmarxOne . Project
Group * checkmarxOne . Group
App * checkmarxOne . Application
reports [] piperutils . Path
}
type checkmarxOneExecuteScanUtilsBundle struct {
workspace string
issues * github . IssuesService
search * github . SearchService
}
func checkmarxOneExecuteScan ( config checkmarxOneExecuteScanOptions , _ * telemetry . CustomData , influx * checkmarxOneExecuteScanInflux ) {
// TODO: Setup connection with Splunk, influxDB?
cx1sh , err := Authenticate ( config , influx )
if err != nil {
log . Entry (). WithError ( err ). Fatalf ( "failed to create Cx1 client: %s" , err )
}
err = runStep ( config , influx , & cx1sh )
if err != nil {
log . Entry (). WithError ( err ). Fatalf ( "Failed to run CheckmarxOne scan." )
}
influx . step_data . fields . checkmarxOne = true
}
func runStep ( config checkmarxOneExecuteScanOptions , influx * checkmarxOneExecuteScanInflux , cx1sh * checkmarxOneExecuteScanHelper ) error {
err := error ( nil )
2025-10-14 16:26:12 +02:00
if len ( cx1sh . config . ProjectID ) == 0 {
cx1sh . Project , err = cx1sh . GetProjectByName ()
if err != nil && err . Error () != "project not found" {
return fmt . Errorf ( "failed to get project: %s" , err )
}
} else {
cx1sh . Project , err = cx1sh . GetProjectByID ( cx1sh . config . ProjectID )
if err != nil {
return fmt . Errorf ( "failed to get project by ID: %s" , err )
}
2023-05-05 14:05:58 +02:00
}
2024-06-03 10:01:50 +02:00
if len ( config . GroupName ) > 0 {
cx1sh . Group , err = cx1sh . GetGroup () // used when creating a project and when generating a SARIF report
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "failed to get group" )
}
2023-05-05 14:05:58 +02:00
}
if cx1sh . Project == nil {
2025-10-14 16:26:12 +02:00
if len ( config . ApplicationID ) > 0 {
cx1sh . App , err = cx1sh . GetApplicationByID ( config . ApplicationID )
if err != nil {
return fmt . Errorf ( "failed to get application by ID: %v" , err )
}
} else if len ( config . ApplicationName ) > 0 {
2025-07-10 17:59:32 +02:00
cx1sh . App , err = cx1sh . GetApplication () // read application name from piper config (optional) and get ID from CxONE API
if err != nil {
return fmt . Errorf ( "failed to get application: %v" , err )
}
2023-05-05 14:05:58 +02:00
}
cx1sh . Project , err = cx1sh . CreateProject () // requires groups, repoUrl, mainBranch, origin, tags, criticality
if err != nil {
return fmt . Errorf ( "failed to create project: %s" , err )
}
2023-09-05 21:49:27 +02:00
} else {
cx1sh . Project , err = cx1sh . GetProjectByID ( cx1sh . Project . ProjectID )
if err != nil {
return fmt . Errorf ( "failed to get project by ID: %s" , err )
} else {
if len ( cx1sh . Project . Applications ) > 0 {
appId := cx1sh . Project . Applications [ 0 ]
cx1sh . App , err = cx1sh . GetApplicationByID ( cx1sh . Project . Applications [ 0 ])
if err != nil {
return fmt . Errorf ( "failed to retrieve information for project's assigned application %v" , appId )
}
}
}
2023-05-05 14:05:58 +02:00
}
err = cx1sh . SetProjectPreset ()
if err != nil {
return fmt . Errorf ( "failed to set preset: %s" , err )
}
2024-06-03 10:01:50 +02:00
// update project's tags
if ( len ( config . ProjectTags )) > 0 {
err = cx1sh . UpdateProjectTags ()
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "failed to tags the project: %s" , err )
}
}
2025-09-18 15:09:37 +02:00
fullScanCycle , err := strconv . Atoi ( cx1sh . config . FullScanCycle )
if err != nil {
log . SetErrorCategory ( log . ErrorConfiguration )
return fmt . Errorf ( "invalid configuration value for fullScanCycle %v, must be a positive int" , cx1sh . config . FullScanCycle )
}
2025-09-11 09:55:04 +02:00
branch , isPR , baseBranch := cx1sh . GetScanBranch ()
2025-09-18 15:09:37 +02:00
scans , err := cx1sh . GetLastScans ( fullScanCycle + 1 , branch )
2023-05-05 14:05:58 +02:00
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "failed to get last 10 scans" )
}
if config . VerifyOnly {
if len ( scans ) > 0 {
results , err := cx1sh . ParseResults ( & scans [ 0 ]) // incl report-gen
if err != nil {
return fmt . Errorf ( "failed to get scan results: %s" , err )
}
err = cx1sh . CheckCompliance ( & scans [ 0 ], & results )
if err != nil {
log . SetErrorCategory ( log . ErrorCompliance )
return fmt . Errorf ( "project %v not compliant: %s" , cx1sh . Project . Name , err )
}
return nil
} else {
log . Entry (). Warnf ( "Cannot load scans for project %v, verification only mode aborted" , cx1sh . Project . Name )
}
}
2025-09-18 15:09:37 +02:00
incremental , fullScanExists , contiguousIncrScansCurrentBranch , err := cx1sh . IncrementalOrFull ( scans ) // requires: scan list
2023-05-05 14:05:58 +02:00
if err != nil {
return fmt . Errorf ( "failed to determine incremental or full scan configuration: %s" , err )
}
2023-12-12 20:24:03 +01:00
if config . Incremental {
2025-09-11 09:55:04 +02:00
log . Entry (). Info ( "If you change your file filter pattern it is recommended to run a Full scan instead of an incremental, to ensure full code coverage." )
2023-12-12 20:24:03 +01:00
}
2023-05-05 14:05:58 +02:00
zipFile , err := cx1sh . ZipFiles ()
if err != nil {
return fmt . Errorf ( "failed to create zip file: %s" , err )
}
uploadLink , err := cx1sh . UploadScanContent ( zipFile ) // POST /api/uploads + PUT /{uploadLink}
if err != nil {
return fmt . Errorf ( "failed to get upload URL: %s" , err )
}
// TODO : The step structure should allow to enable different scanners: SAST, KICKS, SCA
2025-09-11 09:55:04 +02:00
var scan * checkmarxOne . Scan
// user requested an incremental scan on a branch, and the project has a Primary Branch set, not in PR context and no full scan on the branch
if config . Incremental && ! isPR && ! fullScanExists && cx1sh . Project . MainBranch != "" && cx1sh . Project . MainBranch != branch {
2025-09-18 15:09:37 +02:00
scansMainBranch , err := cx1sh . GetLastScans ( fullScanCycle + 1 , cx1sh . Project . MainBranch )
if err != nil {
return fmt . Errorf ( "failed to get scans from primary branch %v: %s" , cx1sh . Project . MainBranch , err )
}
// We check if the main branch is eligible for an incremental scan
incrementalMainBranch , _ , contiguousIncrScansMainBranch , err := cx1sh . IncrementalOrFull ( scansMainBranch )
2025-09-11 09:55:04 +02:00
if err != nil {
return fmt . Errorf ( "failed to determine incremental or full scan configuration: %s" , err )
}
log . Entry (). Debugf ( "Main branch %v incremental scan eligibility: %t" , cx1sh . Project . MainBranch , incrementalMainBranch )
2025-09-18 15:09:37 +02:00
if contiguousIncrScansMainBranch + contiguousIncrScansCurrentBranch + 1 >= fullScanCycle { // contiguous incremental scans on main branch and current branch must not exceed fullScanCycle
incrementalMainBranch = false
}
log . Entry (). Debugf ( "Main branch + current branch incremental scan eligibility: %t" , incrementalMainBranch )
2025-09-11 09:55:04 +02:00
scan , err = cx1sh . CreateScanRequest ( incrementalMainBranch , uploadLink , cx1sh . Project . MainBranch ) // this will create a full scan on the current branch if the main branch is not eligible for an incremental scan
} else if config . Incremental && isPR && len ( baseBranch ) > 0 && baseBranch != "n/a" { // running in a PR context, and we have a base branch for the incremental scan
// in a PR context we always want to do an incremental scan
// The scan will be based on the PR's target branch (baseBranch) if there is no full scan on the PR branch
if fullScanExists {
log . Entry (). Debugf ( "A full scan exists on the PR branch %v, so the incremental scan will be based on it" , branch )
scan , err = cx1sh . CreateScanRequest ( true , uploadLink , "" )
} else {
log . Entry (). Debugf ( "There is no full scan on the PR branch %v, so the incremental scan will be based on branch %v" , branch , baseBranch )
scan , err = cx1sh . CreateScanRequest ( true , uploadLink , baseBranch )
}
} else {
scan , err = cx1sh . CreateScanRequest ( incremental , uploadLink , "" )
}
2023-05-05 14:05:58 +02:00
if err != nil {
return fmt . Errorf ( "failed to create scan: %s" , err )
}
// TODO: how to provide other scan parameters like engineConfiguration?
// TODO: potential to persist file exclusions for git?
err = cx1sh . PollScanStatus ( scan )
if err != nil {
return fmt . Errorf ( "failed while polling scan status: %s" , err )
}
results , err := cx1sh . ParseResults ( scan ) // incl report-gen
if err != nil {
return fmt . Errorf ( "failed to get scan results: %s" , err )
}
err = cx1sh . CheckCompliance ( scan , & results )
if err != nil {
log . SetErrorCategory ( log . ErrorCompliance )
return fmt . Errorf ( "project %v not compliant: %s" , cx1sh . Project . Name , err )
}
// TODO: upload logs to Splunk, influxDB?
return nil
}
func Authenticate ( config checkmarxOneExecuteScanOptions , influx * checkmarxOneExecuteScanInflux ) ( checkmarxOneExecuteScanHelper , error ) {
client := & piperHttp . Client {}
2023-09-20 14:38:45 +05:00
ctx , ghClient , err := piperGithub . NewClientBuilder ( config . GithubToken , config . GithubAPIURL ). Build ()
2023-05-05 14:05:58 +02:00
if err != nil {
log . Entry (). WithError ( err ). Warning ( "Failed to get GitHub client" )
}
sys , err := checkmarxOne . NewSystemInstance ( client , config . ServerURL , config . IamURL , config . Tenant , config . APIKey , config . ClientID , config . ClientSecret )
if err != nil {
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 )
}
influx . step_data . fields . checkmarxOne = false
utils := newcheckmarxOneExecuteScanUtilsBundle ( "./" , ghClient )
return checkmarxOneExecuteScanHelper { ctx , config , sys , influx , utils , nil , nil , nil , [] piperutils . Path {}}, nil
}
func ( c * checkmarxOneExecuteScanHelper ) GetProjectByName () ( * checkmarxOne . Project , error ) {
if len ( c . config . ProjectName ) == 0 {
log . Entry (). Fatalf ( "No project name set in the configuration" )
}
// get the Project, if it exists
projects , err := c . sys . GetProjectsByName ( c . config . ProjectName )
if err != nil {
return nil , fmt . Errorf ( "error when trying to load project: %s" , err )
}
for _ , p := range projects {
if p . Name == c . config . ProjectName {
return & p , nil
}
}
return nil , fmt . Errorf ( "project not found" )
}
2023-09-05 21:49:27 +02:00
func ( c * checkmarxOneExecuteScanHelper ) GetProjectByID ( projectId string ) ( * checkmarxOne . Project , error ) {
project , err := c . sys . GetProjectByID ( projectId )
return & project , err
}
2023-05-05 14:05:58 +02:00
func ( c * checkmarxOneExecuteScanHelper ) GetGroup () ( * checkmarxOne . Group , error ) {
if len ( c . config . GroupName ) > 0 {
group , err := c . sys . GetGroupByName ( c . config . GroupName )
if err != nil {
return nil , fmt . Errorf ( "Failed to get Checkmarx One group by Name %v: %s" , c . config . GroupName , err )
}
return & group , nil
}
2023-09-05 21:49:27 +02:00
return nil , fmt . Errorf ( "No group name specified in configuration" )
2023-05-05 14:05:58 +02:00
}
func ( c * checkmarxOneExecuteScanHelper ) GetApplication () ( * checkmarxOne . Application , error ) {
if len ( c . config . ApplicationName ) > 0 {
app , err := c . sys . GetApplicationByName ( c . config . ApplicationName )
if err != nil {
return nil , fmt . Errorf ( "Failed to get Checkmarx One application by Name %v: %s" , c . config . ApplicationName , err )
}
return & app , nil
}
2023-09-05 21:49:27 +02:00
return nil , fmt . Errorf ( "No application name specified in configuration" )
}
func ( c * checkmarxOneExecuteScanHelper ) GetApplicationByID ( applicationId string ) ( * checkmarxOne . Application , error ) {
app , err := c . sys . GetApplicationByID ( applicationId )
if err != nil {
return nil , fmt . Errorf ( "Failed to get Checkmarx One application by Name %v: %s" , c . config . ApplicationName , err )
}
return & app , nil
2023-05-05 14:05:58 +02:00
}
func ( c * checkmarxOneExecuteScanHelper ) CreateProject () ( * checkmarxOne . Project , error ) {
if len ( c . config . Preset ) == 0 {
return nil , fmt . Errorf ( "Preset is required to create a project" )
}
2023-09-05 21:49:27 +02:00
var project checkmarxOne . Project
var err error
var groupIDs [] string = [] string {}
if c . Group != nil {
groupIDs = [] string { c . Group . GroupID }
}
if c . App != nil {
project , err = c . sys . CreateProjectInApplication ( c . config . ProjectName , c . App . ApplicationID , groupIDs )
} else {
2025-10-14 16:26:12 +02:00
// don't allow creation of project at tenant level
return nil , fmt . Errorf ( "No application found in config, project cannot be created" )
//project, err = c.sys.CreateProject(c.config.ProjectName, groupIDs)
2023-09-05 21:49:27 +02:00
}
2023-05-05 14:05:58 +02:00
if err != nil {
return nil , fmt . Errorf ( "Error when trying to create project: %s" , err )
}
log . Entry (). Infof ( "Project %v created" , project . ProjectID )
// new project, set the defaults per pipeline config
err = c . sys . SetProjectPreset ( project . ProjectID , c . config . Preset , true )
if err != nil {
return nil , fmt . Errorf ( "Unable to set preset for project %v to %v: %s" , project . ProjectID , c . config . Preset , err )
}
log . Entry (). Infof ( "Project preset updated to %v" , c . config . Preset )
if len ( c . config . LanguageMode ) != 0 {
err = c . sys . SetProjectLanguageMode ( project . ProjectID , c . config . LanguageMode , true )
if err != nil {
return nil , fmt . Errorf ( "Unable to set languageMode for project %v to %v: %s" , project . ProjectID , c . config . LanguageMode , err )
}
log . Entry (). Infof ( "Project languageMode updated to %v" , c . config . LanguageMode )
}
return & project , nil
}
2024-06-03 10:01:50 +02:00
func ( c * checkmarxOneExecuteScanHelper ) UpdateProjectTags () error {
if len ( c . config . ProjectTags ) > 0 {
tags := make ( map [ string ] string , 0 )
err := json . Unmarshal ([] byte ( c . config . ProjectTags ), & tags )
if err != nil {
log . Entry (). Infof ( "Failed to parse the project tags: %v" , c . config . ProjectTags )
return err
}
// merge new tags to the existing ones
maps . Copy ( c . Project . Tags , tags )
return c . sys . UpdateProject ( c . Project )
}
return nil
}
2023-05-05 14:05:58 +02:00
func ( c * checkmarxOneExecuteScanHelper ) SetProjectPreset () error {
projectConf , err := c . sys . GetProjectConfiguration ( c . Project . ProjectID )
if err != nil {
return fmt . Errorf ( "Failed to retrieve current project configuration: %s" , err )
}
currentPreset := ""
2023-12-12 20:24:03 +01:00
currentLanguageMode := "multi" // piper default
2023-05-05 14:05:58 +02:00
for _ , conf := range projectConf {
if conf . Key == "scan.config.sast.presetName" {
currentPreset = conf . Value
2023-12-12 20:24:03 +01:00
}
if conf . Key == "scan.config.sast.languageMode" {
currentLanguageMode = conf . Value
}
}
if c . config . LanguageMode == "" || strings . EqualFold ( c . config . LanguageMode , "multi" ) { // default multi if blank
if currentLanguageMode != "multi" {
log . Entry (). Info ( "Pipeline yaml requests multi-language scan - updating project configuration" )
c . sys . SetProjectLanguageMode ( c . Project . ProjectID , "multi" , true )
if c . config . Incremental {
log . Entry (). Warn ( "Pipeline yaml requests incremental scan, but switching from 'primary' to 'multi' language mode requires a full scan - switching from incremental to full" )
c . config . Incremental = false
}
}
} else { // primary language mode
if currentLanguageMode != "primary" {
log . Entry (). Info ( "Pipeline yaml requests primary-language scan - updating project configuration" )
c . sys . SetProjectLanguageMode ( c . Project . ProjectID , "primary" , true )
// no need to switch incremental to full here (multi-language scan includes single-language scan coverage)
2023-05-05 14:05:58 +02:00
}
}
if c . config . Preset == "" {
2023-06-01 11:03:01 +02:00
if currentPreset == "" {
return fmt . Errorf ( "must specify the preset in either the pipeline yaml or in the CheckmarxOne project configuration" )
} else {
log . Entry (). Infof ( "Pipeline yaml does not specify a preset, will use project configuration (%v)." , currentPreset )
}
2023-05-05 14:05:58 +02:00
c . config . Preset = currentPreset
} else if currentPreset != c . config . Preset {
log . Entry (). Infof ( "Project configured preset (%v) does not match pipeline yaml (%v) - updating project configuration." , currentPreset , c . config . Preset )
c . sys . SetProjectPreset ( c . Project . ProjectID , c . config . Preset , true )
2023-12-12 20:24:03 +01:00
if c . config . Incremental {
log . Entry (). Warn ( "Changing project settings requires a full scan to take effect - switching from incremental to full" )
c . config . Incremental = false
}
2023-05-05 14:05:58 +02:00
} else {
2023-06-01 11:03:01 +02:00
log . Entry (). Infof ( "Project is already configured to use pipeline preset %v" , currentPreset )
2023-05-05 14:05:58 +02:00
}
return nil
}
2025-09-11 09:55:04 +02:00
func ( c * checkmarxOneExecuteScanHelper ) GetLastScans ( count int , branch string ) ([] checkmarxOne . Scan , error ) {
scans , err := c . sys . GetLastScansByStatus ( c . Project . ProjectID , branch , count , [] string { "Completed" })
2023-05-05 14:05:58 +02:00
if err != nil {
return [] checkmarxOne . Scan {}, fmt . Errorf ( "Failed to get last %d Completed scans for project %v: %s" , count , c . Project . ProjectID , err )
}
return scans , nil
}
2025-09-18 15:09:37 +02:00
func ( c * checkmarxOneExecuteScanHelper ) IncrementalOrFull ( scans [] checkmarxOne . Scan ) ( bool , bool , int , error ) {
2023-05-05 14:05:58 +02:00
incremental := c . config . Incremental
2025-09-18 15:09:37 +02:00
fullScanExists := false
2023-05-05 14:05:58 +02:00
fullScanCycle , err := strconv . Atoi ( c . config . FullScanCycle )
if err != nil {
log . SetErrorCategory ( log . ErrorConfiguration )
2025-09-18 15:09:37 +02:00
return false , false , 0 , fmt . Errorf ( "invalid configuration value for fullScanCycle %v, must be a positive int" , c . config . FullScanCycle )
2023-05-05 14:05:58 +02:00
}
2025-09-18 15:09:37 +02:00
if len ( scans ) == 0 {
return false , false , 0 , nil // no scans exist, so we need to do a full scan
}
var scanIds [] string
for _ , scan := range scans {
scanIds = append ( scanIds , scan . ScanID )
}
scanMetadatas , err := c . sys . GetScanMetadatas ( scanIds )
if err != nil {
2026-02-16 13:56:00 +02:00
return false , false , 0 , fmt . Errorf ( "failed to fetch metadata for scans: %w" , err )
2025-09-18 15:09:37 +02:00
}
contiguousIncrementalScans := 0
for _ , scanMetadata := range scanMetadatas {
if scanMetadata . IsIncremental {
contiguousIncrementalScans ++
} else {
fullScanExists = true
break
}
}
2023-05-05 14:05:58 +02:00
if c . config . IsOptimizedAndScheduled {
incremental = false
2025-09-18 15:09:37 +02:00
} else if incremental && c . config . FullScansScheduled && fullScanCycle > 0 && ( contiguousIncrementalScans + 1 ) >= fullScanCycle {
2023-05-05 14:05:58 +02:00
incremental = false
}
2025-09-18 15:09:37 +02:00
return incremental , fullScanExists , contiguousIncrementalScans , nil
2023-05-05 14:05:58 +02:00
}
func ( c * checkmarxOneExecuteScanHelper ) ZipFiles () ( * os . File , error ) {
zipFile , err := c . zipWorkspaceFiles ( c . config . FilterPattern , c . utils )
if err != nil {
return nil , fmt . Errorf ( "Failed to zip workspace files" )
}
return zipFile , nil
}
func ( c * checkmarxOneExecuteScanHelper ) UploadScanContent ( zipFile * os . File ) ( string , error ) {
uploadUri , err := c . sys . UploadProjectSourceCode ( c . Project . ProjectID , zipFile . Name ())
if err != nil {
return "" , fmt . Errorf ( "Failed to upload source code for project %v: %s" , c . Project . ProjectID , err )
}
log . Entry (). Debugf ( "Source code uploaded for project %v" , c . Project . Name )
err = os . Remove ( zipFile . Name ())
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "Failed to delete zipped source code for project %v" , c . Project . Name )
}
return uploadUri , nil
}
2025-09-11 09:55:04 +02:00
func ( c * checkmarxOneExecuteScanHelper ) GetScanBranch () ( string , bool , string ) {
2023-05-05 14:05:58 +02:00
branch := c . config . Branch
2026-03-17 14:37:30 +02:00
cicdOrch := orchestrator . GetOrchestratorConfigProvider ( nil )
2025-09-01 09:35:22 +02:00
if len ( branch ) == 0 && len ( c . config . GitBranch ) > 0 && c . config . GitBranch != "n/a" {
2024-04-22 18:21:02 +02:00
branch = c . config . GitBranch
2025-09-01 09:35:22 +02:00
} else if len ( branch ) == 0 && ( len ( c . config . GitBranch ) == 0 || c . config . GitBranch == "n/a" ) { // use the branch from the orchestrator by default
cicdBranch := cicdOrch . Branch ()
if cicdBranch != "n/a" {
branch = cicdBranch
} else {
log . Entry (). Info ( "Could not retrieve branch name from orchestrator" )
}
2024-04-22 18:21:02 +02:00
}
2023-05-05 14:05:58 +02:00
if len ( c . config . PullRequestName ) > 0 {
2025-09-11 09:55:04 +02:00
branch = fmt . Sprintf ( "%v-%v" , c . config . PullRequestName , branch )
2025-09-01 09:35:22 +02:00
} else if cicdOrch . IsPullRequest () && cicdOrch . PullRequestConfig (). Branch != "n/a" {
branch = fmt . Sprintf ( "PR%v-%v" , cicdOrch . PullRequestConfig (). Key , cicdOrch . PullRequestConfig (). Branch )
2023-05-05 14:05:58 +02:00
}
2025-09-18 15:09:37 +02:00
if branch == "" {
branch = ".unknown"
log . Entry (). Info ( "No branch name found, using the cxone default '.unknown' as branch name" )
}
2025-09-11 09:55:04 +02:00
baseBranch := cicdOrch . PullRequestConfig (). Base
isPR := cicdOrch . IsPullRequest ()
log . Entry (). Debugf ( "CxOne scan branch was automatically set to : %v" , branch )
return branch , isPR , baseBranch
}
func ( c * checkmarxOneExecuteScanHelper ) CreateScanRequest ( incremental bool , uploadLink string , baseBranch string ) ( * checkmarxOne . Scan , error ) {
sastConfigString := ""
sastConfig := checkmarxOne . ScanConfiguration {}
sastConfig . ScanType = "sast"
sastConfig . Values = make ( map [ string ] string , 0 )
sastConfig . Values [ "incremental" ] = strconv . FormatBool ( incremental )
sastConfig . Values [ "presetName" ] = c . config . Preset // always set, either coming from config or coming from Cx1 configuration
if incremental && len ( baseBranch ) > 0 { // base the incremental scan on the specified base branch
sastConfig . Values [ "baseBranch" ] = baseBranch
sastConfigString = fmt . Sprintf ( "baseBranch: %v, " , baseBranch )
}
sastConfigString = fmt . Sprintf ( "%vincremental %v, preset %v" , sastConfigString , strconv . FormatBool ( incremental ), c . config . Preset )
if len ( c . config . LanguageMode ) > 0 {
sastConfig . Values [ "languageMode" ] = c . config . LanguageMode
sastConfigString = sastConfigString + fmt . Sprintf ( ", languageMode %v" , c . config . LanguageMode )
}
branch , _ , _ := c . GetScanBranch ()
2023-05-05 14:05:58 +02:00
sastConfigString = fmt . Sprintf ( "Cx1 Branch name %v, " , branch ) + sastConfigString
log . Entry (). Infof ( "Will run a scan with the following configuration: %v" , sastConfigString )
configs := [] checkmarxOne . ScanConfiguration { sastConfig }
2024-06-03 10:01:50 +02:00
// add scan's tags
tags := make ( map [ string ] string , 0 )
if len ( c . config . ScanTags ) > 0 {
err := json . Unmarshal ([] byte ( c . config . ScanTags ), & tags )
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "Failed to parse the scan tags: %v" , c . config . ScanTags )
}
}
// add more engines
scan , err := c . sys . ScanProjectZip ( c . Project . ProjectID , uploadLink , branch , configs , tags )
2023-05-05 14:05:58 +02:00
if err != nil {
return nil , fmt . Errorf ( "Failed to run scan on project %v: %s" , c . Project . Name , err )
}
log . Entry (). Debugf ( "Scanning project %v: %v " , c . Project . Name , scan . ScanID )
return & scan , nil
}
func ( c * checkmarxOneExecuteScanHelper ) PollScanStatus ( scan * checkmarxOne . Scan ) error {
statusDetails := "Scan phase: New"
pastStatusDetails := statusDetails
log . Entry (). Info ( statusDetails )
status := "New"
for {
scan_refresh , err := c . sys . GetScan ( scan . ScanID )
if err != nil {
return fmt . Errorf ( "Error while polling scan %v: %s" , scan . ScanID , err )
}
status = scan_refresh . Status
workflow , err := c . sys . GetScanWorkflow ( scan . ScanID )
if err != nil {
return fmt . Errorf ( "Error while getting workflow for scan %v: %s" , scan . ScanID , err )
}
statusDetails = workflow [ len ( workflow ) - 1 ]. Info
if pastStatusDetails != statusDetails {
log . Entry (). Info ( statusDetails )
pastStatusDetails = statusDetails
}
if status == "Completed" || status == "Canceled" || status == "Failed" {
break
}
if pastStatusDetails != statusDetails {
log . Entry (). Info ( statusDetails )
pastStatusDetails = statusDetails
}
log . Entry (). Debug ( "Polling for status: sleeping..." )
time . Sleep ( 10 * time . Second )
}
if status == "Canceled" {
log . SetErrorCategory ( log . ErrorCustom )
return fmt . Errorf ( "Scan %v canceled via web interface" , scan . ScanID )
}
if status == "Failed" {
return fmt . Errorf ( "Checkmarx One scan failed with the following error: %v" , statusDetails )
}
return nil
}
2025-09-01 09:35:22 +02:00
func ( c * checkmarxOneExecuteScanHelper ) PostScanSummaryInPullRequest ( detailedResults * map [ string ] interface {}, insecure bool ) error {
2026-03-17 14:37:30 +02:00
cicdOrch := orchestrator . GetOrchestratorConfigProvider ( nil )
2025-09-01 09:35:22 +02:00
isPullRequest := cicdOrch . IsPullRequest ()
pullRequestId := cicdOrch . PullRequestConfig (). Key
var owner , repository string
if len ( c . config . Repository ) == 0 || len ( c . config . Owner ) == 0 {
log . Entry (). Debug ( "No repository or owner configured, trying to get it from orchestrator" )
repoUrl := cicdOrch . RepoURL ()
if repoUrl != "n/a" {
parsedURL , err := url . Parse ( repoUrl )
if err != nil {
return fmt . Errorf ( "failed to parse repository URL %s: %s" , repoUrl , err )
}
pathParts := strings . Split ( strings . TrimSuffix ( parsedURL . Path , ".git" ), "/" )
if len ( pathParts ) >= 2 {
if len ( c . config . Owner ) == 0 {
owner = pathParts [ len ( pathParts ) - 2 ]
}
if len ( c . config . Repository ) == 0 {
repository = pathParts [ len ( pathParts ) - 1 ]
}
2025-09-17 17:53:34 +02:00
log . Entry (). Debugf ( "Found repository %s and owner %s from orchestrator" , repository , owner )
2025-09-01 09:35:22 +02:00
} else {
return fmt . Errorf ( "failed to extract owner and repository from URL %s" , repoUrl )
}
} else {
log . Entry (). Debug ( "Could not retrieve repository URL from orchestrator" )
}
} else {
owner = c . config . Owner
repository = c . config . Repository
log . Entry (). Debug ( "Using Owner and Repository from configuration: " + owner + "/" + repository )
}
log . Entry (). Debugf ( "Parameters for PR summary: ScanSummaryInPullRequest: %t, isPullRequest: %t, pullRequestId: %s, PullRequestName: %s, GithubAPIURL: %s, GithubToken: %s, Owner: %s, Repository: %s" , c . config . ScanSummaryInPullRequest , isPullRequest , pullRequestId , c . config . PullRequestName , c . config . GithubAPIURL , c . config . GithubToken , owner , repository )
if c . config . ScanSummaryInPullRequest && isPullRequest && pullRequestId != "n/a" && len ( c . config . GithubToken ) > 0 && len ( c . config . GithubAPIURL ) > 0 && len ( owner ) > 0 && len ( repository ) > 0 {
ghIssues := c . utils . GetIssueService ()
log . Entry (). Debugf ( "Creating/updating GitHub issue with check results with PR: %s, GithubAPIURL: %s, Owner: %s, Repository: %s" , c . config . PullRequestName , c . config . GithubAPIURL , owner , repository )
scanReportOverview := checkmarxOne . CreateJSONHeaderReport ( detailedResults )
2025-09-17 17:53:34 +02:00
var criticalSeverityString , highSeverityString , mediumSeverityString , lowSeverityString , criticalComplianceCheckString , highComplianceCheckString , mediumComplianceCheckString , lowComplianceCheckString string
2025-09-01 09:35:22 +02:00
for _ , finding := range * scanReportOverview . Findings {
switch finding . ClassificationName {
case "Critical" :
2025-09-17 17:53:34 +02:00
// TODO: check if config threshold unit is percent or absolute number
if * finding . Audited < int ( math . Ceil (( float64 ( c . config . VulnerabilityThresholdCritical ) / 100.0 ) * float64 ( finding . Total ))) {
criticalComplianceCheckString = ":x:"
} else {
criticalComplianceCheckString = ":white_check_mark:"
}
if finding . Confirmed > 0 {
criticalSeverityString = fmt . Sprintf ( "%s %d (%d confirmed)" , criticalComplianceCheckString , finding . Total -* finding . Audited , finding . Confirmed )
} else {
criticalSeverityString = fmt . Sprintf ( "%s %d" , criticalComplianceCheckString , finding . Total -* finding . Audited )
}
2025-09-01 09:35:22 +02:00
case "High" :
2025-09-17 17:53:34 +02:00
if * finding . Audited < int ( math . Ceil (( float64 ( c . config . VulnerabilityThresholdHigh ) / 100.0 ) * float64 ( finding . Total ))) {
highComplianceCheckString = ":x:"
} else {
highComplianceCheckString = ":white_check_mark:"
}
if finding . Confirmed > 0 {
highSeverityString = fmt . Sprintf ( "%s %d (%d confirmed)" , highComplianceCheckString , finding . Total -* finding . Audited , finding . Confirmed )
} else {
highSeverityString = fmt . Sprintf ( "%s %d" , highComplianceCheckString , finding . Total -* finding . Audited )
}
2025-09-01 09:35:22 +02:00
case "Medium" :
2025-09-17 17:53:34 +02:00
if * finding . Audited < int ( math . Ceil (( float64 ( c . config . VulnerabilityThresholdMedium ) / 100.0 ) * float64 ( finding . Total ))) {
mediumComplianceCheckString = ":x:"
} else {
mediumComplianceCheckString = ":white_check_mark:"
}
if finding . Confirmed > 0 {
mediumSeverityString = fmt . Sprintf ( "%s %d (%d confirmed)" , mediumComplianceCheckString , finding . Total -* finding . Audited , finding . Confirmed )
} else {
mediumSeverityString = fmt . Sprintf ( "%s %d" , mediumComplianceCheckString , finding . Total -* finding . Audited )
}
2025-09-01 09:35:22 +02:00
case "Low" :
if finding . LowPerQuery != nil {
for _ , lowFinding := range * finding . LowPerQuery {
if c . config . VulnerabilityThresholdLowPerQuery {
2025-09-17 17:53:34 +02:00
confirmedLowString := ""
if lowFinding . Confirmed > 0 {
confirmedLowString = fmt . Sprintf ( ", of which %d confirmed" , lowFinding . Confirmed )
}
2025-09-01 09:35:22 +02:00
lowAuditedRequiredPerQuery := min ( int ( math . Ceil ( float64 ( lowFinding . Total ) * float64 ( c . config . VulnerabilityThresholdLow ) / 100.0 )), c . config . VulnerabilityThresholdLowPerQueryMax )
2025-09-17 17:53:34 +02:00
if lowFinding . Audited < lowAuditedRequiredPerQuery {
lowComplianceCheckString = ":x:"
} else {
lowComplianceCheckString = ":white_check_mark:"
}
lowSeverityString = fmt . Sprintf ( "%s%s %d %s (%d audited / %d required%s) <br>" , lowSeverityString , lowComplianceCheckString , lowFinding . Total - lowFinding . Audited , lowFinding . QueryName , lowFinding . Audited , lowAuditedRequiredPerQuery , confirmedLowString )
2025-09-01 09:35:22 +02:00
} else {
2025-09-17 17:53:34 +02:00
lowSeverityString = fmt . Sprintf ( "%s%s %d %s<br>" , lowSeverityString , lowComplianceCheckString , lowFinding . Total - lowFinding . Audited , lowFinding . QueryName )
2025-09-01 09:35:22 +02:00
}
}
}
}
}
var scanIcon string
if insecure {
scanIcon = ":x:"
} else {
scanIcon = ":white_check_mark:"
}
comment := & github . IssueComment {
2025-11-26 09:26:58 +01:00
Body : github . Ptr ( fmt . Sprintf ( `<!-- Piper CxOne Scan Summary -->
# %s Checkmarx %s scan completed
2025-09-01 09:35:22 +02:00
**Project**: %s
**ScanId**: %s
**Preset**: %s
2025-09-17 17:53:34 +02:00
Severity | Number of unaudited findings
2025-09-01 09:35:22 +02:00
--- | ---
:bangbang: Critical | %s
:red_circle: High | %s
:orange_circle: Medium | %s
:yellow_circle: Low | %s
[Go to the scan results](%s)
` , scanIcon , strings . ToLower ( scanReportOverview . ScanType ), c . Project . Name , scanReportOverview . ScanID , scanReportOverview . Preset , criticalSeverityString , highSeverityString , mediumSeverityString , lowSeverityString , scanReportOverview . DeepLink )),
}
pullRequestNumber , err := strconv . Atoi ( pullRequestId )
if err != nil {
return fmt . Errorf ( "failed to parse int from pull request name %s: %s" , c . config . PullRequestName , err )
}
2025-11-26 09:26:58 +01:00
// Check if comment already exists, delete old one to avoid multiple comments
// search for watermark <!-- Piper CxOne Scan Summary -->
comments , _ , err := ghIssues . ListComments ( c . ctx , owner , repository , pullRequestNumber , & github . IssueListCommentsOptions {})
if err != nil {
log . Entry (). Errorf ( "failed to list GitHub issue comments: %s" , err )
} else {
for _ , existingComment := range comments {
if strings . Contains ( * existingComment . Body , "<!-- Piper CxOne Scan Summary -->" ) {
_ , err := ghIssues . DeleteComment ( c . ctx , owner , repository , existingComment . GetID ())
if err != nil {
log . Entry (). Errorf ( "failed to delete old GitHub issue comment: %s" , err )
}
log . Entry (). Infof ( "Deleted old GitHub issue comment for project %v" , c . Project . Name )
break
}
}
}
2025-09-01 09:35:22 +02:00
_ , _ , err = ghIssues . CreateComment ( c . ctx , owner , repository , pullRequestNumber , comment )
if err != nil {
return fmt . Errorf ( "failed to create GitHub issue comment: %s" , err )
}
log . Entry (). Infof ( "Created GitHub issue comment for project %v" , c . Project . Name )
} else {
log . Entry (). Debug ( "Skipping GitHub issue comment creation, no pull request or GitHub configuration provided" )
}
return nil
}
2023-05-05 14:05:58 +02:00
func ( c * checkmarxOneExecuteScanHelper ) CheckCompliance ( scan * checkmarxOne . Scan , detailedResults * map [ string ] interface {}) error {
links := [] piperutils . Path {{ Target : ( * detailedResults )[ "DeepLink" ].( string ), Name : "Checkmarx One Web UI" }}
insecure := false
var insecureResults [] string
var neutralResults [] string
if c . config . VulnerabilityThresholdEnabled {
insecure , insecureResults , neutralResults = c . enforceThresholds ( detailedResults )
scanReport := checkmarxOne . CreateCustomReport ( detailedResults , insecureResults , neutralResults )
2025-09-01 09:35:22 +02:00
// Create scan summary comment in PR
if c . config . ScanSummaryInPullRequest {
err := c . PostScanSummaryInPullRequest ( detailedResults , insecure )
if err != nil {
log . Entry (). Errorf ( "failed to post scan summary in pull request: %s" , err )
}
}
2023-05-05 14:05:58 +02:00
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 {
log . Entry (). Debug ( "Creating/updating GitHub issue with check results" )
gh := reporting . GitHub {
Owner : & c . config . Owner ,
Repository : & c . config . Repository ,
Assignees : & c . config . Assignees ,
IssueService : c . utils . GetIssueService (),
SearchService : c . utils . GetSearchService (),
}
if err := gh . UploadSingleReport ( c . ctx , scanReport ); err != nil {
return fmt . Errorf ( "failed to upload scan results into GitHub: %s" , err )
}
}
paths , err := checkmarxOne . WriteCustomReports ( scanReport , c . Project . Name , c . Project . ProjectID )
if err != nil {
// do not fail until we have a better idea to handle it
log . Entry (). Warning ( "failed to write HTML/MarkDown report file ..." , err )
} else {
c . reports = append ( c . reports , paths ... )
}
}
piperutils . PersistReportsAndLinks ( "checkmarxOneExecuteScan" , c . utils . GetWorkspace (), c . utils , c . reports , links )
c . reportToInflux ( detailedResults )
if insecure {
if c . config . VulnerabilityThresholdResult == "FAILURE" {
log . SetErrorCategory ( log . ErrorCompliance )
return fmt . Errorf ( "the project is not compliant - see report for details" )
}
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 )
} else {
log . Entry (). Infoln ( "Checkmarx One scan finished successfully" )
}
return nil
}
func ( c * checkmarxOneExecuteScanHelper ) GetReportPDF ( scan * checkmarxOne . Scan ) error {
if c . config . GeneratePdfReport {
pdfReportName := c . createReportName ( c . utils . GetWorkspace (), "Cx1_SASTReport_%v.pdf" )
err := c . downloadAndSaveReport ( pdfReportName , scan , "pdf" )
if err != nil {
return fmt . Errorf ( "Report download failed: %s" , err )
} else {
c . reports = append ( c . reports , piperutils . Path { Target : pdfReportName , Mandatory : true })
}
} else {
log . Entry (). Debug ( "Report generation is disabled via configuration" )
}
return nil
}
func ( c * checkmarxOneExecuteScanHelper ) GetReportSARIF ( scan * checkmarxOne . Scan , scanmeta * checkmarxOne . ScanMetadata , results * [] checkmarxOne . ScanResult ) error {
if c . config . ConvertToSarif {
log . Entry (). Info ( "Calling conversion to SARIF function." )
sarif , err := checkmarxOne . ConvertCxJSONToSarif ( c . sys , c . config . ServerURL , results , scanmeta , scan )
if err != nil {
return fmt . Errorf ( "Failed to generate SARIF: %s" , err )
}
paths , err := checkmarxOne . WriteSarif ( sarif )
if err != nil {
return fmt . Errorf ( "Failed to write SARIF: %s" , err )
}
c . reports = append ( c . reports , paths ... )
}
return nil
}
func ( c * checkmarxOneExecuteScanHelper ) GetReportJSON ( scan * checkmarxOne . Scan ) error {
jsonReportName := c . createReportName ( c . utils . GetWorkspace (), "Cx1_SASTReport_%v.json" )
err := c . downloadAndSaveReport ( jsonReportName , scan , "json" )
if err != nil {
return fmt . Errorf ( "Report download failed: %s" , err )
} else {
c . reports = append ( c . reports , piperutils . Path { Target : jsonReportName , Mandatory : true })
}
return nil
}
func ( c * checkmarxOneExecuteScanHelper ) GetHeaderReportJSON ( detailedResults * map [ string ] interface {}) error {
// This is for the SAP-piper-format short-form JSON report
jsonReport := checkmarxOne . CreateJSONHeaderReport ( detailedResults )
paths , err := checkmarxOne . WriteJSONHeaderReport ( jsonReport )
if err != nil {
return fmt . Errorf ( "Failed to write JSON header report: %s" , err )
} else {
// add JSON report to archiving list
c . reports = append ( c . reports , paths ... )
}
return nil
}
func ( c * checkmarxOneExecuteScanHelper ) ParseResults ( scan * checkmarxOne . Scan ) ( map [ string ] interface {}, error ) {
var detailedResults map [ string ] interface {}
scanmeta , err := c . sys . GetScanMetadata ( scan . ScanID )
if err != nil {
return detailedResults , fmt . Errorf ( "Unable to fetch scan metadata for scan %v: %s" , scan . ScanID , err )
}
2023-06-01 11:03:01 +02:00
totalResultCount := uint64 ( 0 )
2023-05-05 14:05:58 +02:00
scansummary , err := c . sys . GetScanSummary ( scan . ScanID )
if err != nil {
2023-06-01 11:03:01 +02:00
/* TODO: scansummary throws a 404 for 0-result scans, once the bug is fixed put this code back. */
// return detailedResults, fmt.Errorf("Unable to fetch scan summary for scan %v: %s", scan.ScanID, err)
} else {
totalResultCount = scansummary . TotalCount ()
2023-05-05 14:05:58 +02:00
}
2023-06-01 11:03:01 +02:00
results , err := c . sys . GetScanResults ( scan . ScanID , totalResultCount )
2023-05-05 14:05:58 +02:00
if err != nil {
return detailedResults , fmt . Errorf ( "Unable to fetch scan results for scan %v: %s" , scan . ScanID , err )
}
detailedResults , err = c . getDetailedResults ( scan , & scanmeta , & results )
if err != nil {
return detailedResults , fmt . Errorf ( "Unable to fetch detailed results for scan %v: %s" , scan . ScanID , err )
}
err = c . GetReportJSON ( scan )
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "Failed to get JSON report" )
}
err = c . GetReportPDF ( scan )
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "Failed to get PDF report" )
}
err = c . GetReportSARIF ( scan , & scanmeta , & results )
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "Failed to get SARIF report" )
}
err = c . GetHeaderReportJSON ( & detailedResults )
if err != nil {
log . Entry (). WithError ( err ). Warnf ( "Failed to generate JSON Header report" )
}
// create toolrecord
toolRecordFileName , err := c . createToolRecordCx ( & detailedResults )
if err != nil {
// do not fail until the framework is well established
log . Entry (). Warning ( "TR_CHECKMARXONE: Failed to create toolrecord file ..." , err )
} else {
c . reports = append ( c . reports , piperutils . Path { Target : toolRecordFileName })
}
return detailedResults , nil
}
func ( c * checkmarxOneExecuteScanHelper ) createReportName ( workspace , reportFileNameTemplate string ) string {
regExpFileName := regexp . MustCompile ( `[^\w\d]` )
timeStamp , _ := time . Now (). Local (). MarshalText ()
return filepath . Join ( workspace , fmt . Sprintf ( reportFileNameTemplate , regExpFileName . ReplaceAllString ( string ( timeStamp ), "_" )))
}
func ( c * checkmarxOneExecuteScanHelper ) downloadAndSaveReport ( reportFileName string , scan * checkmarxOne . Scan , reportType string ) error {
report , err := c . generateAndDownloadReport ( scan , reportType )
if err != nil {
2026-02-16 13:56:00 +02:00
return fmt . Errorf ( "failed to download the report: %w" , err )
2023-05-05 14:05:58 +02:00
}
log . Entry (). Debugf ( "Saving report to file %v..." , reportFileName )
return c . utils . WriteFile ( reportFileName , report , 0 o700 )
}
func ( c * checkmarxOneExecuteScanHelper ) generateAndDownloadReport ( scan * checkmarxOne . Scan , reportType string ) ([] byte , error ) {
var finalStatus checkmarxOne . ReportStatus
report , err := c . sys . RequestNewReport ( scan . ScanID , scan . ProjectID , scan . Branch , reportType )
if err != nil {
2026-02-16 13:56:00 +02:00
return [] byte {}, fmt . Errorf ( "failed to request new report: %w" , err )
2023-05-05 14:05:58 +02:00
}
for {
finalStatus , err = c . sys . GetReportStatus ( report )
if err != nil {
2026-02-16 13:56:00 +02:00
return [] byte {}, fmt . Errorf ( "failed to get report status: %w" , err )
2023-05-05 14:05:58 +02:00
}
if finalStatus . Status == "completed" {
break
2023-06-01 11:03:01 +02:00
} else if finalStatus . Status == "failed" {
return [] byte {}, fmt . Errorf ( "report generation failed" )
2023-05-05 14:05:58 +02:00
}
time . Sleep ( 10 * time . Second )
}
if finalStatus . Status == "completed" {
return c . sys . DownloadReport ( finalStatus . ReportURL )
}
2023-06-01 11:03:01 +02:00
2023-05-05 14:05:58 +02:00
return [] byte {}, fmt . Errorf ( "unexpected status %v recieved" , finalStatus . Status )
}
func ( c * checkmarxOneExecuteScanHelper ) getNumCoherentIncrementalScans ( scans [] checkmarxOne . Scan ) int {
count := 0
for _ , scan := range scans {
inc , err := scan . IsIncremental ()
if ! inc && err == nil {
break
}
count ++
}
return count
}
func ( c * checkmarxOneExecuteScanHelper ) getDetailedResults ( scan * checkmarxOne . Scan , scanmeta * checkmarxOne . ScanMetadata , results * [] checkmarxOne . ScanResult ) ( map [ string ] interface {}, error ) {
// this converts the JSON format results from Cx1 into the "resultMap" structure used in other parts of this step (influx etc)
resultMap := map [ string ] interface {}{}
resultMap [ "InitiatorName" ] = scan . Initiator
resultMap [ "Owner" ] = "Cx1 Gap: no project owner" // TODO: check for functionality
resultMap [ "ScanId" ] = scan . ScanID
resultMap [ "ProjectId" ] = c . Project . ProjectID
resultMap [ "ProjectName" ] = c . Project . Name
2023-09-05 21:49:27 +02:00
resultMap [ "Group" ] = ""
resultMap [ "GroupFullPathOnReportDate" ] = ""
if c . App != nil {
resultMap [ "Application" ] = c . App . ApplicationID
resultMap [ "ApplicationFullPathOnReportDate" ] = c . App . Name
} else {
resultMap [ "Application" ] = ""
resultMap [ "ApplicationFullPathOnReportDate" ] = ""
}
2023-05-05 14:05:58 +02:00
resultMap [ "ScanStart" ] = scan . CreatedAt
scanCreated , err := time . Parse ( time . RFC3339 , scan . CreatedAt )
if err != nil {
log . Entry (). Warningf ( "Failed to parse string %v into time: %s" , scan . CreatedAt , err )
resultMap [ "ScanTime" ] = "Error parsing scan.CreatedAt"
} else {
scanFinished , err := time . Parse ( time . RFC3339 , scan . UpdatedAt )
if err != nil {
log . Entry (). Warningf ( "Failed to parse string %v into time: %s" , scan . UpdatedAt , err )
resultMap [ "ScanTime" ] = "Error parsing scan.UpdatedAt"
} else {
difference := scanFinished . Sub ( scanCreated )
resultMap [ "ScanTime" ] = difference . String ()
}
}
resultMap [ "LinesOfCodeScanned" ] = scanmeta . LOC
resultMap [ "FilesScanned" ] = scanmeta . FileCount
2023-12-12 20:24:03 +01:00
version , err := c . sys . GetVersion ()
if err != nil {
resultMap [ "ToolVersion" ] = "Error fetching current version"
} else {
resultMap [ "ToolVersion" ] = fmt . Sprintf ( "CxOne: %v, SAST: %v, KICS: %v" , version . CxOne , version . SAST , version . KICS )
}
2023-05-05 14:05:58 +02:00
if scanmeta . IsIncremental {
resultMap [ "ScanType" ] = "Incremental"
} else {
resultMap [ "ScanType" ] = "Full"
}
resultMap [ "Preset" ] = scanmeta . PresetName
2024-11-27 15:54:19 +01:00
resultMap [ "DeepLink" ] = fmt . Sprintf ( "%v/projects/%v/overview?branch=%v" , c . config . ServerURL , c . Project . ProjectID , url . QueryEscape ( scan . Branch ))
2023-05-05 14:05:58 +02:00
resultMap [ "ReportCreationTime" ] = time . Now (). String ()
2025-07-24 14:22:05 +02:00
resultMap [ "Critical" ] = map [ string ] int {}
2023-05-05 14:05:58 +02:00
resultMap [ "High" ] = map [ string ] int {}
resultMap [ "Medium" ] = map [ string ] int {}
resultMap [ "Low" ] = map [ string ] int {}
resultMap [ "Information" ] = map [ string ] int {}
if len ( * results ) > 0 {
for _ , result := range * results {
key := "Information"
switch result . Severity {
2025-07-24 14:22:05 +02:00
case "CRITICAL" :
key = "Critical"
2023-05-05 14:05:58 +02:00
case "HIGH" :
key = "High"
case "MEDIUM" :
key = "Medium"
case "LOW" :
key = "Low"
case "INFORMATION" :
default :
key = "Information"
}
var submap map [ string ] int
if resultMap [ key ] == nil {
submap = map [ string ] int {}
resultMap [ key ] = submap
} else {
submap = resultMap [ key ].( map [ string ] int )
}
submap [ "Issues" ] ++
auditState := "ToVerify"
switch result . State {
case "NOT_EXPLOITABLE" :
auditState = "NotExploitable"
case "CONFIRMED" :
auditState = "Confirmed"
case "URGENT" , "URGENT " :
auditState = "Urgent"
case "PROPOSED_NOT_EXPLOITABLE" :
auditState = "ProposedNotExploitable"
case "TO_VERIFY" :
default :
auditState = "ToVerify"
}
submap [ auditState ] ++
if auditState != "NotExploitable" {
submap [ "NotFalsePositive" ] ++
}
}
// if the flag is switched on, build the list of Low findings per query
if c . config . VulnerabilityThresholdLowPerQuery {
var lowPerQuery = map [ string ] map [ string ] int {}
for _ , result := range * results {
if result . Severity != "LOW" {
continue
}
key := result . Data . QueryName
var submap map [ string ] int
if lowPerQuery [ key ] == nil {
submap = map [ string ] int {}
lowPerQuery [ key ] = submap
} else {
submap = lowPerQuery [ key ]
}
submap [ "Issues" ] ++
auditState := "ToVerify"
switch result . State {
case "NOT_EXPLOITABLE" :
auditState = "NotExploitable"
case "CONFIRMED" :
auditState = "Confirmed"
case "URGENT" , "URGENT " :
auditState = "Urgent"
case "PROPOSED_NOT_EXPLOITABLE" :
auditState = "ProposedNotExploitable"
case "TO_VERIFY" :
default :
auditState = "ToVerify"
}
submap [ auditState ] ++
if auditState != "NotExploitable" {
submap [ "NotFalsePositive" ] ++
}
}
resultMap [ "LowPerQuery" ] = lowPerQuery
}
}
return resultMap , nil
}
func ( c * checkmarxOneExecuteScanHelper ) zipWorkspaceFiles ( filterPattern string , utils checkmarxOneExecuteScanUtils ) ( * os . File , error ) {
zipFileName := filepath . Join ( utils . GetWorkspace (), "workspace.zip" )
2025-09-11 09:55:04 +02:00
log . Entry (). Infof ( "Zipping files using filter: %v" , filterPattern )
2023-05-05 14:05:58 +02:00
patterns := piperutils . Trim ( strings . Split ( filterPattern , "," ))
sort . Strings ( patterns )
zipFile , err := os . Create ( zipFileName )
if err != nil {
2026-02-16 13:56:00 +02:00
return zipFile , fmt . Errorf ( "failed to create archive of project sources: %w" , err )
2023-05-05 14:05:58 +02:00
}
defer zipFile . Close ()
err = c . zipFolder ( utils . GetWorkspace (), zipFile , patterns , utils )
if err != nil {
2026-02-16 13:56:00 +02:00
return nil , fmt . Errorf ( "failed to compact folder: %w" , err )
2023-05-05 14:05:58 +02:00
}
return zipFile , nil
}
func ( c * checkmarxOneExecuteScanHelper ) zipFolder ( source string , zipFile io . Writer , patterns [] string , utils checkmarxOneExecuteScanUtils ) error {
archive := zip . NewWriter ( zipFile )
defer archive . Close ()
log . Entry (). Infof ( "Zipping %v into workspace.zip" , source )
info , err := utils . Stat ( source )
if err != nil {
return nil
}
var baseDir string
if info . IsDir () {
baseDir = filepath . Base ( source )
}
fileCount := 0
err = filepath . Walk ( source , func ( path string , info os . FileInfo , err error ) error {
if err != nil {
return err
}
if ! info . Mode (). IsRegular () || info . Size () == 0 {
return nil
}
2024-10-17 17:16:14 +02:00
fileName := strings . TrimPrefix ( path , baseDir )
2023-05-05 14:05:58 +02:00
noMatch , err := c . isFileNotMatchingPattern ( patterns , path , info , utils )
if err != nil || noMatch {
2024-10-17 17:16:14 +02:00
if noMatch {
log . Entry (). Debugf ( "Excluded %s" , fileName )
}
2023-05-05 14:05:58 +02:00
return err
}
writer , err := archive . Create ( fileName )
if err != nil {
return err
}
file , err := utils . Open ( path )
if err != nil {
return err
}
defer file . Close ()
_ , err = io . Copy ( writer , file )
2024-10-17 17:16:14 +02:00
if err == nil {
log . Entry (). Debugf ( "Zipped %s" , fileName )
}
2023-05-05 14:05:58 +02:00
fileCount ++
return err
})
log . Entry (). Infof ( "Zipped %d files" , fileCount )
err = c . handleZeroFilesZipped ( source , err , fileCount )
return err
}
func ( c * checkmarxOneExecuteScanHelper ) adaptHeader ( info os . FileInfo , header * zip . FileHeader ) {
if info . IsDir () {
header . Name += "/"
} else {
header . Method = zip . Deflate
}
}
func ( c * checkmarxOneExecuteScanHelper ) handleZeroFilesZipped ( source string , err error , fileCount int ) error {
if err == nil && fileCount == 0 {
log . SetErrorCategory ( log . ErrorConfiguration )
err = fmt . Errorf ( "filterPattern matched no files or workspace directory '%s' was empty" , source )
}
return err
}
// isFileNotMatchingPattern checks if file path does not match one of the patterns.
// If it matches a negative pattern (starting with '!') then true is returned.
//
// If it is a directory, false is returned.
// If no patterns are provided, false is returned.
func ( c * checkmarxOneExecuteScanHelper ) isFileNotMatchingPattern ( patterns [] string , path string , info os . FileInfo , utils checkmarxOneExecuteScanUtils ) ( bool , error ) {
if len ( patterns ) == 0 || info . IsDir () {
return false , nil
}
2025-06-02 11:17:51 +02:00
// Check if it is matched by at least one include pattern
includeMatch := false
for _ , pattern := range patterns {
if strings . HasPrefix ( pattern , "!" ) {
continue
}
match , err := utils . PathMatch ( pattern , path )
if err != nil {
2026-02-16 13:56:00 +02:00
return false , fmt . Errorf ( "Pattern %v could not get executed: %w" , pattern , err )
2025-06-02 11:17:51 +02:00
}
if match {
includeMatch = true
break
}
}
if ! includeMatch {
return true , nil // if there is no include pattern matching, the file is necessarily excluded
}
// Check if it is matched by at least one exclude pattern
2023-05-05 14:05:58 +02:00
for _ , pattern := range patterns {
if strings . HasPrefix ( pattern , "!" ) {
pattern = strings . TrimLeft ( pattern , "!" )
2025-06-02 11:17:51 +02:00
} else {
continue
2023-05-05 14:05:58 +02:00
}
match , err := utils . PathMatch ( pattern , path )
if err != nil {
2026-02-16 13:56:00 +02:00
return false , fmt . Errorf ( "Pattern %v could not get executed: %w" , pattern , err )
2023-05-05 14:05:58 +02:00
}
2025-06-02 11:17:51 +02:00
if match { // match with an exclude pattern, the file is excluded
return true , nil
2023-05-05 14:05:58 +02:00
}
}
2025-06-02 11:17:51 +02:00
return false , nil
2023-05-05 14:05:58 +02:00
}
func ( c * checkmarxOneExecuteScanHelper ) createToolRecordCx ( results * map [ string ] interface {}) ( string , error ) {
workspace := c . utils . GetWorkspace ()
record := toolrecord . New ( c . utils , workspace , "checkmarxOne" , c . config . ServerURL )
// Project
err := record . AddKeyData ( "project" ,
( * results )[ "ProjectId" ].( string ),
( * results )[ "ProjectName" ].( string ),
"" )
if err != nil {
return "" , err
}
// Scan
err = record . AddKeyData ( "scanid" ,
( * results )[ "ScanId" ].( string ),
( * results )[ "ScanId" ].( string ),
( * results )[ "DeepLink" ].( string ))
if err != nil {
return "" , err
}
err = record . Persist ()
if err != nil {
return "" , err
}
return record . GetFileName (), nil
}
func ( c * checkmarxOneExecuteScanHelper ) enforceThresholds ( results * map [ string ] interface {}) ( bool , [] string , [] string ) {
neutralResults := [] string {}
insecureResults := [] string {}
insecure := false
2025-07-24 14:22:05 +02:00
cxCriticalThreshold := c . config . VulnerabilityThresholdCritical
2023-05-05 14:05:58 +02:00
cxHighThreshold := c . config . VulnerabilityThresholdHigh
cxMediumThreshold := c . config . VulnerabilityThresholdMedium
cxLowThreshold := c . config . VulnerabilityThresholdLow
cxLowThresholdPerQuery := c . config . VulnerabilityThresholdLowPerQuery
cxLowThresholdPerQueryMax := c . config . VulnerabilityThresholdLowPerQueryMax
2025-09-17 17:53:34 +02:00
// findings are audited if they are in state Confirmed, Urgent or NotExploitable
criticalValue := ( * results )[ "Critical" ].( map [ string ] int )[ "ToVerify" ] + ( * results )[ "Critical" ].( map [ string ] int )[ "ProposedNotExploitable" ]
confirmedCriticalValue := ( * results )[ "Critical" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "Critical" ].( map [ string ] int )[ "Urgent" ]
highValue := ( * results )[ "High" ].( map [ string ] int )[ "ToVerify" ] + ( * results )[ "High" ].( map [ string ] int )[ "ProposedNotExploitable" ]
confirmedHighValue := ( * results )[ "High" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "High" ].( map [ string ] int )[ "Urgent" ]
mediumValue := ( * results )[ "Medium" ].( map [ string ] int )[ "ToVerify" ] + ( * results )[ "Medium" ].( map [ string ] int )[ "ProposedNotExploitable" ]
confirmedMediumValue := ( * results )[ "Medium" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "Medium" ].( map [ string ] int )[ "Urgent" ]
lowValue := ( * results )[ "Low" ].( map [ string ] int )[ "ToVerify" ] + ( * results )[ "Low" ].( map [ string ] int )[ "ProposedNotExploitable" ]
confirmedLowValue := ( * results )[ "Low" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "Low" ].( map [ string ] int )[ "Urgent" ]
2023-05-05 14:05:58 +02:00
var unit string
2025-07-24 14:22:05 +02:00
criticalViolation := ""
2023-05-05 14:05:58 +02:00
highViolation := ""
mediumViolation := ""
lowViolation := ""
if c . config . VulnerabilityThresholdUnit == "percentage" {
unit = "%"
2025-09-17 17:53:34 +02:00
criticalAudited := ( * results )[ "Critical" ].( map [ string ] int )[ "NotExploitable" ] + ( * results )[ "Critical" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "Critical" ].( map [ string ] int )[ "Urgent" ]
2025-07-24 14:22:05 +02:00
criticalOverall := ( * results )[ "Critical" ].( map [ string ] int )[ "Issues" ]
if criticalOverall == 0 {
criticalAudited = 1
criticalOverall = 1
}
2025-09-17 17:53:34 +02:00
highAudited := ( * results )[ "High" ].( map [ string ] int )[ "NotExploitable" ] + ( * results )[ "High" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "High" ].( map [ string ] int )[ "Urgent" ]
2023-05-05 14:05:58 +02:00
highOverall := ( * results )[ "High" ].( map [ string ] int )[ "Issues" ]
if highOverall == 0 {
highAudited = 1
highOverall = 1
}
2025-09-17 17:53:34 +02:00
mediumAudited := ( * results )[ "Medium" ].( map [ string ] int )[ "NotExploitable" ] + ( * results )[ "Medium" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "Medium" ].( map [ string ] int )[ "Urgent" ]
2023-05-05 14:05:58 +02:00
mediumOverall := ( * results )[ "Medium" ].( map [ string ] int )[ "Issues" ]
if mediumOverall == 0 {
mediumAudited = 1
mediumOverall = 1
}
2025-09-17 17:53:34 +02:00
lowAudited := ( * results )[ "Low" ].( map [ string ] int )[ "Confirmed" ] + ( * results )[ "Low" ].( map [ string ] int )[ "NotExploitable" ] + ( * results )[ "Low" ].( map [ string ] int )[ "Urgent" ]
2023-05-05 14:05:58 +02:00
lowOverall := ( * results )[ "Low" ].( map [ string ] int )[ "Issues" ]
if lowOverall == 0 {
lowAudited = 1
lowOverall = 1
}
2025-07-24 14:22:05 +02:00
criticalValue = int ( float32 ( criticalAudited ) / float32 ( criticalOverall ) * 100.0 )
2023-05-05 14:05:58 +02:00
highValue = int ( float32 ( highAudited ) / float32 ( highOverall ) * 100.0 )
mediumValue = int ( float32 ( mediumAudited ) / float32 ( mediumOverall ) * 100.0 )
lowValue = int ( float32 ( lowAudited ) / float32 ( lowOverall ) * 100.0 )
2025-07-24 14:22:05 +02:00
if criticalValue < cxCriticalThreshold {
insecure = true
criticalViolation = fmt . Sprintf ( "<-- %v %v deviation" , cxCriticalThreshold - criticalValue , unit )
}
2023-05-05 14:05:58 +02:00
if highValue < cxHighThreshold {
insecure = true
highViolation = fmt . Sprintf ( "<-- %v %v deviation" , cxHighThreshold - highValue , unit )
}
if mediumValue < cxMediumThreshold {
insecure = true
mediumViolation = fmt . Sprintf ( "<-- %v %v deviation" , cxMediumThreshold - mediumValue , unit )
}
// if the flag is switched on, calculate the Low findings threshold per query
if cxLowThresholdPerQuery {
2023-06-01 11:03:01 +02:00
if ( * results )[ "LowPerQuery" ] != nil {
lowPerQueryMap := ( * results )[ "LowPerQuery" ].( map [ string ] map [ string ] int )
2023-05-05 14:05:58 +02:00
for lowQuery , resultsLowQuery := range lowPerQueryMap {
2025-09-17 17:53:34 +02:00
lowAuditedPerQuery := resultsLowQuery [ "Confirmed" ] + resultsLowQuery [ "NotExploitable" ] + resultsLowQuery [ "Urgent" ]
2023-05-05 14:05:58 +02:00
lowOverallPerQuery := resultsLowQuery [ "Issues" ]
2025-09-01 09:35:22 +02:00
lowAuditedRequiredPerQuery := min ( int ( math . Ceil ( float64 ( lowOverallPerQuery ) * float64 ( cxLowThreshold ) / 100.0 )), cxLowThresholdPerQueryMax )
2023-05-05 14:05:58 +02:00
if lowAuditedPerQuery < lowAuditedRequiredPerQuery && lowAuditedPerQuery < cxLowThresholdPerQueryMax {
insecure = true
msgSeperator := "|"
if lowViolation == "" {
msgSeperator = "<--"
}
lowViolation += fmt . Sprintf ( " %v query: %v, audited: %v, required: %v " , msgSeperator , lowQuery , lowAuditedPerQuery , lowAuditedRequiredPerQuery )
}
}
}
} else { // calculate the Low findings threshold in total
if lowValue < cxLowThreshold {
insecure = true
lowViolation = fmt . Sprintf ( "<-- %v %v deviation" , cxLowThreshold - lowValue , unit )
}
}
}
if c . config . VulnerabilityThresholdUnit == "absolute" {
unit = " findings"
2025-07-24 14:22:05 +02:00
if criticalValue > cxCriticalThreshold {
insecure = true
criticalViolation = fmt . Sprintf ( "<-- %v%v deviation" , criticalValue - cxCriticalThreshold , unit )
}
2023-05-05 14:05:58 +02:00
if highValue > cxHighThreshold {
insecure = true
highViolation = fmt . Sprintf ( "<-- %v%v deviation" , highValue - cxHighThreshold , unit )
}
if mediumValue > cxMediumThreshold {
insecure = true
mediumViolation = fmt . Sprintf ( "<-- %v%v deviation" , mediumValue - cxMediumThreshold , unit )
}
if lowValue > cxLowThreshold {
insecure = true
lowViolation = fmt . Sprintf ( "<-- %v%v deviation" , lowValue - cxLowThreshold , unit )
}
}
2025-09-17 17:53:34 +02:00
var confirmedCriticalString , confirmedHighString , confirmedMediumString , confirmedLowString string
if confirmedCriticalValue > 0 {
confirmedCriticalString = fmt . Sprintf ( " (of which %v confirmed)" , confirmedCriticalValue )
}
if confirmedHighValue > 0 {
confirmedHighString = fmt . Sprintf ( " (of which %v confirmed)" , confirmedHighValue )
}
if confirmedMediumValue > 0 {
confirmedMediumString = fmt . Sprintf ( " (of which %v confirmed)" , confirmedMediumValue )
}
if confirmedLowValue > 0 {
confirmedLowString = fmt . Sprintf ( " (of which %v confirmed)" , confirmedLowValue )
}
criticalText := fmt . Sprintf ( "Critical %v%v %v %v" , criticalValue , unit , confirmedCriticalString , criticalViolation )
highText := fmt . Sprintf ( "High %v%v %v %v" , highValue , unit , confirmedHighString , highViolation )
mediumText := fmt . Sprintf ( "Medium %v%v %v %v" , mediumValue , unit , confirmedMediumString , mediumViolation )
lowText := fmt . Sprintf ( "Low %v%v %v %v" , lowValue , unit , confirmedLowString , lowViolation )
log . Entry (). Info ( "Result auditing status per severity:" )
2025-07-24 14:22:05 +02:00
if len ( criticalViolation ) > 0 {
insecureResults = append ( insecureResults , criticalText )
log . Entry (). Error ( criticalText )
} else {
neutralResults = append ( neutralResults , criticalText )
log . Entry (). Info ( criticalText )
}
2023-05-05 14:05:58 +02:00
if len ( highViolation ) > 0 {
insecureResults = append ( insecureResults , highText )
log . Entry (). Error ( highText )
} else {
neutralResults = append ( neutralResults , highText )
log . Entry (). Info ( highText )
}
if len ( mediumViolation ) > 0 {
insecureResults = append ( insecureResults , mediumText )
log . Entry (). Error ( mediumText )
} else {
neutralResults = append ( neutralResults , mediumText )
log . Entry (). Info ( mediumText )
}
if len ( lowViolation ) > 0 {
insecureResults = append ( insecureResults , lowText )
log . Entry (). Error ( lowText )
} else {
neutralResults = append ( neutralResults , lowText )
log . Entry (). Info ( lowText )
}
return insecure , insecureResults , neutralResults
}
func ( c * checkmarxOneExecuteScanHelper ) reportToInflux ( results * map [ string ] interface {}) {
2025-07-24 14:22:05 +02:00
c . influx . checkmarxOne_data . fields . critical_issues = ( * results )[ "Critical" ].( map [ string ] int )[ "Issues" ]
c . influx . checkmarxOne_data . fields . critical_not_false_postive = ( * results )[ "Critical" ].( map [ string ] int )[ "NotFalsePositive" ]
c . influx . checkmarxOne_data . fields . critical_not_exploitable = ( * results )[ "Critical" ].( map [ string ] int )[ "NotExploitable" ]
c . influx . checkmarxOne_data . fields . critical_confirmed = ( * results )[ "Critical" ].( map [ string ] int )[ "Confirmed" ]
c . influx . checkmarxOne_data . fields . critical_urgent = ( * results )[ "Critical" ].( map [ string ] int )[ "Urgent" ]
c . influx . checkmarxOne_data . fields . critical_proposed_not_exploitable = ( * results )[ "Critical" ].( map [ string ] int )[ "ProposedNotExploitable" ]
c . influx . checkmarxOne_data . fields . critical_to_verify = ( * results )[ "Critical" ].( map [ string ] int )[ "ToVerify" ]
2023-05-05 14:05:58 +02:00
c . influx . checkmarxOne_data . fields . high_issues = ( * results )[ "High" ].( map [ string ] int )[ "Issues" ]
c . influx . checkmarxOne_data . fields . high_not_false_postive = ( * results )[ "High" ].( map [ string ] int )[ "NotFalsePositive" ]
c . influx . checkmarxOne_data . fields . high_not_exploitable = ( * results )[ "High" ].( map [ string ] int )[ "NotExploitable" ]
c . influx . checkmarxOne_data . fields . high_confirmed = ( * results )[ "High" ].( map [ string ] int )[ "Confirmed" ]
c . influx . checkmarxOne_data . fields . high_urgent = ( * results )[ "High" ].( map [ string ] int )[ "Urgent" ]
c . influx . checkmarxOne_data . fields . high_proposed_not_exploitable = ( * results )[ "High" ].( map [ string ] int )[ "ProposedNotExploitable" ]
c . influx . checkmarxOne_data . fields . high_to_verify = ( * results )[ "High" ].( map [ string ] int )[ "ToVerify" ]
c . influx . checkmarxOne_data . fields . medium_issues = ( * results )[ "Medium" ].( map [ string ] int )[ "Issues" ]
c . influx . checkmarxOne_data . fields . medium_not_false_postive = ( * results )[ "Medium" ].( map [ string ] int )[ "NotFalsePositive" ]
c . influx . checkmarxOne_data . fields . medium_not_exploitable = ( * results )[ "Medium" ].( map [ string ] int )[ "NotExploitable" ]
c . influx . checkmarxOne_data . fields . medium_confirmed = ( * results )[ "Medium" ].( map [ string ] int )[ "Confirmed" ]
c . influx . checkmarxOne_data . fields . medium_urgent = ( * results )[ "Medium" ].( map [ string ] int )[ "Urgent" ]
c . influx . checkmarxOne_data . fields . medium_proposed_not_exploitable = ( * results )[ "Medium" ].( map [ string ] int )[ "ProposedNotExploitable" ]
c . influx . checkmarxOne_data . fields . medium_to_verify = ( * results )[ "Medium" ].( map [ string ] int )[ "ToVerify" ]
c . influx . checkmarxOne_data . fields . low_issues = ( * results )[ "Low" ].( map [ string ] int )[ "Issues" ]
c . influx . checkmarxOne_data . fields . low_not_false_postive = ( * results )[ "Low" ].( map [ string ] int )[ "NotFalsePositive" ]
c . influx . checkmarxOne_data . fields . low_not_exploitable = ( * results )[ "Low" ].( map [ string ] int )[ "NotExploitable" ]
c . influx . checkmarxOne_data . fields . low_confirmed = ( * results )[ "Low" ].( map [ string ] int )[ "Confirmed" ]
c . influx . checkmarxOne_data . fields . low_urgent = ( * results )[ "Low" ].( map [ string ] int )[ "Urgent" ]
c . influx . checkmarxOne_data . fields . low_proposed_not_exploitable = ( * results )[ "Low" ].( map [ string ] int )[ "ProposedNotExploitable" ]
c . influx . checkmarxOne_data . fields . low_to_verify = ( * results )[ "Low" ].( map [ string ] int )[ "ToVerify" ]
c . influx . checkmarxOne_data . fields . information_issues = ( * results )[ "Information" ].( map [ string ] int )[ "Issues" ]
c . influx . checkmarxOne_data . fields . information_not_false_postive = ( * results )[ "Information" ].( map [ string ] int )[ "NotFalsePositive" ]
c . influx . checkmarxOne_data . fields . information_not_exploitable = ( * results )[ "Information" ].( map [ string ] int )[ "NotExploitable" ]
c . influx . checkmarxOne_data . fields . information_confirmed = ( * results )[ "Information" ].( map [ string ] int )[ "Confirmed" ]
c . influx . checkmarxOne_data . fields . information_urgent = ( * results )[ "Information" ].( map [ string ] int )[ "Urgent" ]
c . influx . checkmarxOne_data . fields . information_proposed_not_exploitable = ( * results )[ "Information" ].( map [ string ] int )[ "ProposedNotExploitable" ]
c . influx . checkmarxOne_data . fields . information_to_verify = ( * results )[ "Information" ].( map [ string ] int )[ "ToVerify" ]
c . influx . checkmarxOne_data . fields . initiator_name = ( * results )[ "InitiatorName" ].( string )
c . influx . checkmarxOne_data . fields . owner = ( * results )[ "Owner" ].( string )
c . influx . checkmarxOne_data . fields . scan_id = ( * results )[ "ScanId" ].( string )
c . influx . checkmarxOne_data . fields . project_id = ( * results )[ "ProjectId" ].( string )
c . influx . checkmarxOne_data . fields . projectName = ( * results )[ "ProjectName" ].( string )
c . influx . checkmarxOne_data . fields . group = ( * results )[ "Group" ].( string )
c . influx . checkmarxOne_data . fields . group_full_path_on_report_date = ( * results )[ "GroupFullPathOnReportDate" ].( string )
c . influx . checkmarxOne_data . fields . scan_start = ( * results )[ "ScanStart" ].( string )
c . influx . checkmarxOne_data . fields . scan_time = ( * results )[ "ScanTime" ].( string )
c . influx . checkmarxOne_data . fields . lines_of_code_scanned = ( * results )[ "LinesOfCodeScanned" ].( int )
c . influx . checkmarxOne_data . fields . files_scanned = ( * results )[ "FilesScanned" ].( int )
2023-07-21 06:46:25 +02:00
c . influx . checkmarxOne_data . fields . tool_version = ( * results )[ "ToolVersion" ].( string )
2023-09-05 21:49:27 +02:00
2023-05-05 14:05:58 +02:00
c . influx . checkmarxOne_data . fields . scan_type = ( * results )[ "ScanType" ].( string )
c . influx . checkmarxOne_data . fields . preset = ( * results )[ "Preset" ].( string )
c . influx . checkmarxOne_data . fields . deep_link = ( * results )[ "DeepLink" ].( string )
c . influx . checkmarxOne_data . fields . report_creation_time = ( * results )[ "ReportCreationTime" ].( string )
}
// Utils Bundle
// various utilities to set up or work with the workspace and prepare data to send to Cx1
func ( c * checkmarxOneExecuteScanUtilsBundle ) PathMatch ( pattern , name string ) ( bool , error ) {
return doublestar . PathMatch ( pattern , name )
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) GetWorkspace () string {
return c . workspace
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) WriteFile ( filename string , data [] byte , perm os . FileMode ) error {
return os . WriteFile ( filename , data , perm )
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) MkdirAll ( path string , perm os . FileMode ) error {
return os . MkdirAll ( path , perm )
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) FileInfoHeader ( fi os . FileInfo ) ( * zip . FileHeader , error ) {
return zip . FileInfoHeader ( fi )
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) Stat ( name string ) ( os . FileInfo , error ) {
return os . Stat ( name )
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) Open ( name string ) ( * os . File , error ) {
return os . Open ( name )
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) CreateIssue ( ghCreateIssueOptions * piperGithub . CreateIssueOptions ) error {
_ , err := piperGithub . CreateIssue ( ghCreateIssueOptions )
return err
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) GetIssueService () * github . IssuesService {
return c . issues
}
func ( c * checkmarxOneExecuteScanUtilsBundle ) GetSearchService () * github . SearchService {
return c . search
}
func newcheckmarxOneExecuteScanUtilsBundle ( workspace string , client * github . Client ) checkmarxOneExecuteScanUtils {
utils := checkmarxOneExecuteScanUtilsBundle {
workspace : workspace ,
}
if client != nil {
utils . issues = client . Issues
utils . search = client . Search
}
return & utils
}