Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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*
36 changes: 24 additions & 12 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
106 changes: 106 additions & 0 deletions internal/commands/bfl.go
Original file line number Diff line number Diff line change
@@ -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)
}
16 changes: 8 additions & 8 deletions internal/commands/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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,
})
}
}
Expand All @@ -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)
}
8 changes: 8 additions & 0 deletions internal/commands/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
66 changes: 58 additions & 8 deletions internal/commands/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
}
}
6 changes: 6 additions & 0 deletions internal/commands/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Loading