diff --git a/internal/app/export/export.go b/internal/app/export/export.go index e4b6eb9..2c90cac 100644 --- a/internal/app/export/export.go +++ b/internal/app/export/export.go @@ -4,6 +4,7 @@ import ( "archive/zip" "compress/flate" "encoding/base64" + "encoding/json" "fmt" "io" "os" @@ -205,3 +206,9 @@ func getEncryptedKey(key []byte) (encKey []byte, err error) { encKey, err = encryption.EncryptAsymmetric(publicKey, key) return } + +func NewJSONDataSource(obj interface{}) func() ([]byte, error) { + return func() ([]byte, error) { + return json.Marshal(obj) + } +} diff --git a/internal/app/export/transform.go b/internal/app/export/transform.go new file mode 100644 index 0000000..02c21c7 --- /dev/null +++ b/internal/app/export/transform.go @@ -0,0 +1,80 @@ +package export + +import ( + "fmt" + "regexp" + "strings" + + "github.com/checkmarxDev/ast-sast-export/internal/integration/rest" +) + +// TransformTeams flattens teams. +func TransformTeams(teams []*rest.Team) []*rest.Team { + out := make([]*rest.Team, 0) + for _, e := range teams { + e.ParendID = 0 + e.Name = strings.ReplaceAll(strings.TrimLeft(e.FullName, "/"), "/", "_") + e.FullName = "/" + e.Name + out = append(out, e) + } + return out +} + +// TransformUsers reassigns users in the context of flatten teams. +// Note "teams" list passed must be the original, non-flattened, list +func TransformUsers(users []*rest.User, teams []*rest.Team) []*rest.User { + out := make([]*rest.User, 0) + for _, e := range users { + for _, teamID := range e.TeamIDs { + e.TeamIDs = append(e.TeamIDs, getAllChildTeamIDs(teamID, teams)...) + } + out = append(out, e) + } + return out +} + +// TransformSamlTeamMappings updates team mapping in the context of flatten teams. +func TransformSamlTeamMappings(samlTeamMappings []*rest.SamlTeamMapping) []*rest.SamlTeamMapping { + out := make([]*rest.SamlTeamMapping, 0) + for _, e := range samlTeamMappings { + e.TeamFullPath = "/" + strings.ReplaceAll(strings.TrimLeft(e.TeamFullPath, "/"), "/", "_") + out = append(out, e) + } + return out +} + +// TransformScanReport updates scan report in context of flatten teams. +func TransformScanReport(xml []byte) ([]byte, error) { + var teamPath string + out := replaceKeyValue(xml, "TeamFullPathOnReportDate", func(s string) string { + teamPath = strings.ReplaceAll(s, "\\", "_") + return teamPath + }) + out = replaceKeyValue(out, "Team", func(s string) string { + return teamPath + }) + return out, nil +} + +// getAllChildTeamIDs returns all child team ids relative to a root team id. +func getAllChildTeamIDs(root int, teams []*rest.Team) []int { + out := make([]int, 0) + for _, e := range teams { + if e.ParendID == root { + out = append(out, e.ID) + out = append(out, getAllChildTeamIDs(e.ID, teams)...) + } + } + return out +} + +// replaceKeyValue +func replaceKeyValue(d []byte, key string, getValue func(string) string) []byte { + re := regexp.MustCompile(fmt.Sprintf(`(%s)="([^"]+)"`, key)) + submatchCount := 2 + return re.ReplaceAllFunc(d, func(entry []byte) []byte { + matches := re.FindAllSubmatch(entry, submatchCount) + value := getValue(string(matches[0][2])) + return []byte(fmt.Sprintf(`%s=%q`, key, value)) + }) +} diff --git a/internal/app/export/transform_test.go b/internal/app/export/transform_test.go new file mode 100644 index 0000000..2d573a0 --- /dev/null +++ b/internal/app/export/transform_test.go @@ -0,0 +1,318 @@ +package export + +import ( + "fmt" + "testing" + + "github.com/checkmarxDev/ast-sast-export/internal/integration/rest" + "github.com/stretchr/testify/assert" +) + +type transformTeamsTest struct { + Name string + Input []*rest.Team + Expected []*rest.Team +} + +type transformUsersTest struct { + Name string + Input []*rest.User + Teams []*rest.Team + Expected []*rest.User +} + +func TestTransformTeams(t *testing.T) { + tests := []transformTeamsTest{ + {"empty input", []*rest.Team{}, []*rest.Team{}}, + { + "one root team", + []*rest.Team{{ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}}, + []*rest.Team{{ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}}, + }, + { + "one sub-level", + []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamB", FullName: "/TeamA/TeamB", ParendID: 1}, + {ID: 3, Name: "TeamC", FullName: "/TeamA/TeamC", ParendID: 1}, + }, + []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamA_TeamB", FullName: "/TeamA_TeamB", ParendID: 0}, + {ID: 3, Name: "TeamA_TeamC", FullName: "/TeamA_TeamC", ParendID: 0}, + }, + }, + { + "two sub-levels", + []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamB", FullName: "/TeamA/TeamB", ParendID: 1}, + {ID: 3, Name: "TeamC", FullName: "/TeamA/TeamB/TeamC", ParendID: 2}, + }, + []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamA_TeamB", FullName: "/TeamA_TeamB", ParendID: 0}, + {ID: 3, Name: "TeamA_TeamB_TeamC", FullName: "/TeamA_TeamB_TeamC", ParendID: 0}, + }, + }, + { + "two trees with 3 sub-levels", + []*rest.Team{ //nolint:dupl + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamB", FullName: "/TeamA/TeamB", ParendID: 1}, + {ID: 3, Name: "TeamC", FullName: "/TeamA/TeamB/TeamC", ParendID: 2}, + {ID: 4, Name: "TeamD", FullName: "/TeamA/TeamB/TeamC/TeamD", ParendID: 3}, + {ID: 5, Name: "TeamE", FullName: "/TeamE", ParendID: 0}, + {ID: 6, Name: "TeamF", FullName: "/TeamE/TeamF", ParendID: 5}, + {ID: 7, Name: "TeamG", FullName: "/TeamE/TeamF/TeamG", ParendID: 5}, + {ID: 8, Name: "TeamH", FullName: "/TeamE/TeamF/TeamG/TeamH", ParendID: 5}, + }, + []*rest.Team{ //nolint:dupl + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamA_TeamB", FullName: "/TeamA_TeamB", ParendID: 0}, + {ID: 3, Name: "TeamA_TeamB_TeamC", FullName: "/TeamA_TeamB_TeamC", ParendID: 0}, + {ID: 4, Name: "TeamA_TeamB_TeamC_TeamD", FullName: "/TeamA_TeamB_TeamC_TeamD", ParendID: 0}, + {ID: 5, Name: "TeamE", FullName: "/TeamE", ParendID: 0}, + {ID: 6, Name: "TeamE_TeamF", FullName: "/TeamE_TeamF", ParendID: 0}, + {ID: 7, Name: "TeamE_TeamF_TeamG", FullName: "/TeamE_TeamF_TeamG", ParendID: 0}, + {ID: 8, Name: "TeamE_TeamF_TeamG_TeamH", FullName: "/TeamE_TeamF_TeamG_TeamH", ParendID: 0}, + }, + }, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + result := TransformTeams(test.Input) + assert.ElementsMatch(t, test.Expected, result) + }) + } +} + +func TestTransformUsers(t *testing.T) { + tests := []transformUsersTest{ + {"empty input", []*rest.User{}, []*rest.Team{}, []*rest.User{}}, + { + "one user in root team", + []*rest.User{{ID: 1, UserName: "Alice", TeamIDs: []int{1}}}, + []*rest.Team{{ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}}, + []*rest.User{{ID: 1, UserName: "Alice", TeamIDs: []int{1}}}, + }, + { + "two users in two team levels", + []*rest.User{ + {ID: 1, UserName: "Alice", TeamIDs: []int{1}}, + {ID: 2, UserName: "Bob", TeamIDs: []int{2}}, + }, + []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamB", FullName: "/TeamA/TeamB", ParendID: 1}, + }, + []*rest.User{ + {ID: 1, UserName: "Alice", TeamIDs: []int{1, 2}}, + {ID: 2, UserName: "Bob", TeamIDs: []int{2}}, + }, + }, + { + "three users in three team levels", + []*rest.User{ + {ID: 1, UserName: "Alice", TeamIDs: []int{1}}, + {ID: 2, UserName: "Bob", TeamIDs: []int{2}}, + {ID: 3, UserName: "Charlie", TeamIDs: []int{3}}, + }, + []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamB", FullName: "/TeamA/TeamB", ParendID: 1}, + {ID: 3, Name: "TeamC", FullName: "/TeamA/TeamB/TeamC", ParendID: 2}, + }, + []*rest.User{ + {ID: 1, UserName: "Alice", TeamIDs: []int{1, 2, 3}}, + {ID: 2, UserName: "Bob", TeamIDs: []int{2, 3}}, + {ID: 3, UserName: "Charlie", TeamIDs: []int{3}}, + }, + }, + { + "siz users in two team trees with multiple levels", + []*rest.User{ + {ID: 1, UserName: "Alice", TeamIDs: []int{1}}, + {ID: 2, UserName: "Bob", TeamIDs: []int{2}}, + {ID: 3, UserName: "Charlie", TeamIDs: []int{3}}, + {ID: 4, UserName: "Diane", TeamIDs: []int{4}}, + {ID: 5, UserName: "Emily", TeamIDs: []int{5}}, + {ID: 6, UserName: "Fred", TeamIDs: []int{6}}, + }, + []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamB", FullName: "/TeamA/TeamB", ParendID: 1}, + {ID: 3, Name: "TeamC", FullName: "/TeamA/TeamB/TeamC", ParendID: 2}, + {ID: 4, Name: "TeamD", FullName: "/TeamD", ParendID: 0}, + {ID: 5, Name: "TeamE", FullName: "/TeamD/TeamE", ParendID: 4}, + {ID: 6, Name: "TeamF", FullName: "/TeamD/TeamF", ParendID: 4}, + }, + []*rest.User{ + {ID: 1, UserName: "Alice", TeamIDs: []int{1, 2, 3}}, + {ID: 2, UserName: "Bob", TeamIDs: []int{2, 3}}, + {ID: 3, UserName: "Charlie", TeamIDs: []int{3}}, + {ID: 4, UserName: "Diane", TeamIDs: []int{4, 5, 6}}, + {ID: 5, UserName: "Emily", TeamIDs: []int{5}}, + {ID: 6, UserName: "Fred", TeamIDs: []int{6}}, + }, + }, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + result := TransformUsers(test.Input, test.Teams) + assert.ElementsMatch(t, test.Expected, result) + }) + } +} + +func TestTransformSamlTeamMappings(t *testing.T) { + t.Run("no mappings", func(t *testing.T) { + var samlTeamMappings []*rest.SamlTeamMapping + + result := TransformSamlTeamMappings(samlTeamMappings) + + var expected []*rest.SamlTeamMapping + assert.ElementsMatch(t, expected, result) + }) + + t.Run("top level team", func(t *testing.T) { + samlTeamMappings := []*rest.SamlTeamMapping{ + {ID: 1, SamlIdentityProviderID: 1, TeamID: 1, TeamFullPath: "/TeamA", SamlAttributeValue: "team"}, + } + + result := TransformSamlTeamMappings(samlTeamMappings) + + expected := []*rest.SamlTeamMapping{ + {ID: 1, SamlIdentityProviderID: 1, TeamID: 1, TeamFullPath: "/TeamA", SamlAttributeValue: "team"}, + } + assert.ElementsMatch(t, expected, result) + }) + + t.Run("team in sub-level", func(t *testing.T) { + samlTeamMappings := []*rest.SamlTeamMapping{ + {ID: 1, SamlIdentityProviderID: 1, TeamID: 2, TeamFullPath: "/TeamA/TeamB", SamlAttributeValue: "team"}, + } + + result := TransformSamlTeamMappings(samlTeamMappings) + + expected := []*rest.SamlTeamMapping{ + {ID: 1, SamlIdentityProviderID: 1, TeamID: 2, TeamFullPath: "/TeamA_TeamB", SamlAttributeValue: "team"}, + } + assert.ElementsMatch(t, expected, result) + }) + + t.Run("team in 2nd sub-level", func(t *testing.T) { + samlTeamMappings := []*rest.SamlTeamMapping{ + {ID: 1, SamlIdentityProviderID: 1, TeamID: 3, TeamFullPath: "/TeamA/TeamB/TeamC", SamlAttributeValue: "team"}, + } + + result := TransformSamlTeamMappings(samlTeamMappings) + + expected := []*rest.SamlTeamMapping{ + {ID: 1, SamlIdentityProviderID: 1, TeamID: 3, TeamFullPath: "/TeamA_TeamB_TeamC", SamlAttributeValue: "team"}, + } + assert.ElementsMatch(t, expected, result) + }) +} + +func TestTransformScanReport(t *testing.T) { + t.Run("root team", func(t *testing.T) { + report := newMockScanReportXML("TeamA", "TeamA") + + result, err := TransformScanReport([]byte(report)) + + assert.NoError(t, err) + assert.Equal(t, report, string(result)) + }) + + t.Run("one level deep team", func(t *testing.T) { + report := newMockScanReportXML("TeamB", "TeamA\\TeamB") + + result, err := TransformScanReport([]byte(report)) + + assert.NoError(t, err) + expected := newMockScanReportXML("TeamA_TeamB", "TeamA_TeamB") + assert.Equal(t, expected, string(result)) + }) + + t.Run("two levels deep team", func(t *testing.T) { + report := newMockScanReportXML("TeamC", "TeamA\\TeamB\\TeamC") + + result, err := TransformScanReport([]byte(report)) + + assert.NoError(t, err) + expected := newMockScanReportXML("TeamA_TeamB_TeamC", "TeamA_TeamB_TeamC") + assert.Equal(t, expected, string(result)) + }) +} + +func TestGetAllChildTeamIDs(t *testing.T) { + teams := []*rest.Team{ + {ID: 1, Name: "TeamA", FullName: "/TeamA", ParendID: 0}, + {ID: 2, Name: "TeamB", FullName: "/TeamA/TeamB", ParendID: 1}, + {ID: 3, Name: "TeamC", FullName: "/TeamC", ParendID: 0}, + {ID: 4, Name: "TeamD", FullName: "/TeamC/TeamD", ParendID: 3}, + {ID: 5, Name: "TeamE", FullName: "/TeamC/TeamD/TeamE", ParendID: 4}, + {ID: 6, Name: "TeamF", FullName: "/TeamC/TeamF", ParendID: 3}, + } + + t.Run("starting from TeamA", func(t *testing.T) { + result := getAllChildTeamIDs(1, teams) + + expected := []int{2} + assert.ElementsMatch(t, expected, result) + }) + + t.Run("starting from TeamC", func(t *testing.T) { + result := getAllChildTeamIDs(3, teams) + + expected := []int{4, 5, 6} + assert.ElementsMatch(t, expected, result) + }) + + t.Run("starting from TeamD", func(t *testing.T) { + result := getAllChildTeamIDs(4, teams) + + expected := []int{5} + assert.ElementsMatch(t, expected, result) + }) + + t.Run("starting from TeamF", func(t *testing.T) { + result := getAllChildTeamIDs(6, teams) + + var expected []int + assert.ElementsMatch(t, expected, result) + }) +} + +func TestReplaceKeyValue(t *testing.T) { + s := `a="1" b="2" c="3"` + + t.Run("a", func(t *testing.T) { + result := replaceKeyValue([]byte(s), "a", func(a string) string { + return fmt.Sprintf(".%s.", a) + }) + + expected := `a=".1." b="2" c="3"` + assert.Equal(t, expected, string(result)) + }) + + t.Run("b", func(t *testing.T) { + result := replaceKeyValue([]byte(s), "b", func(b string) string { + return fmt.Sprintf("-%s-", b) + }) + + expected := `a="1" b="-2-" c="3"` + assert.Equal(t, expected, string(result)) + }) +} + +func newMockScanReportXML(teamName, teamFullPath string) string { + // nolint:lll + return fmt.Sprintf(` + + + + +`, teamFullPath, teamName) +} diff --git a/internal/integration/rest/apiclient.go b/internal/integration/rest/apiclient.go index ba9bd70..150544f 100644 --- a/internal/integration/rest/apiclient.go +++ b/internal/integration/rest/apiclient.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "time" @@ -34,17 +33,16 @@ const ( type Client interface { Authenticate(username, password string) error - GetResponseBody(endpoint string) ([]byte, error) PostResponseBody(endpoint string, body io.Reader) ([]byte, error) - GetUsers() ([]byte, error) + GetUsers() ([]*User, error) GetRoles() ([]byte, error) - GetTeams() ([]byte, error) + GetTeams() ([]*Team, error) GetLdapServers() ([]byte, error) GetLdapRoleMappings() ([]byte, error) GetLdapTeamMappings() ([]byte, error) GetSamlIdentityProviders() ([]byte, error) GetSamlRoleMappings() ([]byte, error) - GetSamlTeamMappings() ([]byte, error) + GetSamlTeamMappings() ([]*SamlTeamMapping, error) GetProjectsWithLastScanID(fromDate string, offset, limit int) (*[]ProjectWithLastScanID, error) GetTriagedResultsByScanID(scanID int) (*[]TriagedScanResult, error) CreateScanReport(scanID int, reportType string, retry Retry) ([]byte, error) @@ -101,7 +99,7 @@ func (c *APIClient) Authenticate(username, password string) error { Logger() if resp.StatusCode == http.StatusOK { - responseBody, ioErr := ioutil.ReadAll(resp.Body) + responseBody, ioErr := io.ReadAll(resp.Body) if ioErr != nil { logger.Debug().Err(ioErr).Msg("authenticate ok failed read response") return fmt.Errorf("authentication error - could not read response") @@ -117,7 +115,7 @@ func (c *APIClient) Authenticate(username, password string) error { } return nil } else if resp.StatusCode == http.StatusBadRequest { - responseBody, ioErr := ioutil.ReadAll(resp.Body) + responseBody, ioErr := io.ReadAll(resp.Body) if ioErr != nil { logger.Debug().Err(ioErr).Msg("authenticate bad request failed to read response") return fmt.Errorf("authentication error - could not read response") @@ -140,7 +138,8 @@ func (c *APIClient) Authenticate(username, password string) error { return fmt.Errorf("authentication error - please try again later or contact support") } -func (c *APIClient) GetResponseBody(endpoint string) ([]byte, error) { +// getResponseBody returns response body as byte array +func (c *APIClient) getResponseBody(endpoint string) ([]byte, error) { req, err := CreateRequest(http.MethodGet, c.BaseURL+endpoint, nil, c.Token) if err != nil { return []byte{}, err @@ -148,6 +147,7 @@ func (c *APIClient) GetResponseBody(endpoint string) ([]byte, error) { return c.getResponseBodyFromRequest(req) } +// getResponseBodyFromRequest sends request and reads its response body func (c *APIClient) getResponseBodyFromRequest(req *retryablehttp.Request) ([]byte, error) { resp, err := c.doRequest(req, http.StatusOK) if err != nil { @@ -158,7 +158,16 @@ func (c *APIClient) getResponseBodyFromRequest(req *retryablehttp.Request) ([]by log.Debug().Err(closeErr).Msg("getResponseBody") } }() - return ioutil.ReadAll(resp.Body) + return io.ReadAll(resp.Body) +} + +// unmarshalResponseBody gets and unmarshal response body +func (c *APIClient) unmarshalResponseBody(endpoint string, output interface{}) error { + data, getErr := c.getResponseBody(endpoint) + if getErr != nil { + return getErr + } + return json.Unmarshal(data, output) } func (c *APIClient) PostResponseBody(endpoint string, body io.Reader) ([]byte, error) { @@ -176,7 +185,7 @@ func (c *APIClient) PostResponseBody(endpoint string, body io.Reader) ([]byte, e log.Debug().Err(closeErr).Msg("postResponseBody") } }() - return ioutil.ReadAll(resp.Body) + return io.ReadAll(resp.Body) } func (c *APIClient) doRequest(req *retryablehttp.Request, expectStatusCode int) (*http.Response, error) { @@ -210,48 +219,54 @@ func (c *APIClient) getReportStatusResponse(report ReportResponse) (*StatusRespo return &status, nil } -func (c *APIClient) GetUsers() ([]byte, error) { - return c.GetResponseBody(usersEndpoint) +func (c *APIClient) GetUsers() ([]*User, error) { + var users []*User + err := c.unmarshalResponseBody(usersEndpoint, &users) + return users, err } func (c *APIClient) GetRoles() ([]byte, error) { - return c.GetResponseBody(rolesEndpoint) + return c.getResponseBody(rolesEndpoint) } -func (c *APIClient) GetTeams() ([]byte, error) { - return c.GetResponseBody(teamsEndpoint) +func (c *APIClient) GetTeams() ([]*Team, error) { + var teams []*Team + err := c.unmarshalResponseBody(teamsEndpoint, &teams) + return teams, err } func (c *APIClient) GetLdapServers() ([]byte, error) { - return c.GetResponseBody(ldapServersEndpoint) + return c.getResponseBody(ldapServersEndpoint) } func (c *APIClient) GetLdapRoleMappings() ([]byte, error) { - return c.GetResponseBody(ldapRoleMappingsEndpoint) + return c.getResponseBody(ldapRoleMappingsEndpoint) } func (c *APIClient) GetLdapTeamMappings() ([]byte, error) { - return c.GetResponseBody(ldapTeamMappingsEndpoint) + return c.getResponseBody(ldapTeamMappingsEndpoint) } func (c *APIClient) GetSamlIdentityProviders() ([]byte, error) { - return c.GetResponseBody(samlIdentityProvidersEndpoint) + return c.getResponseBody(samlIdentityProvidersEndpoint) } func (c *APIClient) GetSamlRoleMappings() ([]byte, error) { - return c.GetResponseBody(samlRoleMappingsEndpoint) + return c.getResponseBody(samlRoleMappingsEndpoint) } -func (c *APIClient) GetSamlTeamMappings() ([]byte, error) { - return c.GetResponseBody(teamMappingsEndpoint) +func (c *APIClient) GetSamlTeamMappings() ([]*SamlTeamMapping, error) { + var samlTeamMappings []*SamlTeamMapping + err := c.unmarshalResponseBody(teamMappingsEndpoint, &samlTeamMappings) + return samlTeamMappings, err } func (c *APIClient) getReportIDStatus(reportID int) ([]byte, error) { - return c.GetResponseBody(fmt.Sprintf(reportsCheckStatusEndpoint, reportID)) + return c.getResponseBody(fmt.Sprintf(reportsCheckStatusEndpoint, reportID)) } func (c *APIClient) getReportResult(reportID int) ([]byte, error) { - return c.GetResponseBody(fmt.Sprintf(reportsResultEndpoint, reportID)) + return c.getResponseBody(fmt.Sprintf(reportsResultEndpoint, reportID)) } func (c *APIClient) postReportID(body io.Reader) ([]byte, error) { diff --git a/internal/integration/rest/apiclient_test.go b/internal/integration/rest/apiclient_test.go index 43831dd..c1bc264 100644 --- a/internal/integration/rest/apiclient_test.go +++ b/internal/integration/rest/apiclient_test.go @@ -3,7 +3,7 @@ package rest import ( "bytes" "fmt" - "io/ioutil" + "io" "net/http" "strings" "testing" @@ -19,6 +19,10 @@ const ( InvalidDataResponseJSON = `invalid data` ) +var ( + mockToken = &AccessToken{AccessToken: "jwt", TokenType: "Bearer", ExpiresIn: 1234} +) + type DoResponse struct { Response *http.Response Err error @@ -41,9 +45,19 @@ func (c *HTTPClientMock2) Do(request *retryablehttp.Request) (*http.Response, er return c.DoHandler(request) } +func newMockClient(response *http.Response) (*APIClient, error) { + adapter := &HTTPClientMock{DoResponse: response, DoError: nil} + client, err := NewSASTClient(BaseURL, adapter) + if err != nil { + return nil, err + } + client.Token = mockToken + return client, nil +} + func TestNewSASTClient(t *testing.T) { response := http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString("test")), + Body: io.NopCloser(bytes.NewBufferString("test")), } adapter := &HTTPClientMock{DoResponse: &response, DoError: nil} @@ -93,7 +107,7 @@ func TestAPIClient_Authenticate(t *testing.T) { response := http.Response{ StatusCode: 0, Status: "Unknown", - Body: ioutil.NopCloser(bytes.NewBufferString("")), + Body: io.NopCloser(bytes.NewBufferString("")), } adapter := &HTTPClientMock{DoResponse: &response, DoError: fmt.Errorf("can't connect to server")} client, _ := NewSASTClient(BaseURL, adapter) @@ -115,8 +129,6 @@ func TestAPIClient_Authenticate(t *testing.T) { } func TestAPIClient_doRequest(t *testing.T) { - mockToken := &AccessToken{AccessToken: "jwt", TokenType: "Bearer", ExpiresIn: 1234} - t.Run("returns successful response", func(t *testing.T) { request, err := retryablehttp.NewRequest("GET", "http://localhost/test", nil) assert.NoError(t, err) @@ -135,7 +147,7 @@ func TestAPIClient_doRequest(t *testing.T) { assert.NotNil(t, result) assert.Equal(t, result.StatusCode, expectedStatusCode) - content, ioErr := ioutil.ReadAll(result.Body) + content, ioErr := io.ReadAll(result.Body) assert.NoError(t, ioErr) assert.Equal(t, responseJSON, string(content)) }) @@ -161,28 +173,26 @@ func TestAPIClient_doRequest(t *testing.T) { // nolint:dupl func TestAPIClient_GetUsers(t *testing.T) { - mockToken := &AccessToken{AccessToken: "jwt", TokenType: "Bearer", ExpiresIn: 1234} t.Run("returns users response", func(t *testing.T) { responseJSON := `[{"id": 1, "userName": "test1", "lastLoginDate": "2021-08-17T12:22:28.2331383Z", "active": true}, {"id": 2, "userName": "test2", "lastLoginDate": "2021-08-17T12:22:28.2331383Z", "active": true}, {"id": 3, "userName": "test3", "lastLoginDate": "2021-08-17T12:22:28.2331383Z", "active": true}]` - response := makeOkResponse(responseJSON) //nolint:bodyclose - adapter := &HTTPClientMock{DoResponse: response, DoError: nil} - client, _ := NewSASTClient(BaseURL, adapter) - client.Token = mockToken + client, clientErr := newMockClient(makeOkResponse(responseJSON)) //nolint:bodyclose + assert.NoError(t, clientErr) result, err := client.GetUsers() assert.NoError(t, err) - assert.NotNil(t, result) - assert.Equal(t, responseJSON, string(result)) + expected := []*User{ + {ID: 1, UserName: "test1", LastLoginDate: "2021-08-17T12:22:28.2331383Z", Active: true}, + {ID: 2, UserName: "test2", LastLoginDate: "2021-08-17T12:22:28.2331383Z", Active: true}, + {ID: 3, UserName: "test3", LastLoginDate: "2021-08-17T12:22:28.2331383Z", Active: true}, + } + assert.Equal(t, expected, result) }) t.Run("returns error if response is not HTTP OK", func(t *testing.T) { - response := makeBadRequestResponse(ErrorResponseJSON) - defer response.Body.Close() - adapter := &HTTPClientMock{DoResponse: response, DoError: nil} - client, _ := NewSASTClient(BaseURL, adapter) - client.Token = mockToken + client, clientErr := newMockClient(makeBadRequestResponse(ErrorResponseJSON)) //nolint:bodyclose + assert.NoError(t, clientErr) result, err := client.GetUsers() @@ -193,28 +203,26 @@ func TestAPIClient_GetUsers(t *testing.T) { // nolint:dupl func TestAPIClient_GetTeams(t *testing.T) { - mockToken := &AccessToken{AccessToken: "jwt", TokenType: "Bearer", ExpiresIn: 1234} t.Run("returns teams response", func(t *testing.T) { - responseJSON := `[{"id": 1, "name": "test1", "fullName": "/CxServer/test1", "parentId": 1}, + responseJSON := `[{"id": 1, "name": "test1", "fullName": "/CxServer/test1", "parentId": 0}, {"id": 2, "name": "test2", "fullName": "/CxServer/test2", "parentId": 1}, {"id": 3, "name": "test3", "fullName": "/CxServer/test3", "parentId": 1}]` - response := makeOkResponse(responseJSON) //nolint:bodyclose - adapter := &HTTPClientMock{DoResponse: response, DoError: nil} - client, _ := NewSASTClient(BaseURL, adapter) - client.Token = mockToken + client, clientErr := newMockClient(makeOkResponse(responseJSON)) //nolint:bodyclose + assert.NoError(t, clientErr) result, err := client.GetTeams() assert.NoError(t, err) - assert.NotNil(t, result) - assert.Equal(t, responseJSON, string(result)) + expected := []*Team{ + {ID: 1, Name: "test1", FullName: "/CxServer/test1", ParendID: 0}, + {ID: 2, Name: "test2", FullName: "/CxServer/test2", ParendID: 1}, + {ID: 3, Name: "test3", FullName: "/CxServer/test3", ParendID: 1}, + } + assert.Equal(t, expected, result) }) t.Run("returns error if response is not HTTP OK", func(t *testing.T) { - response := makeBadRequestResponse(ErrorResponseJSON) - defer response.Body.Close() - adapter := &HTTPClientMock{DoResponse: response, DoError: nil} - client, _ := NewSASTClient(BaseURL, adapter) - client.Token = mockToken + client, clientErr := newMockClient(makeBadRequestResponse(ErrorResponseJSON)) //nolint:bodyclose + assert.NoError(t, clientErr) result, err := client.GetTeams() @@ -223,9 +231,33 @@ func TestAPIClient_GetTeams(t *testing.T) { }) } +func TestAPIClient_GetSamlTeamMappings(t *testing.T) { + t.Run("success case", func(t *testing.T) { + responseJSON := `[{"id":3,"samlIdentityProviderId":2,"teamId":4,"teamFullPath":"/CxServer/Mapped SAML","samlAttributeValue":"TeamA"}]` + client, clientErr := newMockClient(makeOkResponse(responseJSON)) //nolint:bodyclose + assert.NoError(t, clientErr) + + result, err := client.GetSamlTeamMappings() + + assert.NoError(t, err) + expected := []*SamlTeamMapping{ + {ID: 3, SamlIdentityProviderID: 2, TeamID: 4, TeamFullPath: "/CxServer/Mapped SAML", SamlAttributeValue: "TeamA"}, + } + assert.Equal(t, expected, result) + }) + t.Run("failure case", func(t *testing.T) { + client, clientErr := newMockClient(makeBadRequestResponse(ErrorResponseJSON)) //nolint:bodyclose + assert.NoError(t, clientErr) + + result, err := client.GetSamlTeamMappings() + + assert.Error(t, err) + assert.Len(t, result, 0) + }) +} + // nolint:dupl func TestAPIClient_GetRoles(t *testing.T) { - mockToken := &AccessToken{AccessToken: "jwt", TokenType: "Bearer", ExpiresIn: 1234} t.Run("returns teams response", func(t *testing.T) { responseJSON := `[{"id": 1, "isSystemRole": true, "name": "test1", "description": "test1", permissionIds: []}, {"id": 2, "isSystemRole": true, "name": "test2", "description": "test2", permissionIds: []}, @@ -264,7 +296,6 @@ func TestAPIClient_GetProjectsWithLastScanID(t *testing.T) { {"Id": 2,"LastScanId": 1000001,"LastScan": {"Id": 1000001}} ] }` - mockToken := &AccessToken{AccessToken: "jwt", TokenType: "Bearer", ExpiresIn: 1234} adapter := &HTTPClientMock{DoResponse: makeOkResponse(odataResponse), DoError: nil} //nolint:bodyclose client, _ := NewSASTClient(BaseURL, adapter) client.Token = mockToken @@ -288,7 +319,6 @@ func TestAPIClient_GetTriagedResultsByScanID(t *testing.T) { {"Id": 3} ] }` - mockToken := &AccessToken{AccessToken: "jwt", TokenType: "Bearer", ExpiresIn: 1234} response := makeOkResponse(odataResponse) defer response.Body.Close() adapter := &HTTPClientMock{DoResponse: response, DoError: nil} @@ -490,7 +520,7 @@ func makeOkResponse(body string) *http.Response { return &http.Response{ StatusCode: 200, Status: "OK", - Body: ioutil.NopCloser(bytes.NewBufferString(body)), + Body: io.NopCloser(bytes.NewBufferString(body)), } } @@ -498,7 +528,7 @@ func makeBadRequestResponse(body string) *http.Response { return &http.Response{ StatusCode: 400, Status: "Bad Request", - Body: ioutil.NopCloser(bytes.NewBufferString(body)), + Body: io.NopCloser(bytes.NewBufferString(body)), } } @@ -506,7 +536,7 @@ func makeResponse(statusCode int, status, body string) *http.Response { return &http.Response{ StatusCode: statusCode, Status: status, - Body: ioutil.NopCloser(bytes.NewBufferString(body)), + Body: io.NopCloser(bytes.NewBufferString(body)), } } diff --git a/internal/integration/rest/models.go b/internal/integration/rest/models.go index a35c95d..c366271 100644 --- a/internal/integration/rest/models.go +++ b/internal/integration/rest/models.go @@ -55,4 +55,41 @@ type ( TriagedScanResult struct { ID int `json:"Id"` } + + Team struct { + ID int `json:"id"` + Name string `json:"name"` + FullName string `json:"fullName"` + ParendID int `json:"parentId"` + } + + User struct { + ID int `json:"id"` + UserName string `json:"userName"` + LastLoginDate string `json:"lastLoginDate"` + RoleIDs []int `json:"roleIds"` + TeamIDs []int `json:"teamIds"` + AuthenticationProviderID int `json:"authenticationProviderId"` + CreationDate string `json:"creationDate"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + Email string `json:"email"` + PhoneNumber string `json:"phoneNumber"` + CellPhoneNumber string `json:"cellPhoneNumber"` + JobTitle string `json:"jobTitle"` + Other string `json:"other"` + Country string `json:"country"` + Active bool `json:"active"` + ExpirationDate string `json:"expirationDate"` + AllowedIPList []string `json:"allowedIpList"` + LocaleID int `json:"localeId"` + } + + SamlTeamMapping struct { + ID int `json:"id"` + SamlIdentityProviderID int `json:"samlIdentityProviderId"` + TeamID int `json:"teamId"` + TeamFullPath string `json:"teamFullPath"` + SamlAttributeValue string `json:"samlAttributeValue"` + } ) diff --git a/internal/integration/rest/requests_test.go b/internal/integration/rest/requests_test.go index 726d6cc..ec6957c 100644 --- a/internal/integration/rest/requests_test.go +++ b/internal/integration/rest/requests_test.go @@ -3,7 +3,6 @@ package rest import ( "bytes" "io" - "io/ioutil" "net/http" "strings" "testing" @@ -51,7 +50,7 @@ func TestRequests_CreateRequest(t *testing.T) { response := http.Response{ StatusCode: 400, Status: "Bad Request", - Body: ioutil.NopCloser(bytes.NewBufferString(ErrorResponseJSON)), + Body: io.NopCloser(bytes.NewBufferString(ErrorResponseJSON)), } adapter := &HTTPClientMock{DoResponse: &response, DoError: nil} client, _ := NewSASTClient(BaseURL, adapter) diff --git a/internal/process.go b/internal/process.go index 226a3e5..0de33d5 100644 --- a/internal/process.go +++ b/internal/process.go @@ -232,7 +232,16 @@ func fetchSelectedData(client rest.Client, exporter export2.Exporter, args *Args func fetchUsersData(client rest.Client, exporter export2.Exporter) error { log.Info().Msg("collecting users") - if err := exporter.AddFileWithDataSource(export2.UsersFileName, client.GetUsers); err != nil { + users, usersErr := client.GetUsers() + if usersErr != nil { + return errors.Wrap(usersErr, "failed getting users") + } + teams, teamsErr := client.GetTeams() + if teamsErr != nil { + return errors.Wrap(teamsErr, "failed getting teams") + } + usersDataSource := export2.NewJSONDataSource(export2.TransformUsers(users, teams)) + if err := exporter.AddFileWithDataSource(export2.UsersFileName, usersDataSource); err != nil { return err } if err := exporter.AddFileWithDataSource(export2.RolesFileName, client.GetRoles); err != nil { @@ -259,13 +268,23 @@ func fetchUsersData(client rest.Client, exporter export2.Exporter) error { func fetchTeamsData(client rest.Client, exporter export2.Exporter) error { log.Info().Msg("collecting teams") - if err := exporter.AddFileWithDataSource(export2.TeamsFileName, client.GetTeams); err != nil { + teams, teamsErr := client.GetTeams() + if teamsErr != nil { + return errors.Wrap(teamsErr, "failed getting teams") + } + teamsDataSource := export2.NewJSONDataSource(export2.TransformTeams(teams)) + if err := exporter.AddFileWithDataSource(export2.TeamsFileName, teamsDataSource); err != nil { return err } if err := exporter.AddFileWithDataSource(export2.LdapTeamMappingsFileName, client.GetLdapTeamMappings); err != nil { return err } - if err := exporter.AddFileWithDataSource(export2.SamlTeamMappingsFileName, client.GetSamlTeamMappings); err != nil { + samlTeamMappings, samlTeamMappingsErr := client.GetSamlTeamMappings() + if samlTeamMappingsErr != nil { + return errors.Wrap(samlTeamMappingsErr, "failed getting saml team mappings") + } + samlTeamMappingsDataSource := export2.NewJSONDataSource(export2.TransformSamlTeamMappings(samlTeamMappings)) + if err := exporter.AddFileWithDataSource(export2.SamlTeamMappingsFileName, samlTeamMappingsDataSource); err != nil { return err } if _, fileErr := os.Stat(export2.LdapServersFileName); os.IsNotExist(fileErr) { @@ -459,7 +478,13 @@ func consumeReports(client rest.Client, exporter export2.Exporter, workerID int, } } // export report - exportErr := exporter.AddFile(fmt.Sprintf(scansFileName, reportJob.ProjectID), reportData) + transformedReportData, transformErr := export2.TransformScanReport(reportData) + if transformErr != nil { + l.Debug().Err(transformErr).Msg("failed transforming report data") + done <- ReportConsumeOutput{Err: transformErr, ProjectID: reportJob.ProjectID, ScanID: reportJob.ScanID} + continue + } + exportErr := exporter.AddFile(fmt.Sprintf(scansFileName, reportJob.ProjectID), transformedReportData) if exportErr != nil { l.Debug().Err(exportErr).Msg("failed saving result") done <- ReportConsumeOutput{Err: exportErr, ProjectID: reportJob.ProjectID, ScanID: reportJob.ScanID} diff --git a/internal/process_test.go b/internal/process_test.go index 9f03bc4..dceafeb 100644 --- a/internal/process_test.go +++ b/internal/process_test.go @@ -2,7 +2,7 @@ package internal import ( "fmt" - "io/ioutil" + "os" "testing" "time" @@ -31,6 +31,7 @@ type mockExpectProps struct { type usersExpect struct { Users mockExpectProps + Teams mockExpectProps Roles mockExpectProps LdapRoleMappings mockExpectProps SamlRoleMappings mockExpectProps @@ -49,9 +50,14 @@ type teamsExpect struct { func fetchUsersSetupExpects(client *mock_integration_rest.MockClient, expect *usersExpect) { client.EXPECT(). GetUsers(). - Return([]byte{}, expect.Users.ReturnError). + Return([]*rest.User{}, expect.Users.ReturnError). MinTimes(expect.Users.RunCount). MaxTimes(expect.Users.RunCount) + client.EXPECT(). + GetTeams(). + Return([]*rest.Team{}, expect.Teams.ReturnError). + MinTimes(expect.Teams.RunCount). + MaxTimes(expect.Teams.RunCount) client.EXPECT(). GetRoles(). Return([]byte{}, expect.Roles.ReturnError). @@ -82,7 +88,7 @@ func fetchUsersSetupExpects(client *mock_integration_rest.MockClient, expect *us func fetchTeamsSetupExpects(client *mock_integration_rest.MockClient, expect *teamsExpect) { client.EXPECT(). GetTeams(). - Return([]byte{}, expect.Teams.ReturnError). + Return([]*rest.Team{}, expect.Teams.ReturnError). MinTimes(expect.Teams.RunCount). MaxTimes(expect.Teams.RunCount) client.EXPECT(). @@ -92,7 +98,7 @@ func fetchTeamsSetupExpects(client *mock_integration_rest.MockClient, expect *te MaxTimes(expect.LdapTeamMappings.RunCount) client.EXPECT(). GetSamlTeamMappings(). - Return([]byte{}, expect.SamlTeamMappings.ReturnError). + Return([]*rest.SamlTeamMapping{}, expect.SamlTeamMappings.ReturnError). MinTimes(expect.SamlTeamMappings.RunCount). MaxTimes(expect.SamlTeamMappings.RunCount) client.EXPECT(). @@ -283,6 +289,7 @@ func TestFetchUsersData(t *testing.T) { { usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{rolesErr, 1}, }, rolesErr, @@ -290,6 +297,7 @@ func TestFetchUsersData(t *testing.T) { { usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{ldapMappingsErr, 1}, }, @@ -298,6 +306,7 @@ func TestFetchUsersData(t *testing.T) { { usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, SamlRoleMappings: mockExpectProps{samlMappingsErr, 1}, @@ -307,6 +316,7 @@ func TestFetchUsersData(t *testing.T) { { usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, SamlRoleMappings: mockExpectProps{nil, 1}, @@ -317,6 +327,7 @@ func TestFetchUsersData(t *testing.T) { { usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, SamlRoleMappings: mockExpectProps{nil, 1}, @@ -360,6 +371,7 @@ func TestFetchUsersData(t *testing.T) { { fetchMockExpects: usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, }, writeMockExpects: usersExpect{ Users: mockExpectProps{usersErr, 1}, @@ -369,6 +381,7 @@ func TestFetchUsersData(t *testing.T) { { fetchMockExpects: usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, }, writeMockExpects: usersExpect{ @@ -380,6 +393,7 @@ func TestFetchUsersData(t *testing.T) { { fetchMockExpects: usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, }, @@ -393,6 +407,7 @@ func TestFetchUsersData(t *testing.T) { { fetchMockExpects: usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, SamlRoleMappings: mockExpectProps{nil, 1}, @@ -408,6 +423,7 @@ func TestFetchUsersData(t *testing.T) { { fetchMockExpects: usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, SamlRoleMappings: mockExpectProps{nil, 1}, @@ -425,6 +441,7 @@ func TestFetchUsersData(t *testing.T) { { fetchMockExpects: usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, SamlRoleMappings: mockExpectProps{nil, 1}, @@ -459,6 +476,7 @@ func TestFetchUsersData(t *testing.T) { client := mock_integration_rest.NewMockClient(gomock.NewController(t)) fetchUsersSetupExpects(client, &usersExpect{ Users: mockExpectProps{nil, 1}, + Teams: mockExpectProps{nil, 1}, Roles: mockExpectProps{nil, 1}, LdapRoleMappings: mockExpectProps{nil, 1}, SamlRoleMappings: mockExpectProps{nil, 1}, @@ -828,7 +846,7 @@ func TestProduceReports(t *testing.T) { } func TestConsumeReports(t *testing.T) { - report1, ioErr := ioutil.ReadFile("../test/data/process/report1.xml") + report1, ioErr := os.ReadFile("../test/data/process/report1.xml") assert.NoError(t, ioErr) reportCount := 4 reportJobs := make(chan ReportJob, reportCount) @@ -1008,6 +1026,8 @@ func TestFetchSelectedData(t *testing.T) { t.Run("export users success case", func(t *testing.T) { ctrl := gomock.NewController(t) client := mock_integration_rest.NewMockClient(ctrl) + client.EXPECT().GetUsers().Return([]*rest.User{}, nil) + client.EXPECT().GetTeams().Return([]*rest.Team{}, nil) exporter := mock_app_export.NewMockExporter(ctrl) exporter.EXPECT().AddFileWithDataSource(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() args := Args{ @@ -1023,6 +1043,8 @@ func TestFetchSelectedData(t *testing.T) { t.Run("export users fails if fetch or write fails", func(t *testing.T) { ctrl := gomock.NewController(t) client := mock_integration_rest.NewMockClient(ctrl) + client.EXPECT().GetUsers().Return([]*rest.User{}, nil) + client.EXPECT().GetTeams().Return([]*rest.Team{}, nil) exporter := mock_app_export.NewMockExporter(ctrl) exporter.EXPECT().AddFileWithDataSource(gomock.Eq(export.UsersFileName), gomock.Any()). Return(nil) @@ -1041,6 +1063,9 @@ func TestFetchSelectedData(t *testing.T) { t.Run("export users and teams success case", func(t *testing.T) { ctrl := gomock.NewController(t) client := mock_integration_rest.NewMockClient(ctrl) + client.EXPECT().GetUsers().Return([]*rest.User{}, nil) + client.EXPECT().GetTeams().Return([]*rest.Team{}, nil).Times(2) + client.EXPECT().GetSamlTeamMappings().Return([]*rest.SamlTeamMapping{}, nil) exporter := mock_app_export.NewMockExporter(ctrl) exporter.EXPECT().AddFileWithDataSource(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() args := Args{ @@ -1056,6 +1081,8 @@ func TestFetchSelectedData(t *testing.T) { t.Run("export users and teams fail if fetch or write fails", func(t *testing.T) { ctrl := gomock.NewController(t) client := mock_integration_rest.NewMockClient(ctrl) + client.EXPECT().GetUsers().Return([]*rest.User{}, nil) + client.EXPECT().GetTeams().Return([]*rest.Team{}, nil).Times(2) exporter := mock_app_export.NewMockExporter(ctrl) exporter.EXPECT().AddFileWithDataSource(gomock.Eq(export.UsersFileName), gomock.Any()). Return(nil) @@ -1090,6 +1117,9 @@ func TestFetchSelectedData(t *testing.T) { {ID: 1, LastScanID: 1}, {ID: 2, LastScanID: 2}, } + client.EXPECT().GetUsers().Return([]*rest.User{}, nil) + client.EXPECT().GetTeams().Return([]*rest.Team{}, nil).Times(2) + client.EXPECT().GetSamlTeamMappings().Return([]*rest.SamlTeamMapping{}, nil) client.EXPECT(). GetProjectsWithLastScanID(gomock.Any(), gomock.Eq(0), gomock.Any()). Return(&projectPage, nil) @@ -1122,6 +1152,9 @@ func TestFetchSelectedData(t *testing.T) { t.Run("export users, teams and results fails if result processing fails", func(t *testing.T) { ctrl := gomock.NewController(t) client := mock_integration_rest.NewMockClient(ctrl) + client.EXPECT().GetUsers().Return([]*rest.User{}, nil) + client.EXPECT().GetTeams().Return([]*rest.Team{}, nil).Times(2) + client.EXPECT().GetSamlTeamMappings().Return([]*rest.SamlTeamMapping{}, nil) client.EXPECT(). GetProjectsWithLastScanID(gomock.Any(), gomock.Eq(0), gomock.Any()). Return(&[]rest.ProjectWithLastScanID{}, fmt.Errorf("failed fetching projects")) diff --git a/test/mocks/integration/rest/mock_client.go b/test/mocks/integration/rest/mock_client.go index 67c6182..076717e 100644 --- a/test/mocks/integration/rest/mock_client.go +++ b/test/mocks/integration/rest/mock_client.go @@ -124,21 +124,6 @@ func (mr *MockClientMockRecorder) GetProjectsWithLastScanID(arg0, arg1, arg2 int return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProjectsWithLastScanID", reflect.TypeOf((*MockClient)(nil).GetProjectsWithLastScanID), arg0, arg1, arg2) } -// GetResponseBody mocks base method. -func (m *MockClient) GetResponseBody(arg0 string) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetResponseBody", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetResponseBody indicates an expected call of GetResponseBody. -func (mr *MockClientMockRecorder) GetResponseBody(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResponseBody", reflect.TypeOf((*MockClient)(nil).GetResponseBody), arg0) -} - // GetRoles mocks base method. func (m *MockClient) GetRoles() ([]byte, error) { m.ctrl.T.Helper() @@ -185,10 +170,10 @@ func (mr *MockClientMockRecorder) GetSamlRoleMappings() *gomock.Call { } // GetSamlTeamMappings mocks base method. -func (m *MockClient) GetSamlTeamMappings() ([]byte, error) { +func (m *MockClient) GetSamlTeamMappings() ([]*rest.SamlTeamMapping, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSamlTeamMappings") - ret0, _ := ret[0].([]byte) + ret0, _ := ret[0].([]*rest.SamlTeamMapping) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -200,10 +185,10 @@ func (mr *MockClientMockRecorder) GetSamlTeamMappings() *gomock.Call { } // GetTeams mocks base method. -func (m *MockClient) GetTeams() ([]byte, error) { +func (m *MockClient) GetTeams() ([]*rest.Team, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetTeams") - ret0, _ := ret[0].([]byte) + ret0, _ := ret[0].([]*rest.Team) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -230,10 +215,10 @@ func (mr *MockClientMockRecorder) GetTriagedResultsByScanID(arg0 interface{}) *g } // GetUsers mocks base method. -func (m *MockClient) GetUsers() ([]byte, error) { +func (m *MockClient) GetUsers() ([]*rest.User, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUsers") - ret0, _ := ret[0].([]byte) + ret0, _ := ret[0].([]*rest.User) ret1, _ := ret[1].(error) return ret0, ret1 }