github.com/jaylevin/jenkins-library@v1.230.4/pkg/checkmarx/checkmarx.go (about) 1 package checkmarx 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net/http" 10 "net/url" 11 "strconv" 12 "strings" 13 "time" 14 15 "encoding/xml" 16 17 piperHttp "github.com/SAP/jenkins-library/pkg/http" 18 "github.com/SAP/jenkins-library/pkg/log" 19 "github.com/SAP/jenkins-library/pkg/piperutils" 20 "github.com/pkg/errors" 21 "github.com/sirupsen/logrus" 22 ) 23 24 // ReportsDirectory defines the subfolder for the Checkmarx reports which are generated 25 const ReportsDirectory = "checkmarx" 26 27 // AuthToken - Structure to store OAuth2 token 28 type AuthToken struct { 29 TokenType string `json:"token_type"` 30 AccessToken string `json:"access_token"` 31 ExpiresIn int `json:"expires_in"` 32 } 33 34 // Preset - Project's Preset 35 type Preset struct { 36 ID int `json:"id"` 37 Name string `json:"name"` 38 OwnerName string `json:"ownerName"` 39 Link Link `json:"link"` 40 } 41 42 // Scan - Scan Structure 43 type Scan struct { 44 ID int `json:"id"` 45 Link Link `json:"link"` 46 } 47 48 // ProjectCreateResult - ProjectCreateResult Structure 49 type ProjectCreateResult struct { 50 ID int `json:"id"` 51 Link Link `json:"link"` 52 } 53 54 // Report - Report Structure 55 type Report struct { 56 ReportID int `json:"reportId"` 57 Links Links `json:"links"` 58 } 59 60 // ResultsStatistics - ResultsStatistics Structure 61 type ResultsStatistics struct { 62 High int `json:"highSeverity"` 63 Medium int `json:"mediumSeverity"` 64 Low int `json:"lowSeverity"` 65 Info int `json:"infoSeverity"` 66 } 67 68 // ScanStatus - ScanStatus Structure 69 type ScanStatus struct { 70 ID int `json:"id"` 71 Link Link `json:"link"` 72 Status Status `json:"status"` 73 ScanType string `json:"scanType"` 74 Comment string `json:"comment"` 75 IsIncremental bool `json:"isIncremental"` 76 } 77 78 // Status - Status Structure 79 type Status struct { 80 ID int `json:"id"` 81 Name string `json:"name"` 82 Details ScanStatusDetail `json:"details"` 83 } 84 85 // ScanStatusDetail - ScanStatusDetail Structure 86 type ScanStatusDetail struct { 87 Stage string `json:"stage"` 88 Step string `json:"step"` 89 } 90 91 // ReportStatusResponse - ReportStatusResponse Structure 92 type ReportStatusResponse struct { 93 Location string `json:"location"` 94 ContentType string `json:"contentType"` 95 Status ReportStatus `json:"status"` 96 } 97 98 // ReportStatus - ReportStatus Structure 99 type ReportStatus struct { 100 ID int `json:"id"` 101 Value string `json:"value"` 102 } 103 104 // Project - Project Structure 105 type Project struct { 106 ID int `json:"id"` 107 TeamID string `json:"teamId"` 108 Name string `json:"name"` 109 IsPublic bool `json:"isPublic"` 110 SourceSettingsLink SourceSettingsLink `json:"sourceSettingsLink"` 111 Link Link `json:"link"` 112 } 113 114 // ScanSettings - scan settings at project level 115 type ScanSettings struct { 116 Project ProjectLink `json:"project"` 117 Preset PresetLink `json:"preset"` 118 EngineConfiguration EngineConfigurationLink `json:"engineConfiguration" ` 119 } 120 121 // ProjectLink - project link found in ScanSettings response 122 type ProjectLink struct { 123 ProjectID int `json:"id"` 124 Link Link `json:"link"` 125 } 126 127 // PresetLink - preset link found in ScanSettings response 128 type PresetLink struct { 129 PresetID int `json:"id"` 130 Link Link `json:"link"` 131 } 132 133 // EngineConfigurationLink - engine configuration link found in ScanSettings response 134 type EngineConfigurationLink struct { 135 EngineConfigurationID int `json:"id"` 136 Link Link `json:"link"` 137 } 138 139 // Team - Team Structure 140 type Team struct { 141 ID json.RawMessage `json:"id"` 142 FullName string `json:"fullName"` 143 } 144 145 // Links - Links Structure 146 type Links struct { 147 Report Link `json:"report"` 148 Status Link `json:"status"` 149 } 150 151 // Link - Link Structure 152 type Link struct { 153 Rel string `json:"rel"` 154 URI string `json:"uri"` 155 } 156 157 // SourceSettingsLink - SourceSettingsLink Structure 158 type SourceSettingsLink struct { 159 Type string `json:"type"` 160 Rel string `json:"rel"` 161 URI string `json:"uri"` 162 } 163 164 type ShortDescription struct { 165 Text string `json:"shortDescription"` 166 } 167 168 //DetailedResult - DetailedResult Structure 169 type DetailedResult struct { 170 XMLName xml.Name `xml:"CxXMLResults"` 171 InitiatorName string `xml:"InitiatorName,attr"` 172 ScanID string `xml:"ScanId,attr"` 173 Owner string `xml:"Owner,attr"` 174 ProjectID string `xml:"ProjectId,attr"` 175 ProjectName string `xml:"ProjectName,attr"` 176 TeamFullPathOnReportDate string `xml:"TeamFullPathOnReportDate,attr"` 177 DeepLink string `xml:"DeepLink,attr"` 178 ScanStart string `xml:"ScanStart,attr"` 179 Preset string `xml:"Preset,attr"` 180 ScanTime string `xml:"ScanTime,attr"` 181 LinesOfCodeScanned int `xml:"LinesOfCodeScanned,attr"` 182 FilesScanned int `xml:"FilesScanned,attr"` 183 ReportCreationTime string `xml:"ReportCreationTime,attr"` 184 Team string `xml:"Team,attr"` 185 CheckmarxVersion string `xml:"CheckmarxVersion,attr"` 186 ScanType string `xml:"ScanType,attr"` 187 SourceOrigin string `xml:"SourceOrigin,attr"` 188 Visibility string `xml:"Visibility,attr"` 189 Queries []Query `xml:"Query"` 190 } 191 192 // Query - Query Structure 193 type Query struct { 194 XMLName xml.Name `xml:"Query"` 195 Results []Result `xml:"Result"` 196 } 197 198 // Result - Result Structure 199 type Result struct { 200 XMLName xml.Name `xml:"Result"` 201 State string `xml:"state,attr"` 202 Severity string `xml:"Severity,attr"` 203 FalsePositive string `xml:"FalsePositive,attr"` 204 } 205 206 // SystemInstance is the client communicating with the Checkmarx backend 207 type SystemInstance struct { 208 serverURL string 209 username string 210 password string 211 client piperHttp.Uploader 212 logger *logrus.Entry 213 } 214 215 // System is the interface abstraction of a specific SystemIns 216 type System interface { 217 FilterPresetByName(presets []Preset, presetName string) Preset 218 FilterPresetByID(presets []Preset, presetID int) Preset 219 FilterProjectByName(projects []Project, projectName string) Project 220 FilterTeamByName(teams []Team, teamName string) (Team, error) 221 FilterTeamByID(teams []Team, teamID json.RawMessage) Team 222 DownloadReport(reportID int) ([]byte, error) 223 GetReportStatus(reportID int) (ReportStatusResponse, error) 224 RequestNewReport(scanID int, reportType string) (Report, error) 225 GetResults(scanID int) ResultsStatistics 226 GetScanStatusAndDetail(scanID int) (string, ScanStatusDetail) 227 GetScans(projectID int) ([]ScanStatus, error) 228 ScanProject(projectID int, isIncremental, isPublic, forceScan bool) (Scan, error) 229 UpdateProjectConfiguration(projectID int, presetID int, engineConfigurationID string) error 230 UpdateProjectExcludeSettings(projectID int, excludeFolders string, excludeFiles string) error 231 UploadProjectSourceCode(projectID int, zipFile string) error 232 CreateProject(projectName, teamID string) (ProjectCreateResult, error) 233 CreateBranch(projectID int, branchName string) int 234 GetPresets() []Preset 235 GetProjectByID(projectID int) (Project, error) 236 GetProjectsByNameAndTeam(projectName, teamID string) ([]Project, error) 237 GetProjects() ([]Project, error) 238 GetShortDescription(scanID int, pathID int) (ShortDescription, error) 239 GetTeams() []Team 240 } 241 242 // NewSystemInstance returns a new Checkmarx client for communicating with the backend 243 func NewSystemInstance(client piperHttp.Uploader, serverURL, username, password string) (*SystemInstance, error) { 244 loggerInstance := log.Entry().WithField("package", "SAP/jenkins-library/pkg/checkmarx") 245 sys := &SystemInstance{ 246 serverURL: serverURL, 247 username: username, 248 password: password, 249 client: client, 250 logger: loggerInstance, 251 } 252 253 token, err := sys.getOAuth2Token() 254 if err != nil { 255 return sys, errors.Wrap(err, "Error fetching oAuth token") 256 } 257 258 log.RegisterSecret(token) 259 260 options := piperHttp.ClientOptions{ 261 Token: token, 262 TransportTimeout: time.Minute * 15, 263 } 264 sys.client.SetOptions(options) 265 266 return sys, nil 267 } 268 269 func sendRequest(sys *SystemInstance, method, url string, body io.Reader, header http.Header) ([]byte, error) { 270 return sendRequestInternal(sys, method, url, body, header, []int{}) 271 } 272 273 func sendRequestInternal(sys *SystemInstance, method, url string, body io.Reader, header http.Header, acceptedErrorCodes []int) ([]byte, error) { 274 var requestBody io.Reader 275 var requestBodyCopy io.Reader 276 if body != nil { 277 closer := ioutil.NopCloser(body) 278 bodyBytes, _ := ioutil.ReadAll(closer) 279 requestBody = bytes.NewBuffer(bodyBytes) 280 requestBodyCopy = bytes.NewBuffer(bodyBytes) 281 defer closer.Close() 282 } 283 response, err := sys.client.SendRequest(method, fmt.Sprintf("%v/cxrestapi%v", sys.serverURL, url), requestBody, header, nil) 284 if err != nil && (response == nil || !piperutils.ContainsInt(acceptedErrorCodes, response.StatusCode)) { 285 sys.recordRequestDetailsInErrorCase(requestBodyCopy, response) 286 sys.logger.Errorf("HTTP request failed with error: %s", err) 287 return nil, err 288 } 289 290 data, _ := ioutil.ReadAll(response.Body) 291 sys.logger.Debugf("Valid response body: %v", string(data)) 292 defer response.Body.Close() 293 return data, nil 294 } 295 296 func (sys *SystemInstance) recordRequestDetailsInErrorCase(requestBody io.Reader, response *http.Response) { 297 if requestBody != nil { 298 data, _ := ioutil.ReadAll(ioutil.NopCloser(requestBody)) 299 sys.logger.Errorf("Request body: %s", data) 300 } 301 if response != nil && response.Body != nil { 302 data, _ := ioutil.ReadAll(response.Body) 303 sys.logger.Errorf("Response body: %s", data) 304 response.Body.Close() 305 } 306 } 307 308 func (sys *SystemInstance) getOAuth2Token() (string, error) { 309 body := url.Values{ 310 "username": {sys.username}, 311 "password": {sys.password}, 312 "grant_type": {"password"}, 313 "scope": {"sast_rest_api"}, 314 "client_id": {"resource_owner_client"}, 315 "client_secret": {"014DF517-39D1-4453-B7B3-9930C563627C"}, 316 } 317 header := http.Header{} 318 header.Add("Content-type", "application/x-www-form-urlencoded") 319 data, err := sendRequest(sys, http.MethodPost, "/auth/identity/connect/token", strings.NewReader(body.Encode()), header) 320 if err != nil { 321 return "", err 322 } 323 324 var token AuthToken 325 json.Unmarshal(data, &token) 326 return token.TokenType + " " + token.AccessToken, nil 327 } 328 329 // GetTeams returns the teams the user is assigned to 330 func (sys *SystemInstance) GetTeams() []Team { 331 sys.logger.Debug("Getting Teams...") 332 var teams []Team 333 334 data, err := sendRequest(sys, http.MethodGet, "/auth/teams", nil, nil) 335 if err != nil { 336 sys.logger.Errorf("Fetching teams failed: %s", err) 337 return teams 338 } 339 340 json.Unmarshal(data, &teams) 341 return teams 342 } 343 344 // GetProjects returns the projects defined in the Checkmarx backend which the user has access to 345 func (sys *SystemInstance) GetProjects() ([]Project, error) { 346 return sys.GetProjectsByNameAndTeam("", "") 347 } 348 349 // GetProjectByID returns the project addressed by projectID from the Checkmarx backend which the user has access to 350 func (sys *SystemInstance) GetProjectByID(projectID int) (Project, error) { 351 sys.logger.Debugf("Getting Project with ID %v...", projectID) 352 var project Project 353 354 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/projects/%v", projectID), nil, nil) 355 if err != nil { 356 return project, errors.Wrapf(err, "fetching project %v failed", projectID) 357 } 358 359 json.Unmarshal(data, &project) 360 return project, nil 361 } 362 363 // GetProjectsByNameAndTeam returns the project addressed by projectID from the Checkmarx backend which the user has access to 364 func (sys *SystemInstance) GetProjectsByNameAndTeam(projectName, teamID string) ([]Project, error) { 365 sys.logger.Debugf("Getting projects with name %v of team %v...", projectName, teamID) 366 var projects []Project 367 header := http.Header{} 368 header.Set("Accept-Type", "application/json") 369 var data []byte 370 var err error 371 if len(teamID) > 0 && len(projectName) > 0 { 372 body := url.Values{ 373 "projectName": {projectName}, 374 "teamId": {teamID}, 375 } 376 data, err = sendRequestInternal(sys, http.MethodGet, fmt.Sprintf("/projects?%v", body.Encode()), nil, header, []int{404}) 377 } else { 378 data, err = sendRequestInternal(sys, http.MethodGet, "/projects", nil, header, []int{404}) 379 } 380 if err != nil { 381 return projects, errors.Wrapf(err, "fetching project %v failed", projectName) 382 } 383 384 json.Unmarshal(data, &projects) 385 return projects, nil 386 } 387 388 // CreateProject creates a new project in the Checkmarx backend 389 func (sys *SystemInstance) CreateProject(projectName, teamID string) (ProjectCreateResult, error) { 390 var result ProjectCreateResult 391 jsonData := map[string]interface{}{ 392 "name": projectName, 393 "owningTeam": teamID, 394 "isPublic": true, 395 } 396 397 jsonValue, err := json.Marshal(jsonData) 398 if err != nil { 399 return result, errors.Wrapf(err, "failed to marshal project data") 400 } 401 402 header := http.Header{} 403 header.Set("Content-Type", "application/json") 404 405 data, err := sendRequest(sys, http.MethodPost, "/projects", bytes.NewBuffer(jsonValue), header) 406 if err != nil { 407 return result, errors.Wrapf(err, "failed to create project %v", projectName) 408 } 409 410 json.Unmarshal(data, &result) 411 return result, nil 412 } 413 414 // CreateBranch creates a branch of an existing project in the Checkmarx backend 415 func (sys *SystemInstance) CreateBranch(projectID int, branchName string) int { 416 jsonData := map[string]interface{}{ 417 "name": branchName, 418 } 419 420 jsonValue, err := json.Marshal(jsonData) 421 if err != nil { 422 sys.logger.Errorf("Error Marshal: %s", err) 423 return 0 424 } 425 426 header := http.Header{} 427 header.Set("Content-Type", "application/json") 428 data, err := sendRequest(sys, http.MethodPost, fmt.Sprintf("/projects/%v/branch", projectID), bytes.NewBuffer(jsonValue), header) 429 if err != nil { 430 sys.logger.Errorf("Failed to create project: %s", err) 431 return 0 432 } 433 434 var scan Scan 435 436 json.Unmarshal(data, &scan) 437 return scan.ID 438 } 439 440 // UploadProjectSourceCode zips and uploads the project sources for scanning 441 func (sys *SystemInstance) UploadProjectSourceCode(projectID int, zipFile string) error { 442 sys.logger.Debug("Starting to upload files...") 443 444 header := http.Header{} 445 header.Add("Accept-Encoding", "gzip,deflate") 446 header.Add("Accept", "text/plain") 447 resp, err := sys.client.UploadFile(fmt.Sprintf("%v/cxrestapi/projects/%v/sourceCode/attachments", sys.serverURL, projectID), zipFile, "zippedSource", header, nil, "form") 448 if err != nil { 449 return errors.Wrap(err, "failed to uploaded zipped sources") 450 } 451 452 data, err := ioutil.ReadAll(resp.Body) 453 defer resp.Body.Close() 454 if err != nil { 455 return errors.Wrap(err, "error reading the response data") 456 } 457 458 responseData := make(map[string]string) 459 json.Unmarshal(data, &responseData) 460 461 if resp.StatusCode == http.StatusNoContent { 462 return nil 463 } 464 465 sys.logger.Debugf("Body %s", data) 466 return errors.Wrapf(err, "error writing the request's body, status: %s", resp.Status) 467 } 468 469 // UpdateProjectExcludeSettings updates the exclude configuration of the project 470 func (sys *SystemInstance) UpdateProjectExcludeSettings(projectID int, excludeFolders string, excludeFiles string) error { 471 jsonData := map[string]string{ 472 "excludeFoldersPattern": excludeFolders, 473 "excludeFilesPattern": excludeFiles, 474 } 475 476 jsonValue, err := json.Marshal(jsonData) 477 if err != nil { 478 return errors.Wrap(err, "error marhalling project exclude settings") 479 } 480 481 header := http.Header{} 482 header.Set("Content-Type", "application/json") 483 _, err = sendRequest(sys, http.MethodPut, fmt.Sprintf("/projects/%v/sourceCode/excludeSettings", projectID), bytes.NewBuffer(jsonValue), header) 484 if err != nil { 485 return errors.Wrap(err, "request to checkmarx system failed") 486 } 487 488 return nil 489 } 490 491 // GetPresets loads the preset values defined in the Checkmarx backend 492 func (sys *SystemInstance) GetPresets() []Preset { 493 sys.logger.Debug("Getting Presets...") 494 var presets []Preset 495 496 data, err := sendRequest(sys, http.MethodGet, "/sast/presets", nil, nil) 497 if err != nil { 498 sys.logger.Errorf("Fetching presets failed: %s", err) 499 return presets 500 } 501 502 json.Unmarshal(data, &presets) 503 return presets 504 } 505 506 // UpdateProjectConfiguration updates the configuration of the project addressed by projectID 507 func (sys *SystemInstance) UpdateProjectConfiguration(projectID int, presetID int, engineConfigurationID string) error { 508 engineConfigID, _ := strconv.Atoi(engineConfigurationID) 509 510 var projectScanSettings ScanSettings 511 header := http.Header{} 512 header.Set("Content-Type", "application/json") 513 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/sast/scanSettings/%v", projectID), nil, header) 514 if err != nil { 515 // if an error happens, try to update the config anyway 516 sys.logger.Warnf("Failed to fetch scan settings of project %v: %s", projectID, err) 517 } else { 518 // Check if the current project config needs to be updated 519 json.Unmarshal(data, &projectScanSettings) 520 if projectScanSettings.Preset.PresetID == presetID && projectScanSettings.EngineConfiguration.EngineConfigurationID == engineConfigID { 521 sys.logger.Debugf("Project configuration does not need to be updated") 522 return nil 523 } 524 } 525 526 jsonData := map[string]interface{}{ 527 "projectId": projectID, 528 "presetId": presetID, 529 "engineConfigurationId": engineConfigID, 530 } 531 532 jsonValue, err := json.Marshal(jsonData) 533 if err != nil { 534 return errors.Wrapf(err, "error marshalling project data") 535 } 536 537 _, err = sendRequest(sys, http.MethodPost, "/sast/scanSettings", bytes.NewBuffer(jsonValue), header) 538 if err != nil { 539 return errors.Wrapf(err, "request to checkmarx system failed") 540 } 541 sys.logger.Debugf("Project configuration updated") 542 543 return nil 544 } 545 546 // ScanProject triggers a scan on the project addressed by projectID 547 func (sys *SystemInstance) ScanProject(projectID int, isIncremental, isPublic, forceScan bool) (Scan, error) { 548 scan := Scan{} 549 jsonData := map[string]interface{}{ 550 "projectId": projectID, 551 "isIncremental": isIncremental, 552 "isPublic": isPublic, 553 "forceScan": forceScan, 554 "comment": "Scan From Golang Script", 555 } 556 557 jsonValue, _ := json.Marshal(jsonData) 558 559 header := http.Header{} 560 header.Set("cxOrigin", "GolangScript") 561 header.Set("Content-Type", "application/json") 562 data, err := sendRequest(sys, http.MethodPost, "/sast/scans", bytes.NewBuffer(jsonValue), header) 563 if err != nil { 564 sys.logger.Errorf("Failed to trigger scan of project %v: %s", projectID, err) 565 return scan, errors.Wrapf(err, "Failed to trigger scan of project %v", projectID) 566 } 567 568 json.Unmarshal(data, &scan) 569 return scan, nil 570 } 571 572 // GetScans returns all scan status on the project addressed by projectID 573 func (sys *SystemInstance) GetScans(projectID int) ([]ScanStatus, error) { 574 scans := []ScanStatus{} 575 body := url.Values{ 576 "projectId": {fmt.Sprintf("%v", projectID)}, 577 "last": {fmt.Sprintf("%v", 20)}, 578 } 579 580 header := http.Header{} 581 header.Set("cxOrigin", "GolangScript") 582 header.Set("Accept-Type", "application/json") 583 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/sast/scans?%v", body.Encode()), nil, header) 584 if err != nil { 585 sys.logger.Errorf("Failed to fetch scans of project %v: %s", projectID, err) 586 return scans, errors.Wrapf(err, "failed to fetch scans of project %v", projectID) 587 } 588 589 json.Unmarshal(data, &scans) 590 return scans, nil 591 } 592 593 // GetScanStatusAndDetail returns the status of the scan addressed by scanID 594 func (sys *SystemInstance) GetScanStatusAndDetail(scanID int) (string, ScanStatusDetail) { 595 var scanStatus ScanStatus 596 597 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/sast/scans/%v", scanID), nil, nil) 598 if err != nil { 599 sys.logger.Errorf("Failed to get scan status for scanID %v: %s", scanID, err) 600 return "Failed", ScanStatusDetail{} 601 } 602 603 json.Unmarshal(data, &scanStatus) 604 return scanStatus.Status.Name, scanStatus.Status.Details 605 } 606 607 // GetResults returns the results of the scan addressed by scanID 608 func (sys *SystemInstance) GetResults(scanID int) ResultsStatistics { 609 var results ResultsStatistics 610 611 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/sast/scans/%v/resultsStatistics", scanID), nil, nil) 612 if err != nil { 613 sys.logger.Errorf("Failed to fetch scan results for scanID %v: %s", scanID, err) 614 return results 615 } 616 617 json.Unmarshal(data, &results) 618 return results 619 } 620 621 // RequestNewReport triggers the generation of a report for a specific scan addressed by scanID 622 func (sys *SystemInstance) RequestNewReport(scanID int, reportType string) (Report, error) { 623 report := Report{} 624 jsonData := map[string]interface{}{ 625 "scanId": scanID, 626 "reportType": reportType, 627 "comment": "Scan report triggered by Piper", 628 } 629 630 jsonValue, _ := json.Marshal(jsonData) 631 632 header := http.Header{} 633 header.Set("cxOrigin", "GolangScript") 634 header.Set("Content-Type", "application/json") 635 data, err := sendRequest(sys, http.MethodPost, "/reports/sastScan", bytes.NewBuffer(jsonValue), header) 636 if err != nil { 637 return report, errors.Wrapf(err, "Failed to trigger report generation for scan %v", scanID) 638 } 639 640 json.Unmarshal(data, &report) 641 return report, nil 642 } 643 644 // GetReportStatus returns the status of the report generation process 645 func (sys *SystemInstance) GetReportStatus(reportID int) (ReportStatusResponse, error) { 646 var response ReportStatusResponse 647 648 header := http.Header{} 649 header.Set("Accept", "application/json") 650 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/reports/sastScan/%v/status", reportID), nil, header) 651 if err != nil { 652 sys.logger.Errorf("Failed to fetch report status for reportID %v: %s", reportID, err) 653 return response, errors.Wrapf(err, "failed to fetch report status for reportID %v", reportID) 654 } 655 656 json.Unmarshal(data, &response) 657 return response, nil 658 } 659 660 // GetShortDescription returns the short description for an issue with a scanID and pathID 661 func (sys *SystemInstance) GetShortDescription(scanID int, pathID int) (ShortDescription, error) { 662 var shortDescription ShortDescription 663 664 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/sast/scans/%v/results/%v/shortDescription", scanID, pathID), nil, nil) 665 if err != nil { 666 sys.logger.Errorf("Failed to get short description for scanID %v and pathID %v: %s", scanID, pathID, err) 667 return shortDescription, err 668 } 669 670 json.Unmarshal(data, &shortDescription) 671 return shortDescription, nil 672 } 673 674 // DownloadReport downloads the report addressed by reportID and returns the XML contents 675 func (sys *SystemInstance) DownloadReport(reportID int) ([]byte, error) { 676 header := http.Header{} 677 header.Set("Accept", "application/json") 678 data, err := sendRequest(sys, http.MethodGet, fmt.Sprintf("/reports/sastScan/%v", reportID), nil, header) 679 if err != nil { 680 return []byte{}, errors.Wrapf(err, "failed to download report with reportID %v", reportID) 681 } 682 return data, nil 683 } 684 685 // FilterTeamByName filters a team by its name 686 func (sys *SystemInstance) FilterTeamByName(teams []Team, teamName string) (Team, error) { 687 for _, team := range teams { 688 if team.FullName == teamName || team.FullName == strings.ReplaceAll(teamName, `\`, `/`) { 689 return team, nil 690 } 691 } 692 return Team{}, errors.New("Failed to find team with name " + teamName) 693 } 694 695 // FilterTeamByID filters a team by its ID 696 func (sys *SystemInstance) FilterTeamByID(teams []Team, teamID json.RawMessage) Team { 697 teamIDBytes1, _ := teamID.MarshalJSON() 698 for _, team := range teams { 699 teamIDBytes2, _ := team.ID.MarshalJSON() 700 if bytes.Compare(teamIDBytes1, teamIDBytes2) == 0 { 701 return team 702 } 703 } 704 return Team{} 705 } 706 707 // FilterProjectByName filters a project by its name 708 func (sys *SystemInstance) FilterProjectByName(projects []Project, projectName string) Project { 709 for _, project := range projects { 710 if project.Name == projectName { 711 sys.logger.Debugf("Filtered project with name %v", project.Name) 712 return project 713 } 714 } 715 return Project{} 716 } 717 718 // FilterPresetByName filters a preset by its name 719 func (sys *SystemInstance) FilterPresetByName(presets []Preset, presetName string) Preset { 720 for _, preset := range presets { 721 if preset.Name == presetName { 722 return preset 723 } 724 } 725 return Preset{} 726 } 727 728 // FilterPresetByID filters a preset by its name 729 func (sys *SystemInstance) FilterPresetByID(presets []Preset, presetID int) Preset { 730 for _, preset := range presets { 731 if preset.ID == presetID { 732 return preset 733 } 734 } 735 return Preset{} 736 }