diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a2e0848fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# IDE logic +.vscode + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +/bin +bin/* +*.env + +credentials.ast + + +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Ignore any .tfvars files that are generated automatically for each Terraform run. Most +# .tfvars files are managed as part of configuration and so should be included in +# version control. +# +# example.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index 7c689669d..b3505604c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -12,11 +12,14 @@ import ( ) const ( - astURIEnv = "AST_URI" - scansPathEnv = "SCANS_PATH" - projectsPathEnv = "PROJECTS_PATH" - resultsPathEnv = "RESULTS_PATH" - uploadsPathEnv = "UPLOADS_PATH" + astURIEnv = "AST_URI" + scansPathEnv = "SCANS_PATH" + projectsPathEnv = "PROJECTS_PATH" + resultsPathEnv = "RESULTS_PATH" + bflPathEnv = "BFL_PATH" + uploadsPathEnv = "UPLOADS_PATH" + credentialsFilePathEnv = "CREDENTIALS_FILE_PATH" + tokenExpirySecondsEnv = "TOKEN_EXPIRY_SECONDS" successfulExitCode = 0 failureExitCode = 1 @@ -44,6 +47,11 @@ func main() { exitIfError(err) results := viper.GetString(resultsPathKey) + bflPathKey := strings.ToLower(bflPathEnv) + err = bindKeyToEnvAndDefault(bflPathKey, bflPathEnv, "api/bfl") + exitIfError(err) + bfl := viper.GetString(bflPathKey) + uploadsPathKey := strings.ToLower(uploadsPathEnv) err = bindKeyToEnvAndDefault(uploadsPathKey, uploadsPathEnv, "api/uploads") exitIfError(err) @@ -56,17 +64,27 @@ func main() { err = bindKeyToEnvAndDefault(commands.AstAuthenticationURIConfigKey, commands.AstAuthenticationURIEnv, "") exitIfError(err) + credentialsFilePathKey := strings.ToLower(credentialsFilePathEnv) + err = bindKeyToEnvAndDefault(credentialsFilePathKey, credentialsFilePathEnv, "credentials.ast") + exitIfError(err) + + tokenExpirySecondsKey := strings.ToLower(tokenExpirySecondsEnv) + err = bindKeyToEnvAndDefault(tokenExpirySecondsKey, tokenExpirySecondsEnv, "300") + exitIfError(err) + scansURL := fmt.Sprintf("%s/%s", ast, scans) uploadsURL := fmt.Sprintf("%s/%s", ast, uploads) projectsURL := fmt.Sprintf("%s/%s", ast, projects) resultsURL := fmt.Sprintf("%s/%s", ast, results) + bflURL := fmt.Sprintf("%s/%s", ast, bfl) scansWrapper := wrappers.NewHTTPScansWrapper(scansURL) uploadsWrapper := wrappers.NewUploadsHTTPWrapper(uploadsURL) projectsWrapper := wrappers.NewHTTPProjectsWrapper(projectsURL) resultsWrapper := wrappers.NewHTTPResultsWrapper(resultsURL) + bflWrapper := wrappers.NewHTTPBFLWrapper(bflURL) - astCli := commands.NewAstCLI(scansWrapper, uploadsWrapper, projectsWrapper, resultsWrapper) + astCli := commands.NewAstCLI(scansWrapper, uploadsWrapper, projectsWrapper, resultsWrapper, bflWrapper) err = astCli.Execute() exitIfError(err) @@ -84,9 +102,3 @@ func bindKeyToEnvAndDefault(key, env, defaultVal string) error { viper.SetDefault(key, defaultVal) return err } - -// When building an executable for Windows and providing a name, -// be sure to explicitly specify the .exe suffix when setting the executable’s name. -// env GOOS=windows GOARCH=amd64 go build -o ./bin/ast.exe ./cmd -// "bin/ast.exe" -v scan create --input-file ./internal/commands/payloads/uploads.json --sources ./internal/commands/payloads/sources.zip -// "bin/ast.exe" scan list 4d9a9189-ddcc-4aa0-ba2f-9d6d7f92eceb diff --git a/go.mod b/go.mod index 6df4a8338..2ff6cee2c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/checkmarxDev/ast-cli go 1.13 require ( - github.com/checkmarxDev/scans v1.2.7 + github.com/checkmarxDev/scans v1.2.8 github.com/checkmarxDev/uploads v1.0.0 github.com/pkg/errors v0.8.1 github.com/spf13/cobra v0.0.6 diff --git a/go.sum b/go.sum index 067d4771e..267382168 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/checkmarxDev/scans v1.2.7 h1:yGOZaWttkY0Ll6B2rQi70PKoRnh9VjMDPmtJjI71H/E= github.com/checkmarxDev/scans v1.2.7/go.mod h1:hcAM6h2mAq8iC+IgqaKUPDFsKoYJEnLJFFPt/wJdnhA= +github.com/checkmarxDev/scans v1.2.8 h1:wZFI+XGsGIKCJXxcz6HW/QljVR1+7NCI45FbWLtVdK8= +github.com/checkmarxDev/scans v1.2.8/go.mod h1:hcAM6h2mAq8iC+IgqaKUPDFsKoYJEnLJFFPt/wJdnhA= github.com/checkmarxDev/uploads v1.0.0 h1:Bypl38qpKyYM/P4WH+qnMC/cMrmXL+3gDgAZ8dc+wSY= github.com/checkmarxDev/uploads v1.0.0/go.mod h1:7WMSc96f012/4O3+3rYV2vhKI9GTEBGNVkp56b8F0ok= github.com/cheggaaa/pb v1.0.28/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= diff --git a/internal/commands/bfl.go b/internal/commands/bfl.go new file mode 100644 index 000000000..8238d5c86 --- /dev/null +++ b/internal/commands/bfl.go @@ -0,0 +1,106 @@ +package commands + +import ( + "encoding/json" + "fmt" + + "github.com/checkmarxDev/ast-cli/internal/wrappers" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +const ( + failedGettingBfl = "Failed getting BFL" +) + +func NewBFLCommand(bflWrapper wrappers.BFLWrapper) *cobra.Command { + bflCmd := &cobra.Command{ + Use: "bfl", + Short: "Retrieve Best Fix Location for a given scan ID", + RunE: runGetBFLByScanIDCommand(bflWrapper), + } + + bflCmd.PersistentFlags().Uint64P(limitFlag, limitFlagSh, 0, limitUsage) + bflCmd.PersistentFlags().Uint64P(offsetFlag, offsetFlagSh, 0, offsetUsage) + + return bflCmd +} + +func runGetBFLByScanIDCommand(bflWrapper wrappers.BFLWrapper) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + var bflResponseModel *wrappers.BFLResponseModel + var errorModel *wrappers.ErrorModel + var err error + if len(args) == 0 { + return errors.Errorf("%s: Please provide a scan ID", failedGettingBfl) + } + scanID := args[0] + limit, offset := getLimitAndOffset(cmd) + + bflResponseModel, errorModel, err = bflWrapper.GetByScanID(scanID, limit, offset) + if err != nil { + return errors.Wrapf(err, "%s", failedGettingBfl) + } + // Checking the response + if errorModel != nil { + return errors.Errorf("%s: CODE: %d, %s", failedGettingBfl, errorModel.Code, errorModel.Message) + } else if bflResponseModel != nil { + err = outputBFL(cmd, bflResponseModel) + if err != nil { + return err + } + } + return nil + } +} + +func outputBFL(cmd *cobra.Command, model *wrappers.BFLResponseModel) error { + if IsJSONFormat() { + var bflJSON []byte + bflJSON, err := json.Marshal(model) + if err != nil { + return errors.Wrapf(err, "%s: failed to serialize results response ", failedGettingBfl) + } + fmt.Fprintln(cmd.OutOrStdout(), string(bflJSON)) + } else if IsPrettyFormat() { + fmt.Println("************ Best Fix Location ************") + fmt.Println("BFL ID:", model.ID) + fmt.Println() + for i := 0; i < len(model.Trees); i++ { + fmt.Println("************ Tree ************") + fmt.Println("ID:", model.Trees[i].ID) + fmt.Println() + fmt.Println("************ BFL Node ************") + bfl := model.Trees[i].BFL + outputSingleResultNodePretty(&wrappers.ResultNode{ + Column: bfl.Column, + FileName: bfl.FileName, + FullName: bfl.FullName, + Length: bfl.Length, + Line: bfl.Line, + MethodLine: bfl.MethodLine, + Name: bfl.Name, + NodeID: bfl.NodeID, + DomType: bfl.DomType, + NodeSystemID: bfl.NodeSystemID, + }) + fmt.Println() + err := outputResultsPretty(model.Trees[i].Results) + if err != nil { + return err + } + } + } + return nil +} + +func outputSingleResultNodePretty(model *wrappers.ResultNode) { + fmt.Println("Name:", model.Name) + fmt.Println("File Name:", model.FileName) + fmt.Println("Full Name:", model.FullName) + fmt.Println("Length:", model.Length) + fmt.Println("Column:", model.Column) + fmt.Println("Line:", model.Line) + fmt.Println("Method Line:", model.MethodLine) + fmt.Println("Node System ID:", model.NodeSystemID) +} diff --git a/internal/commands/project.go b/internal/commands/project.go index a88434c4a..360d81ccd 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -9,7 +9,8 @@ import ( "github.com/pkg/errors" wrappers "github.com/checkmarxDev/ast-cli/internal/wrappers" - projectsRESTApi "github.com/checkmarxDev/scans/api/v1/rest/projects" + + projectsRESTApi "github.com/checkmarxDev/scans/pkg/api/projects/v1/rest" "github.com/spf13/cobra" ) @@ -230,10 +231,10 @@ func outputProjects(cmd *cobra.Command, model *projectsRESTApi.SlicedProjectsRes } else if IsPrettyFormat() { for _, project := range model.Projects { outputSingleProject(&projectsRESTApi.ProjectResponseModel{ - ID: project.ID, - Created: project.Created, - Updated: project.Updated, - Tags: project.Tags, + ID: project.ID, + CreatedAt: project.CreatedAt, + UpdatedAt: project.UpdatedAt, + Tags: project.Tags, }) } } @@ -258,9 +259,8 @@ func outputProject(cmd *cobra.Command, model *projectsRESTApi.ProjectResponseMod } func outputSingleProject(model *projectsRESTApi.ProjectResponseModel) { - fmt.Println("----------------------------") fmt.Println("Project ID:", model.ID) - fmt.Println("Created at:", model.Created) - fmt.Println("Updated at:", model.Updated) + fmt.Println("Created at:", model.CreatedAt) + fmt.Println("Updated at:", model.UpdatedAt) fmt.Println("Tags:", model.Tags) } diff --git a/internal/commands/project_test.go b/internal/commands/project_test.go index 95fff3c92..6f90b975f 100644 --- a/internal/commands/project_test.go +++ b/internal/commands/project_test.go @@ -121,6 +121,14 @@ func TestRunGetAllProjectsCommandWithLimit(t *testing.T) { assert.NilError(t, err) } +func TestRunGetAllProjectsCommandWithLimitPretty(t *testing.T) { + cmd := createASTTestCommand() + err := executeTestCommand(cmd, "-v", "project", "list", "--format", "pretty", "--limit", "40") + assert.NilError(t, err) + err = executeTestCommand(cmd, "-v", "project", "list", "--format", "pretty", "-l", "40") + assert.NilError(t, err) +} + func TestRunGetAllProjectsCommandWithOffset(t *testing.T) { cmd := createASTTestCommand() err := executeTestCommand(cmd, "-v", "project", "list", "--offset", "150") diff --git a/internal/commands/result.go b/internal/commands/result.go index d7eaa9ec9..4d29d0a13 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -33,8 +33,8 @@ func NewResultCommand(resultsWrapper wrappers.ResultsWrapper) *cobra.Command { func runGetResultByScanIDCommand(resultsWrapper wrappers.ResultsWrapper) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - var resultResponseModel []wrappers.ResultResponseModel - var errorModel *wrappers.ResultError + var resultResponseModel *wrappers.ResultsResponseModel + var errorModel *wrappers.ErrorModel var err error if len(args) == 0 { return errors.Errorf("%s: Please provide a scan ID", failedListingResults) @@ -50,14 +50,64 @@ func runGetResultByScanIDCommand(resultsWrapper wrappers.ResultsWrapper) func(cm if errorModel != nil { return errors.Errorf("%s: CODE: %d, %s", failedListingResults, errorModel.Code, errorModel.Message) } else if resultResponseModel != nil { - var responseModelJSON []byte - responseModelJSON, err = json.Marshal(resultResponseModel) - if err != nil { - return errors.Wrapf(err, "%s: failed to serialize results response ", failedListingResults) + if IsJSONFormat() { + var resultsJSON []byte + resultsJSON, err = json.Marshal(resultResponseModel) + if err != nil { + return errors.Wrapf(err, "%s: failed to serialize results response ", failedGettingAll) + } + fmt.Fprintln(cmd.OutOrStdout(), string(resultsJSON)) + } else if IsPrettyFormat() { + err = outputResultsPretty(resultResponseModel.Results) + if err != nil { + return err + } } - cmdOut := cmd.OutOrStdout() - fmt.Fprintln(cmdOut, string(responseModelJSON)) } return nil } } + +func outputResultsPretty(results []wrappers.ResultResponseModel) error { + fmt.Println("************ Results ************") + for i := 0; i < len(results); i++ { + outputSingleResult(&wrappers.ResultResponseModel{ + QueryID: results[i].QueryID, + QueryName: results[i].QueryName, + Severity: results[i].Severity, + CweID: results[i].CweID, + SimilarityID: results[i].SimilarityID, + UniqueID: results[i].UniqueID, + FirstScanID: results[i].FirstScanID, + FirstFoundAt: results[i].FirstFoundAt, + FoundAt: results[i].FoundAt, + Status: results[i].Status, + PathSystemID: results[i].PathSystemID, + PathSystemIDBySimiAndFilesPaths: results[i].PathSystemIDBySimiAndFilesPaths, + Nodes: results[i].Nodes, + }) + fmt.Println() + } + return nil +} + +func outputSingleResult(model *wrappers.ResultResponseModel) { + fmt.Println("Result Unique ID:", model.UniqueID) + fmt.Println("Query ID:", model.QueryID) + fmt.Println("Query Name:", model.QueryName) + fmt.Println("Severity:", model.Severity) + fmt.Println("CWE ID:", model.CweID) + fmt.Println("Similarity ID:", model.SimilarityID) + fmt.Println("First Scan ID:", model.FirstScanID) + fmt.Println("Found At:", model.FoundAt) + fmt.Println("First Found At:", model.FirstFoundAt) + fmt.Println("Status:", model.Status) + fmt.Println("Path System ID:", model.PathSystemID) + fmt.Println("Path System ID (by similarity and file paths):", model.PathSystemIDBySimiAndFilesPaths) + fmt.Println() + fmt.Println("************ Nodes ************") + for i := 0; i < len(model.Nodes); i++ { + outputSingleResultNodePretty(model.Nodes[i]) + fmt.Println() + } +} diff --git a/internal/commands/result_test.go b/internal/commands/result_test.go index fbd557e23..8a489fbcb 100644 --- a/internal/commands/result_test.go +++ b/internal/commands/result_test.go @@ -25,3 +25,9 @@ func TestRunGetResultsByScanIDCommand(t *testing.T) { err := executeTestCommand(cmd, "-v", "result", "list", "MOCK") assert.NilError(t, err) } + +func TestRunGetResultsByScanIDCommandPretty(t *testing.T) { + cmd := createASTTestCommand() + err := executeTestCommand(cmd, "-v", "result", "--format", "pretty", "list", "MOCK") + assert.NilError(t, err) +} diff --git a/internal/commands/root.go b/internal/commands/root.go index e56f21612..9244a1b77 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -51,10 +51,12 @@ var ( ) // Return an AST CLI root command to execute -func NewAstCLI(scansWrapper wrappers.ScansWrapper, +func NewAstCLI( + scansWrapper wrappers.ScansWrapper, uploadsWrapper wrappers.UploadsWrapper, projectsWrapper wrappers.ProjectsWrapper, - resultsWrapper wrappers.ResultsWrapper) *cobra.Command { + resultsWrapper wrappers.ResultsWrapper, + bflWrapper wrappers.BFLWrapper) *cobra.Command { rootCmd := &cobra.Command{ Use: "ast", Short: "A CLI wrapping Checkmarx AST APIs", @@ -81,11 +83,12 @@ func NewAstCLI(scansWrapper wrappers.ScansWrapper, scanCmd := NewScanCommand(scansWrapper, uploadsWrapper) projectCmd := NewProjectCommand(projectsWrapper) resultCmd := NewResultCommand(resultsWrapper) + bflCmd := NewBFLCommand(bflWrapper) versionCmd := NewVersionCommand() clusterCmd := NewClusterCommand() appCmd := NewAppCommand() - rootCmd.AddCommand(scanCmd, projectCmd, resultCmd, versionCmd, clusterCmd, appCmd) + rootCmd.AddCommand(scanCmd, projectCmd, resultCmd, versionCmd, clusterCmd, appCmd, bflCmd) rootCmd.SilenceUsage = true return rootCmd } diff --git a/internal/commands/root_test.go b/internal/commands/root_test.go index 806d00837..7126b7a0f 100644 --- a/internal/commands/root_test.go +++ b/internal/commands/root_test.go @@ -27,7 +27,8 @@ func createASTTestCommand() *cobra.Command { uploadsMockWrapper := &wrappers.UploadsMockWrapper{} projectsMockWrapper := &wrappers.ProjectsMockWrapper{} resultsMockWrapper := &wrappers.ResultsMockWrapper{} - return NewAstCLI(scansMockWrapper, uploadsMockWrapper, projectsMockWrapper, resultsMockWrapper) + bflMockWrapper := &wrappers.BFLMockWrapper{} + return NewAstCLI(scansMockWrapper, uploadsMockWrapper, projectsMockWrapper, resultsMockWrapper, bflMockWrapper) } func TestRootHelp(t *testing.T) { diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 3def2a374..b56130d59 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" wrappers "github.com/checkmarxDev/ast-cli/internal/wrappers" - scansRESTApi "github.com/checkmarxDev/scans/api/v1/rest/scans" + scansRESTApi "github.com/checkmarxDev/scans/pkg/api/scans/v1/rest" "github.com/spf13/cobra" ) @@ -257,10 +257,12 @@ func outputScans(cmd *cobra.Command, allScansModel *scansRESTApi.SlicedScansResp } else if IsPrettyFormat() { for _, scan := range allScansModel.Scans { prettySingleScan(&scansRESTApi.ScanResponseModel{ - ID: scan.ID, - Created: scan.Created, - Updated: scan.Updated, - Tags: scan.Tags, + ID: scan.ID, + Status: scan.Status, + CreatedAt: scan.CreatedAt, + UpdatedAt: scan.UpdatedAt, + ProjectID: scan.ProjectID, + Tags: scan.Tags, }) } } @@ -284,9 +286,11 @@ func outputScan(cmd *cobra.Command, model *scansRESTApi.ScanResponseModel) error return nil } func prettySingleScan(model *scansRESTApi.ScanResponseModel) { - fmt.Println("----------------------------") fmt.Println("Scan ID:", model.ID) - fmt.Println("Created at:", model.Created) - fmt.Println("Updated at:", model.Updated) + fmt.Println("Project ID:", model.ProjectID) + fmt.Println("Status:", model.Status) + fmt.Println("Created at:", model.CreatedAt) + fmt.Println("Updated at:", model.UpdatedAt) fmt.Println("Tags:", model.Tags) + fmt.Println() } diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index c2a56a8b3..c4429440c 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -109,6 +109,12 @@ func TestRunGetAllCommand(t *testing.T) { assert.NilError(t, err) } +func TestRunGetAllCommandPretty(t *testing.T) { + cmd := createASTTestCommand() + err := executeTestCommand(cmd, "-v", "scan", "list", "--format", "pretty") + assert.NilError(t, err) +} + func TestRunGetAllCommandFlagNonExist(t *testing.T) { cmd := createASTTestCommand() err := executeTestCommand(cmd, "-v", "scan", "list", "--chibutero") diff --git a/internal/wrappers/bfl-http.go b/internal/wrappers/bfl-http.go new file mode 100644 index 000000000..fa68a023f --- /dev/null +++ b/internal/wrappers/bfl-http.go @@ -0,0 +1,54 @@ +package wrappers + +import ( + "encoding/json" + "net/http" + + "github.com/pkg/errors" +) + +const ( + failedToParseBFL = "Failed to parse BFL" +) + +type BFLHTTPWrapper struct { + url string +} + +func NewHTTPBFLWrapper(url string) BFLWrapper { + return &BFLHTTPWrapper{ + url: url, + } +} + +func (b *BFLHTTPWrapper) GetByScanID(scanID string, limit, offset uint64) (*BFLResponseModel, *ErrorModel, error) { + params := make(map[string]string) + params["scan-id"] = scanID + resp, err := SendHTTPRequestWithLimitAndOffset(http.MethodGet, b.url, params, limit, offset, nil) + if err != nil { + return nil, nil, err + } + + decoder := json.NewDecoder(resp.Body) + + defer resp.Body.Close() + switch resp.StatusCode { + case http.StatusBadRequest, http.StatusInternalServerError: + errorModel := ErrorModel{} + err = decoder.Decode(&errorModel) + if err != nil { + return nil, nil, errors.Wrapf(err, failedToParseBFL) + } + return nil, &errorModel, nil + case http.StatusOK: + model := BFLResponseModel{} + err = decoder.Decode(&model) + if err != nil { + return nil, nil, errors.Wrapf(err, failedToParseBFL) + } + return &model, nil, nil + + default: + return nil, nil, errors.Errorf("Unknown response status code %d", resp.StatusCode) + } +} diff --git a/internal/wrappers/bfl-mock.go b/internal/wrappers/bfl-mock.go new file mode 100644 index 000000000..f19e837c6 --- /dev/null +++ b/internal/wrappers/bfl-mock.go @@ -0,0 +1,7 @@ +package wrappers + +type BFLMockWrapper struct{} + +func (b *BFLMockWrapper) GetByScanID(scanID string, limit, offset uint64) (*BFLResponseModel, *ErrorModel, error) { + return &BFLResponseModel{}, nil, nil +} diff --git a/internal/wrappers/bfl.go b/internal/wrappers/bfl.go new file mode 100644 index 000000000..3861ff1fd --- /dev/null +++ b/internal/wrappers/bfl.go @@ -0,0 +1,16 @@ +package wrappers + +type BFLWrapper interface { + GetByScanID(scanID string, limit, offset uint64) (*BFLResponseModel, *ErrorModel, error) +} + +type BFLResponseModel struct { + ID string + Trees []BFLTreeModel + TotalCount int +} +type BFLTreeModel struct { + ID string + BFL ResultNode + Results []ResultResponseModel +} diff --git a/internal/wrappers/client.go b/internal/wrappers/client.go index 176090b11..799c1791c 100644 --- a/internal/wrappers/client.go +++ b/internal/wrappers/client.go @@ -7,12 +7,18 @@ import ( "io" "io/ioutil" "net/http" + "os" "strconv" "strings" + "time" "github.com/spf13/viper" ) +const ( + expiryGraceSeconds = 10 +) + type ClientCredentialsInfo struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` @@ -49,18 +55,30 @@ func SendHTTPRequest(method, url string, body io.Reader) (*http.Response, error) return resp, nil } -func SendHTTPRequestWithLimitAndOffset(method, url string, limit, offset uint64, body io.Reader) (*http.Response, error) { +func SendHTTPRequestWithLimitAndOffset(method, url string, params map[string]string, + limit, offset uint64, body io.Reader) (*http.Response, error) { + if params == nil { + params = make(map[string]string) + } + if limit > 0 { + params[limitQueryParam] = strconv.FormatUint(limit, 10) + } + if offset > 0 { + params[offsetQueryParam] = strconv.FormatUint(offset, 10) + } + return SendHTTPRequestWithQueryParams(method, url, params, body) +} + +func SendHTTPRequestWithQueryParams(method, url string, params map[string]string, + body io.Reader) (*http.Response, error) { client := getClient() req, err := http.NewRequest(method, url, body) if err != nil { return nil, err } q := req.URL.Query() - if limit > 0 { - q.Add(limitQueryParam, strconv.FormatUint(limit, 10)) - } - if offset > 0 { - q.Add(offsetQueryParam, strconv.FormatUint(offset, 10)) + for k, v := range params { + q.Add(k, v) } req.URL.RawQuery = q.Encode() req, err = enrichWithCredentials(req) @@ -80,15 +98,35 @@ func enrichWithCredentials(request *http.Request) (*http.Request, error) { accessKeyID := viper.GetString("ast_access_key_id") accessKeySecret := viper.GetString("ast_access_key_secret") - credentialsInfo, err := getClientCredentials(authHost, accessKeyID, accessKeySecret) + accessToken, err := getClientCredentials(authHost, accessKeyID, accessKeySecret) if err != nil { return nil, err } - request.Header.Add("Authorization", credentialsInfo.AccessToken) + request.Header.Add("Authorization", *accessToken) return request, nil } -func getClientCredentials(authServerURI, accessKeyID, accessKeySecret string) (*ClientCredentialsInfo, error) { +func getClientCredentials(authServerURI, accessKeyID, accessKeySecret string) (*string, error) { + // Try to load access token from file, if not expired + credentialsFilePath := viper.GetString("credentials_file_path") + tokenExpirySeconds := viper.GetInt("token_expiry_seconds") + + if info, err := os.Stat(credentialsFilePath); err == nil { + // Credentials file exists. Check for access token validity + modifiedAt := info.ModTime() + expired := time.Since(modifiedAt) > time.Duration(tokenExpirySeconds-expiryGraceSeconds)*time.Second + if !expired { + b, err := ioutil.ReadFile(credentialsFilePath) + if err != nil { + return nil, err + } + accessToken := string(b) + return &accessToken, nil + } + } + + // Here the file can either not exist, exist and failed opening or the token has expired. + // We don't care. Create a new token. payload := strings.NewReader(getCredentialsPayload(accessKeyID, accessKeySecret)) req, err := http.NewRequest(http.MethodPost, authServerURI, payload) if err != nil { @@ -101,12 +139,18 @@ func getClientCredentials(authServerURI, accessKeyID, accessKeySecret string) (* } defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) - info := ClientCredentialsInfo{} - err = json.Unmarshal(body, &info) + credentialsInfo := ClientCredentialsInfo{} + err = json.Unmarshal(body, &credentialsInfo) if err != nil { return nil, err } - return &info, nil + + // We have a new access token. Save it to file + accessToken := credentialsInfo.AccessToken + accessTokenData := []byte(accessToken) + _ = ioutil.WriteFile(credentialsFilePath, accessTokenData, 0644) + + return &accessToken, nil } func getCredentialsPayload(accessKeyID, accessKeySecret string) string { diff --git a/internal/wrappers/projects-http.go b/internal/wrappers/projects-http.go index b2ec116cf..dc0b4736b 100644 --- a/internal/wrappers/projects-http.go +++ b/internal/wrappers/projects-http.go @@ -7,7 +7,7 @@ import ( "github.com/pkg/errors" - projectsRESTApi "github.com/checkmarxDev/scans/api/v1/rest/projects" + projectsRESTApi "github.com/checkmarxDev/scans/pkg/api/projects/v1/rest" ) const ( @@ -43,7 +43,7 @@ func (p *ProjectsHTTPWrapper) Create(model *projectsRESTApi.Project) ( func (p *ProjectsHTTPWrapper) Get(limit, offset uint64) ( *projectsRESTApi.SlicedProjectsResponseModel, *projectsRESTApi.ErrorModel, error) { - resp, err := SendHTTPRequestWithLimitAndOffset(http.MethodGet, p.url, limit, offset, nil) + resp, err := SendHTTPRequestWithLimitAndOffset(http.MethodGet, p.url, nil, limit, offset, nil) if err != nil { return nil, nil, err } diff --git a/internal/wrappers/projects-mock.go b/internal/wrappers/projects-mock.go index 60d3d91d0..1823db73c 100644 --- a/internal/wrappers/projects-mock.go +++ b/internal/wrappers/projects-mock.go @@ -3,7 +3,7 @@ package wrappers import ( "fmt" - projectsRESTApi "github.com/checkmarxDev/scans/api/v1/rest/projects" + projectsRESTApi "github.com/checkmarxDev/scans/pkg/api/projects/v1/rest" ) type ProjectsMockWrapper struct{} diff --git a/internal/wrappers/projects.go b/internal/wrappers/projects.go index 0ee2cc9d7..fb857943b 100644 --- a/internal/wrappers/projects.go +++ b/internal/wrappers/projects.go @@ -1,7 +1,7 @@ package wrappers import ( - projectsRESTApi "github.com/checkmarxDev/scans/api/v1/rest/projects" + projectsRESTApi "github.com/checkmarxDev/scans/pkg/api/projects/v1/rest" ) type ProjectsWrapper interface { diff --git a/internal/wrappers/response.go b/internal/wrappers/response.go index 6cab6f180..1eef1ccc3 100644 --- a/internal/wrappers/response.go +++ b/internal/wrappers/response.go @@ -4,8 +4,8 @@ import ( "encoding/json" "net/http" - projectsApi "github.com/checkmarxDev/scans/api/v1/rest/projects" - scansApi "github.com/checkmarxDev/scans/api/v1/rest/scans" + projectsApi "github.com/checkmarxDev/scans/pkg/api/projects/v1/rest" + scansApi "github.com/checkmarxDev/scans/pkg/api/scans/v1/rest" "github.com/pkg/errors" ) diff --git a/internal/wrappers/results-http.go b/internal/wrappers/results-http.go index a2631d890..67c238072 100644 --- a/internal/wrappers/results-http.go +++ b/internal/wrappers/results-http.go @@ -2,7 +2,6 @@ package wrappers import ( "encoding/json" - "fmt" "net/http" "github.com/pkg/errors" @@ -22,12 +21,10 @@ func NewHTTPResultsWrapper(url string) ResultsWrapper { } } -func (r *ResultsHTTPWrapper) GetByScanID( - scanID string, - limit, - offset uint64) ([]ResultResponseModel, *ResultError, error) { - resp, err := SendHTTPRequestWithLimitAndOffset(http.MethodGet, - fmt.Sprintf("%s/%s/items", r.url, scanID), limit, offset, nil) +func (r *ResultsHTTPWrapper) GetByScanID(scanID string, limit, offset uint64) (*ResultsResponseModel, *ErrorModel, error) { + params := make(map[string]string) + params["scan-id"] = scanID + resp, err := SendHTTPRequestWithLimitAndOffset(http.MethodGet, r.url, params, limit, offset, nil) if err != nil { return nil, nil, err } @@ -37,19 +34,19 @@ func (r *ResultsHTTPWrapper) GetByScanID( defer resp.Body.Close() switch resp.StatusCode { case http.StatusBadRequest, http.StatusInternalServerError: - errorModel := ResultError{} + errorModel := ErrorModel{} err = decoder.Decode(&errorModel) if err != nil { return nil, nil, errors.Wrapf(err, failedToParseGetResults) } return nil, &errorModel, nil case http.StatusOK: - model := []ResultResponseModel{} + model := ResultsResponseModel{} err = decoder.Decode(&model) if err != nil { return nil, nil, errors.Wrapf(err, failedToParseGetResults) } - return model, nil, nil + return &model, nil, nil default: return nil, nil, errors.Errorf("Unknown response status code %d", resp.StatusCode) diff --git a/internal/wrappers/results-mock.go b/internal/wrappers/results-mock.go index 3eb59c384..6b26b8fb7 100644 --- a/internal/wrappers/results-mock.go +++ b/internal/wrappers/results-mock.go @@ -2,7 +2,22 @@ package wrappers type ResultsMockWrapper struct{} -func (r ResultsMockWrapper) GetByScanID(scanID string, - limit, offset uint64) ([]ResultResponseModel, *ResultError, error) { - return []ResultResponseModel{}, nil, nil +func (r ResultsMockWrapper) GetByScanID(scanID string, limit, offset uint64) (*ResultsResponseModel, *ErrorModel, error) { + return &ResultsResponseModel{ + Results: []ResultResponseModel{ + { + QueryID: 0, + QueryName: scanID, + Severity: scanID, + PathSystemID: scanID, + PathSystemIDBySimiAndFilesPaths: scanID, + ID: scanID, + FirstScanID: scanID, + FirstFoundAt: scanID, + FoundAt: scanID, + Status: scanID, + }, + }, + TotalCount: 1, + }, nil, nil } diff --git a/internal/wrappers/results.go b/internal/wrappers/results.go index 0d5b4fcbd..f98010d58 100644 --- a/internal/wrappers/results.go +++ b/internal/wrappers/results.go @@ -1,77 +1,54 @@ package wrappers type ResultsWrapper interface { - GetByScanID(scanID string, limit, offset uint64) ([]ResultResponseModel, *ResultError, error) + GetByScanID(scanID string, limit, offset uint64) (*ResultsResponseModel, *ErrorModel, error) } -type ResultError struct { +type ErrorModel struct { Code int32 `json:"code,omitempty"` Message string `json:"message,omitempty"` Data interface{} `json:"data,omitempty"` } -type ResultNode struct { - // Column position of the node - Column int32 `json:"column,omitempty"` - // Full file name of the containing source file - FileName string `json:"fileName,omitempty"` - // FQN of the node - FullName string `json:"fullName,omitempty"` - // Length of the node - Length int32 `json:"length,omitempty"` - // Line position of the node - Line int32 `json:"line,omitempty"` - // Line position of the containing method - MethodLine int32 `json:"methodLine,omitempty"` - // node name - Name string `json:"name,omitempty"` - // ID of node - NodeID int32 `json:"nodeID,omitempty"` - // node DomType - DomType string `json:"domType,omitempty"` - // ID of the customer tenant - NodeSystemID string `json:"nodeSystemID,omitempty"` -} - +// Result is based on results.ResultRow type ResultResponseModel struct { - // Query ID - QueryID string `json:"queryID,omitempty"` - // Query name + // query + QueryID int64 `json:"queryID,omitempty"` QueryName string `json:"queryName,omitempty"` - // Query group; sperate by ':' - GroupName string `json:"groupName,omitempty"` - // Severity of result - Severity string `json:"severity,omitempty"` - // Common Weakness Enumeration ID - CweID string `json:"cweID,omitempty"` - // ID of the path. changes from scan to scan. - PathID int32 `json:"pathID,omitempty"` - // ID of the Similarity feature (Indicator to identify a result by its first and last nodes) - SimilarityID string `json:"similarityID,omitempty"` - // Same as similarityID but can change in the future (SAST feature) - UniqueID string `json:"uniqueID,omitempty"` - // Confidence Level of the exsitin of the result - ConfidenceLevel int32 `json:"confidenceLevel,omitempty"` - - Nodes []ResultNode `json:"nodes,omitempty"` - // ID of the customer tenant - TenantID string `json:"tenantID,omitempty"` - // ID of the scan - ScanID string `json:"scanID,omitempty"` - // Creation date of the result - CreatedAt string `json:"createdAt,omitempty"` - - Classification int32 `json:"classification,omitempty"` - // Groups arrays + Severity string `json:"severity,omitempty"` + CweID int64 `json:"cweID,omitempty"` + // path + SimilarityID int64 `json:"similarityID,omitempty"` + UniqueID int64 `json:"uniqueID,omitempty"` + Nodes []*ResultNode `json:"nodes,omitempty"` + ConfidenceLevel float32 `json:"confidenceLevel,omitempty"` + // query Groups []string `json:"groups,omitempty"` - // ID of the customer tenant - PathSystemID string `json:"pathSystemID,omitempty"` - // ID created from queryMetaInfo + similarityID + files name + // path + PathSystemID string `json:"pathSystemID,omitempty"` PathSystemIDBySimiAndFilesPaths string `json:"pathSystemIDBySimiAndFilesPaths,omitempty"` - // enum of the current state(new,old,fixed) - Status int32 `json:"status,omitempty"` - // TBD - MetadataJSON string `json:"metadataJSON,omitempty"` - // TBD - ExtraJSON string `json:"extraJSON,omitempty"` + + ID string `json:"id,omitempty"` + FirstScanID string `json:"firstScanID,omitempty"` + FirstFoundAt string `json:"firstFoundAt,omitempty"` + FoundAt string `json:"foundAt,omitempty"` + Status string `json:"status,omitempty"` +} + +type ResultNode struct { + Column int32 `json:"column,omitempty"` + FileName string `json:"fileName,omitempty"` + FullName string `json:"fullName,omitempty"` + Length int32 `json:"length,omitempty"` + Line int32 `json:"line,omitempty"` + MethodLine int32 `json:"methodLine,omitempty"` + Name string `json:"name,omitempty"` + NodeID int32 `json:"-"` + DomType string `json:"domType,omitempty"` + NodeSystemID string `json:"nodeSystemID,omitempty"` +} + +type ResultsResponseModel struct { + Results []ResultResponseModel + TotalCount int } diff --git a/internal/wrappers/scans-http.go b/internal/wrappers/scans-http.go index 29f49c025..a20ee208c 100644 --- a/internal/wrappers/scans-http.go +++ b/internal/wrappers/scans-http.go @@ -5,7 +5,7 @@ import ( "encoding/json" "net/http" - scansApi "github.com/checkmarxDev/scans/api/v1/rest/scans" + scansApi "github.com/checkmarxDev/scans/pkg/api/scans/v1/rest" "github.com/pkg/errors" ) @@ -42,7 +42,7 @@ func (s *ScansHTTPWrapper) Create(model *scansApi.Scan) (*scansApi.ScanResponseM } func (s *ScansHTTPWrapper) Get(limit, offset uint64) (*scansApi.SlicedScansResponseModel, *scansApi.ErrorModel, error) { - resp, err := SendHTTPRequestWithLimitAndOffset(http.MethodGet, s.url, limit, offset, nil) + resp, err := SendHTTPRequestWithLimitAndOffset(http.MethodGet, s.url, nil, limit, offset, nil) if err != nil { return nil, nil, err } diff --git a/internal/wrappers/scans-mock.go b/internal/wrappers/scans-mock.go index 900495e77..b53e475a4 100644 --- a/internal/wrappers/scans-mock.go +++ b/internal/wrappers/scans-mock.go @@ -3,7 +3,7 @@ package wrappers import ( "fmt" - scansRESTApi "github.com/checkmarxDev/scans/api/v1/rest/scans" + scansRESTApi "github.com/checkmarxDev/scans/pkg/api/scans/v1/rest" ) type ScansMockWrapper struct { diff --git a/internal/wrappers/scans.go b/internal/wrappers/scans.go index bcf89fbea..f50777b62 100644 --- a/internal/wrappers/scans.go +++ b/internal/wrappers/scans.go @@ -1,7 +1,7 @@ package wrappers import ( - scansRESTApi "github.com/checkmarxDev/scans/api/v1/rest/scans" + scansRESTApi "github.com/checkmarxDev/scans/pkg/api/scans/v1/rest" ) type ScansWrapper interface { diff --git a/test/integration/project_test.go b/test/integration/project_test.go index 551a520b2..cb903c9e4 100644 --- a/test/integration/project_test.go +++ b/test/integration/project_test.go @@ -11,7 +11,7 @@ import ( "strconv" "testing" - projectsRESTApi "github.com/checkmarxDev/scans/api/v1/rest/projects" + projectsRESTApi "github.com/checkmarxDev/scans/pkg/api/projects/v1/rest" "gotest.tools/assert" ) @@ -109,8 +109,6 @@ func getAllProjects(t *testing.T, projectID string) { allProjects := projectsRESTApi.SlicedProjectsResponseModel{} err = json.Unmarshal(getAllJSON, &allProjects) assert.NilError(t, err, "Parsing all projects response JSON should pass") - assert.Assert(t, uint64(allProjects.Limit) == limit, fmt.Sprintf("limit should be %d", limit)) - assert.Assert(t, uint64(allProjects.Offset) == offset, fmt.Sprintf("offset should be %d", offset)) assert.Assert(t, allProjects.TotalCount == 1, "Total should be 1") assert.Assert(t, len(allProjects.Projects) == 1, "Total should be 1") assert.Assert(t, allProjects.Projects[0].ID == projectID) diff --git a/test/integration/result_test.go b/test/integration/result_test.go index 3a12389e7..d4612294a 100644 --- a/test/integration/result_test.go +++ b/test/integration/result_test.go @@ -6,6 +6,7 @@ import ( "bytes" "encoding/json" "io/ioutil" + "log" "strconv" "testing" @@ -21,14 +22,15 @@ func getResultsNumberForScan(t *testing.T, scanID string) int { var offset uint64 = 0 l := strconv.FormatUint(limit, 10) o := strconv.FormatUint(offset, 10) + log.Println("LIMIT IS ", l) err := execute(getResultsCmd, "-v", "result", "list", scanID, "--limit", l, "--offset", o) assert.NilError(t, err, "Getting all results should pass") // Read response from buffer var getAllJSON []byte getAllJSON, err = ioutil.ReadAll(b) assert.NilError(t, err, "Reading all results response JSON should pass") - allResults := []wrappers.ResultResponseModel{} - err = json.Unmarshal(getAllJSON, &allResults) + resultsReponseModel := wrappers.ResultsResponseModel{} + err = json.Unmarshal(getAllJSON, &resultsReponseModel) assert.NilError(t, err, "Parsing all results response JSON should pass") - return len(allResults) + return resultsReponseModel.TotalCount } diff --git a/test/integration/root_test.go b/test/integration/root_test.go index 490df1608..6a56f4de3 100644 --- a/test/integration/root_test.go +++ b/test/integration/root_test.go @@ -18,14 +18,17 @@ import ( ) const ( - astURIEnv = "AST_URI" - scansPathEnv = "SCANS_PATH" - projectsPathEnv = "PROJECTS_PATH" - resultsPathEnv = "RESULTS_PATH" - uploadsPathEnv = "UPLOADS_PATH" - letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - successfulExitCode = 0 - failureExitCode = 1 + astURIEnv = "AST_URI" + scansPathEnv = "SCANS_PATH" + projectsPathEnv = "PROJECTS_PATH" + resultsPathEnv = "RESULTS_PATH" + uploadsPathEnv = "UPLOADS_PATH" + bflPathEnv = "BFL_PATH" + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + credentialsFilePathEnv = "CREDENTIALS_FILE_PATH" + tokenExpirySecondsEnv = "TOKEN_EXPIRY_SECONDS" + successfulExitCode = 0 + failureExitCode = 1 ) func bindKeyToEnvAndDefault(key, env, defaultVal string) error { @@ -77,6 +80,11 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { assert.NilError(t, err) uploads := viper.GetString(uploadsPathKey) + bflPathKey := strings.ToLower(bflPathEnv) + err = bindKeyToEnvAndDefault(bflPathKey, bflPathEnv, "api/bfl") + assert.NilError(t, err) + bfl := viper.GetString(bflPathKey) + err = bindKeyToEnvAndDefault(commands.AccessKeyIDConfigKey, commands.AccessKeyIDEnv, "") assert.NilError(t, err) err = bindKeyToEnvAndDefault(commands.AccessKeySecretConfigKey, commands.AccessKeySecretEnv, "") @@ -84,17 +92,27 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { err = bindKeyToEnvAndDefault(commands.AstAuthenticationURIConfigKey, commands.AstAuthenticationURIEnv, "") assert.NilError(t, err) + credentialsFilePathKey := strings.ToLower(credentialsFilePathEnv) + err = bindKeyToEnvAndDefault(credentialsFilePathKey, credentialsFilePathEnv, "credentials.ast") + assert.NilError(t, err) + + tokenExpirySecondsKey := strings.ToLower(tokenExpirySecondsEnv) + err = bindKeyToEnvAndDefault(tokenExpirySecondsKey, tokenExpirySecondsEnv, "300") + assert.NilError(t, err) + scansURL := fmt.Sprintf("%s/%s", ast, scans) uploadsURL := fmt.Sprintf("%s/%s", ast, uploads) projectsURL := fmt.Sprintf("%s/%s", ast, projects) resultsURL := fmt.Sprintf("%s/%s", ast, results) + bflURL := fmt.Sprintf("%s/%s", ast, bfl) scansWrapper := wrappers.NewHTTPScansWrapper(scansURL) uploadsWrapper := wrappers.NewUploadsHTTPWrapper(uploadsURL) projectsWrapper := wrappers.NewHTTPProjectsWrapper(projectsURL) resultsWrapper := wrappers.NewHTTPResultsWrapper(resultsURL) + bflWrapper := wrappers.NewHTTPBFLWrapper(bflURL) - astCli := commands.NewAstCLI(scansWrapper, uploadsWrapper, projectsWrapper, resultsWrapper) + astCli := commands.NewAstCLI(scansWrapper, uploadsWrapper, projectsWrapper, resultsWrapper, bflWrapper) return astCli } diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index 414731e13..d2ea52302 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -6,20 +6,24 @@ import ( "bytes" "context" "encoding/json" - "fmt" "io/ioutil" "log" "strconv" "testing" "time" - scansRESTApi "github.com/checkmarxDev/scans/api/v1/rest/scans" + scansRESTApi "github.com/checkmarxDev/scans/pkg/api/scans/v1/rest" "gotest.tools/assert/cmp" "github.com/spf13/viper" "gotest.tools/assert" ) +const ( + scanResultsNum = 575 + incScanResultsNum = 572 +) + func TestScansE2E(t *testing.T) { viper.SetDefault("TEST_FULL_SCAN_WAIT_COMPLETED_SECONDS", "120") fullScanWaitTime := viper.GetInt("TEST_FULL_SCAN_WAIT_COMPLETED_SECONDS") @@ -36,6 +40,8 @@ func TestScansE2E(t *testing.T) { // Validate the results for full scan scanResults := getResultsNumberForScan(t, scanID) + log.Println("SCAN RESULTS IS ", scanResults) + assert.Assert(t, scanResults == scanResultsNum, "Wrong number of scan results") incScanID := createIncScan(t) log.Printf("Waiting %d seconds for the incremental scan to complete...\n", incScanWaitTime) // Wait for the inc scan to finish. See it's completed successfully @@ -46,7 +52,8 @@ func TestScansE2E(t *testing.T) { // Validate the results for inc scan incScanResults := getResultsNumberForScan(t, incScanID) - assert.Assert(t, incScanResults < scanResults, "Wrong number of inc scan results") + log.Println("INC SCAN RESULTS IS ", incScanResults) + assert.Assert(t, incScanResults == incScanResultsNum, "Wrong number of inc scan results") listScansPretty(t) listScans(t) @@ -93,10 +100,6 @@ func listScans(t *testing.T) { allScans := scansRESTApi.SlicedScansResponseModel{} err = json.Unmarshal(getAllJSON, &allScans) assert.NilError(t, err, "Parsing all scans response JSON should pass") - assert.Assert(t, uint64(allScans.Limit) == limit, fmt.Sprintf("limit should be %d", limit)) - assert.Assert(t, uint64(allScans.Offset) == offset, fmt.Sprintf("offset should be %d", offset)) - assert.Assert(t, allScans.TotalCount == 2, "Total should be 2") - assert.Assert(t, len(allScans.Scans) == 2, "Total should be 2") } func listScansPretty(t *testing.T) {