Skip to content
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func main() {
accessManagementPath := viper.GetString(params.AccessManagementPathKey)
byorPath := viper.GetString(params.ByorPathKey)

customStatesWrapper := wrappers.NewCustomStatesHTTPWrapper()
scansWrapper := wrappers.NewHTTPScansWrapper(scans)
resultsPdfReportsWrapper := wrappers.NewResultsPdfReportsHTTPWrapper(resultsPdfPath)
exportWrapper := wrappers.NewExportHTTPWrapper(exportPath)
Expand Down Expand Up @@ -94,6 +95,7 @@ func main() {
exportWrapper,
resultsPdfReportsWrapper,
resultsPredicatesWrapper,
customStatesWrapper,
codeBashingWrapper,
uploadsWrapper,
projectsWrapper,
Expand Down
39 changes: 37 additions & 2 deletions internal/commands/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,59 @@ import (
"github.com/spf13/cobra"
)

func NewResultsPredicatesCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
func NewResultsPredicatesCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper, customStatesWrapper wrappers.CustomStatesWrapper ) *cobra.Command {
triageCmd := &cobra.Command{
Use: "triage",
Short: "Manage results",
Long: "The 'triage' command enables the ability to manage results in Checkmarx One.",
}
triageShowCmd := triageShowSubCommand(resultsPredicatesWrapper)
triageUpdateCmd := triageUpdateSubCommand(resultsPredicatesWrapper, featureFlagsWrapper)
triageGetStatesCmd := triageGetStatesSubCommand(customStatesWrapper)


addFormatFlagToMultipleCommands(
[]*cobra.Command{triageShowCmd},
printer.FormatList, printer.FormatTable, printer.FormatJSON,
)

triageCmd.AddCommand(triageShowCmd, triageUpdateCmd)
triageCmd.AddCommand(triageShowCmd, triageUpdateCmd, triageGetStatesCmd)
return triageCmd
}

func triageGetStatesSubCommand(customStatesWrapper wrappers.CustomStatesWrapper) *cobra.Command {
triageGetStatesCmd := &cobra.Command{
Use: "get-states",
Short: "Fetch and display custom states.",
Long: "Retrieves a list of custom states and prints their names.",
Example: heredoc.Doc(
`
$ cx triage get-states
$ cx triage get-states --all
`,
),
RunE: runTriageGetStates(customStatesWrapper),
}

triageGetStatesCmd.PersistentFlags().Bool(params.AllStatesFlag, false, "Include deleted states")

return triageGetStatesCmd
}

func runTriageGetStates(customStatesWrapper wrappers.CustomStatesWrapper) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, _ []string) error {
includeDeleted, _ := cmd.Flags().GetBool(params.AllStatesFlag)
states, err := customStatesWrapper.GetAllCustomStates(includeDeleted)
if err != nil {
return errors.Wrap(err, "Failed to fetch custom states")
}
err = printer.Print(cmd.OutOrStdout(), states, printer.FormatJSON)
return err
}
}



func triageShowSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) *cobra.Command {
triageShowCmd := &cobra.Command{
Use: "show",
Expand Down
18 changes: 18 additions & 0 deletions internal/commands/predicates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package commands

import (
"fmt"
"github.com/checkmarx/ast-cli/internal/wrappers/mock"
"testing"

"gotest.tools/assert"
Expand Down Expand Up @@ -48,3 +49,20 @@ func TestRunUpdateTriageCommandWithNoInput(t *testing.T) {
t,
err.Error() == "required flag(s) \"project-id\", \"scan-type\", \"severity\", \"similarity-id\", \"state\" not set")
}

func TestTriageGetStatesFlag(t *testing.T) {
mockWrapper := &mock.CustomStatesMockWrapper{}
cmd := triageGetStatesSubCommand(mockWrapper)
cmd.SetArgs([]string{})
err := cmd.Execute()
assert.NilError(t, err)
states, err := mockWrapper.GetAllCustomStates(false)
assert.NilError(t, err)
assert.Equal(t, len(states), 2)
cmd.SetArgs([]string{"--all"})
err = cmd.Execute()
assert.NilError(t, err)
states, err = mockWrapper.GetAllCustomStates(true)
assert.NilError(t, err)
assert.Equal(t, len(states), 3)
}
3 changes: 2 additions & 1 deletion internal/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func NewAstCLI(
exportWrapper wrappers.ExportWrapper,
resultsPdfReportsWrapper wrappers.ResultsPdfWrapper,
resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper,
customStatesWrapper wrappers.CustomStatesWrapper,
codeBashingWrapper wrappers.CodeBashingWrapper,
uploadsWrapper wrappers.UploadsWrapper,
projectsWrapper wrappers.ProjectsWrapper,
Expand Down Expand Up @@ -195,7 +196,7 @@ func NewAstCLI(
)

configCmd := util.NewConfigCommand()
triageCmd := NewResultsPredicatesCommand(resultsPredicatesWrapper, featureFlagsWrapper)
triageCmd := NewResultsPredicatesCommand(resultsPredicatesWrapper, featureFlagsWrapper, customStatesWrapper)

chatCmd := NewChatCommand(chatWrapper, tenantWrapper)

Expand Down
3 changes: 2 additions & 1 deletion internal/commands/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ func createASTTestCommand() *cobra.Command {
accessManagementWrapper := &mock.AccessManagementMockWrapper{}
byorWrapper := &mock.ByorMockWrapper{}
containerResolverMockWrapper := &mock.ContainerResolverMockWrapper{}

customStatesMockWrapper := &mock.CustomStatesMockWrapper{}
return NewAstCLI(
applicationWrapper,
scansMockWrapper,
exportWrapper,
resultsPdfWrapper,
resultsPredicatesMockWrapper,
customStatesMockWrapper,
codeBashingWrapper,
uploadsMockWrapper,
projectsMockWrapper,
Expand Down
1 change: 1 addition & 0 deletions internal/params/binds.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var EnvVarsBinds = []struct {
{IgnoreProxyKey, IgnoreProxyEnv, ""},
{AgentNameKey, AgentNameEnv, "ASTCLI"},
{CodeBashingPathKey, ScansPathEnv, "api/codebashing/lessons"},
{CustomStatesAPIPathKey, CustomStatesAPIPathEnv, "api/custom-states"},
{ScansPathKey, ScansPathEnv, "api/scans"},
{ProjectsPathKey, ProjectsPathEnv, "api/projects"},
{ApplicationsPathKey, ApplicationsPathEnv, "api/applications"},
Expand Down
1 change: 1 addition & 0 deletions internal/params/envs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package params

const (
CustomStatesAPIPathEnv = "CX_CUSTOM_STATES_PATH"
TenantEnv = "CX_TENANT"
BranchEnv = "CX_BRANCH"
BaseURIEnv = "CX_BASE_URI"
Expand Down
5 changes: 5 additions & 0 deletions internal/params/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package params

// Flags
const (
AllStatesFlag = "all"
AgentFlag = "agent"
AgentFlagUsage = "Scan origin name"
ApplicationName = "application-name"
Expand Down Expand Up @@ -281,3 +282,7 @@ const ScaAgent = "SCA_AGENT"
var (
Version = "dev"
)

// Custom states
const IncludeDeletedQueryParam = "include-deleted"
const True = "true"
1 change: 1 addition & 0 deletions internal/params/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package params
import "strings"

var (
CustomStatesAPIPathKey = strings.ToLower(CustomStatesAPIPathEnv)
TenantKey = strings.ToLower(TenantEnv)
BranchKey = strings.ToLower(BranchEnv)
BaseURIKey = strings.ToLower(BaseURIEnv)
Expand Down
19 changes: 19 additions & 0 deletions internal/wrappers/mock/custom-states-mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package mock

import "github.com/checkmarx/ast-cli/internal/wrappers"

type CustomStatesMockWrapper struct{}

func (m *CustomStatesMockWrapper) GetAllCustomStates(includeDeleted bool) ([]wrappers.CustomState, error) {
if includeDeleted {
return []wrappers.CustomState{
{ID: 1, Name: "demo1", Type: "Custom"},
{ID: 2, Name: "demo2", Type: "System"},
{ID: 3, Name: "demo3", Type: "Custom"},
}, nil
}
return []wrappers.CustomState{
{ID: 2, Name: "demo2", Type: "System"},
{ID: 3, Name: "demo3", Type: "Custom"},
}, nil
}
39 changes: 39 additions & 0 deletions internal/wrappers/predicates-http.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,42 @@ func handleResponseWithBody(resp *http.Response, err error) (*PredicatesCollecti
func responsePredicateParsingFailed(err error) (*PredicatesCollectionResponseModel, *WebError, error) {
return nil, nil, errors.Wrapf(err, failedToParsePredicates)
}


type CustomStatesHTTPWrapper struct {
path string
}

func NewCustomStatesHTTPWrapper() CustomStatesWrapper {
return &CustomStatesHTTPWrapper{
path: viper.GetString(params.CustomStatesAPIPathKey),
}
}

func (c *CustomStatesHTTPWrapper) GetAllCustomStates(includeDeleted bool) ([]CustomState, error) {
clientTimeout := viper.GetUint(params.ClientTimeoutKey)

if c.path == "" {
return nil, errors.New("CustomStatesAPIPathKey is not set")
}
queryParams := make(map[string]string)
if includeDeleted {
queryParams[params.IncludeDeletedQueryParam] = params.True
}

logger.PrintIfVerbose(fmt.Sprintf("Fetching custom states from: %s with params: %v", c.path, queryParams))
resp, err := SendHTTPRequestWithQueryParams(http.MethodGet, c.path, queryParams, http.NoBody, clientTimeout)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.Errorf("Failed to fetch custom states. HTTP status: %d", resp.StatusCode)
}
var states []CustomState
err = json.NewDecoder(resp.Body).Decode(&states)
if err != nil {
return nil, errors.Wrap(err, "Failed to parse custom states response")
}
return states, nil
}
13 changes: 13 additions & 0 deletions internal/wrappers/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ type PredicatesCollectionResponseModel struct {
TotalCount int `json:"totalCount"`
}

type CustomState struct {
ID int `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
}



type CustomStatesWrapper interface {
GetAllCustomStates(includeDeleted bool) ([]CustomState, error)
}


type ResultsPredicatesWrapper interface {
PredicateSeverityAndState(predicate *PredicateRequest, scanType string) (*WebError, error)
GetAllPredicatesForSimilarityID(
Expand Down
2 changes: 2 additions & 0 deletions test/integration/util_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command {
applicationsWrapper := wrappers.NewApplicationsHTTPWrapper(applications)
resultsPdfReportsWrapper := wrappers.NewResultsPdfReportsHTTPWrapper(resultsPdfPath)
exportWrapper := wrappers.NewExportHTTPWrapper(exportPath)
customStatesWrapper := wrappers.NewCustomStatesHTTPWrapper()

resultsPredicatesWrapper := wrappers.NewResultsPredicatesHTTPWrapper()
groupsWrapper := wrappers.NewHTTPGroupsWrapper(groups)
Expand Down Expand Up @@ -125,6 +126,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command {
exportWrapper,
resultsPdfReportsWrapper,
resultsPredicatesWrapper,
customStatesWrapper,
codeBashingWrapper,
uploadsWrapper,
projectsWrapper,
Expand Down
Loading