From 0fb7ee5488a10664aa4eef2f0697fbe15d4bd44d Mon Sep 17 00:00:00 2001 From: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Date: Mon, 5 Oct 2020 08:16:18 +0200 Subject: [PATCH] fix: Checkmarx project creation (#2112) * fix : allow creation of Checkmarx projects * checkmarx: fix project creation * do not swallow error * fix preset error handling --- cmd/checkmarxExecuteScan.go | 22 ++++++++++++------- pkg/checkmarx/checkmarx.go | 39 ++++++++------------------------- pkg/checkmarx/checkmarx_test.go | 20 ++++++++++++++++- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/cmd/checkmarxExecuteScan.go b/cmd/checkmarxExecuteScan.go index 2abb63f5e..0c3eb6df6 100644 --- a/cmd/checkmarxExecuteScan.go +++ b/cmd/checkmarxExecuteScan.go @@ -109,8 +109,11 @@ func loadExistingProject(sys checkmarx.System, initialProjectName, pullRequestNa } } else { projects, err := sys.GetProjectsByNameAndTeam(projectName, teamID) - if err != nil || len(projects) == 0 { - return project, projectName, errors.Wrap(err, "no projects found") + if err != nil { + return project, projectName, errors.Wrap(err, "failed getting projects") + } + if len(projects) == 0 { + return checkmarx.Project{}, projectName, nil } project = projects[0] log.Entry().Debugf("Loaded project with name %v", project.Name) @@ -407,24 +410,27 @@ func enforceThresholds(config checkmarxExecuteScanOptions, results map[string]in } func createAndConfigureNewProject(sys checkmarx.System, projectName, teamID, presetValue, engineConfiguration string) (checkmarx.Project, error) { + if len(presetValue) == 0 { + log.SetErrorCategory(log.ErrorConfiguration) + return checkmarx.Project{}, fmt.Errorf("preset not specified, creation of project %v failed", projectName) + } + projectCreateResult, err := sys.CreateProject(projectName, teamID) if err != nil { return checkmarx.Project{}, errors.Wrapf(err, "cannot create project %v", projectName) } - if len(presetValue) > 0 { - setPresetForProject(sys, projectCreateResult.ID, projectName, presetValue, engineConfiguration) - } else { - log.SetErrorCategory(log.ErrorConfiguration) - return checkmarx.Project{}, errors.Wrapf(err, "preset not specified, creation of project %v failed", projectName) + if err := setPresetForProject(sys, projectCreateResult.ID, projectName, presetValue, engineConfiguration); err != nil { + return checkmarx.Project{}, errors.Wrapf(err, "failed to set preset %v for project", presetValue) } + projects, err := sys.GetProjectsByNameAndTeam(projectName, teamID) if err != nil || len(projects) == 0 { return checkmarx.Project{}, errors.Wrapf(err, "failed to load newly created project %v", projectName) } log.Entry().Debugf("New Project %v created", projectName) + log.Entry().Debugf("Projects: %v", projects) return projects[0], nil - } // loadPreset finds a checkmarx.Preset that has either the ID or Name given by presetValue. diff --git a/pkg/checkmarx/checkmarx.go b/pkg/checkmarx/checkmarx.go index 6028b9fdd..c8305a25c 100644 --- a/pkg/checkmarx/checkmarx.go +++ b/pkg/checkmarx/checkmarx.go @@ -232,10 +232,10 @@ func NewSystemInstance(client piperHttp.Uploader, serverURL, username, password } func sendRequest(sys *SystemInstance, method, url string, body io.Reader, header http.Header) ([]byte, error) { - return sendRequestInternal(sys, method, url, body, header, "200:399") + return sendRequestInternal(sys, method, url, body, header, []int{}) } -func sendRequestInternal(sys *SystemInstance, method, url string, body io.Reader, header http.Header, validStatusCodeRange string) ([]byte, error) { +func sendRequestInternal(sys *SystemInstance, method, url string, body io.Reader, header http.Header, acceptedErrorCodes []int) ([]byte, error) { var requestBody io.Reader var requestBodyCopy io.Reader if body != nil { @@ -246,37 +246,16 @@ func sendRequestInternal(sys *SystemInstance, method, url string, body io.Reader defer closer.Close() } response, err := sys.client.SendRequest(method, fmt.Sprintf("%v/cxrestapi%v", sys.serverURL, url), requestBody, header, nil) - if err != nil { + if err != nil && !piperutils.ContainsInt(acceptedErrorCodes, response.StatusCode) { sys.recordRequestDetailsInErrorCase(requestBodyCopy, response) sys.logger.Errorf("HTTP request failed with error: %s", err) return nil, err } - var validResponseCodeList []int - values := strings.Split(validStatusCodeRange, ",") - for _, value := range values { - parts := strings.Split(value, ":") - if len(parts) > 1 { - lower, _ := strconv.Atoi(parts[0]) - upper, _ := strconv.Atoi(parts[1]) - for i := lower; i <= upper; i++ { - validResponseCodeList = append(validResponseCodeList, i) - } - } else { - validCode, _ := strconv.Atoi(value) - validResponseCodeList = append(validResponseCodeList, validCode) - } - } - - if piperutils.ContainsInt(validResponseCodeList, response.StatusCode) { - data, _ := ioutil.ReadAll(response.Body) - sys.logger.Debugf("Valid response body: %v", string(data)) - defer response.Body.Close() - return data, nil - } - sys.recordRequestDetailsInErrorCase(requestBodyCopy, response) - sys.logger.Errorf("HTTP request failed with error %s", response.Status) - return nil, errors.Errorf("Invalid HTTP status %v with with code %v received", response.Status, response.StatusCode) + data, _ := ioutil.ReadAll(response.Body) + sys.logger.Debugf("Valid response body: %v", string(data)) + defer response.Body.Close() + return data, nil } func (sys *SystemInstance) recordRequestDetailsInErrorCase(requestBody io.Reader, response *http.Response) { @@ -359,9 +338,9 @@ func (sys *SystemInstance) GetProjectsByNameAndTeam(projectName, teamID string) "projectName": {projectName}, "teamId": {teamID}, } - data, err = sendRequestInternal(sys, http.MethodGet, fmt.Sprintf("/projects?%v", body.Encode()), nil, header, "200:399,404") + data, err = sendRequestInternal(sys, http.MethodGet, fmt.Sprintf("/projects?%v", body.Encode()), nil, header, []int{404}) } else { - data, err = sendRequestInternal(sys, http.MethodGet, "/projects", nil, header, "200:399,404") + data, err = sendRequestInternal(sys, http.MethodGet, "/projects", nil, header, []int{404}) } if err != nil { return projects, errors.Wrapf(err, "fetching project %v failed", projectName) diff --git a/pkg/checkmarx/checkmarx_test.go b/pkg/checkmarx/checkmarx_test.go index 3596f4a95..a21d292fa 100644 --- a/pkg/checkmarx/checkmarx_test.go +++ b/pkg/checkmarx/checkmarx_test.go @@ -40,7 +40,11 @@ func (sm *senderMock) SendRequest(method, url string, body io.Reader, header htt buf.ReadFrom(body) sm.requestBody = buf.String() } - return &http.Response{StatusCode: sm.httpStatusCode, Body: ioutil.NopCloser(strings.NewReader(sm.responseBody))}, nil + var httpError error + if sm.httpStatusCode > 399 { + httpError = fmt.Errorf("http error %v", sm.httpStatusCode) + } + return &http.Response{StatusCode: sm.httpStatusCode, Body: ioutil.NopCloser(strings.NewReader(sm.responseBody))}, httpError } func (sm *senderMock) UploadFile(url, file, fieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error) { sm.httpMethod = http.MethodPost @@ -95,6 +99,20 @@ func TestSendRequest(t *testing.T) { }) } +func TestSendRequestInternal(t *testing.T) { + logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/checkmarx_test") + opts := piperHttp.ClientOptions{} + + t.Run("test accepted error", func(t *testing.T) { + myTestClient := senderMock{responseBody: `{"some": "test"}`, httpStatusCode: 404} + sys := SystemInstance{serverURL: "https://cx.server.com", client: &myTestClient, logger: logger} + myTestClient.SetOptions(opts) + _, err := sendRequestInternal(&sys, "GET", "/test", nil, nil, []int{404}) + + assert.NoError(t, err, "No error expected but error occurred") + }) +} + func TestGetOAuthToken(t *testing.T) { logger := log.Entry().WithField("package", "SAP/jenkins-library/pkg/checkmarx_test") opts := piperHttp.ClientOptions{}