11package commands
22
33import (
4- "strings"
5- "time"
6-
74 "github.com/MakeNowJust/heredoc"
85 "github.com/checkmarx/ast-cli/internal/commands/util/printer"
96 "github.com/checkmarx/ast-cli/internal/params"
107 "github.com/checkmarx/ast-cli/internal/wrappers"
118 "github.com/pkg/errors"
129 "github.com/spf13/cobra"
10+ "strings"
11+ "time"
1312)
1413
15- var constantsStates = []wrappers.CustomState {
16- {ID : - 1 , Name : "To Verify" , Type : "" },
17- {ID : - 1 , Name : "Not Exploitable" , Type : "" },
18- {ID : - 1 , Name : "Proposed Not Exploitable" , Type : "" },
19- {ID : - 1 , Name : "Confirmed" , Type : "" },
20- {ID : - 1 , Name : "Urgent" , Type : "" },
14+ var systemStates = []wrappers.CustomState {
15+ {ID : - 1 , Name : params . ToVerify , Type : "" },
16+ {ID : - 1 , Name : params . NotExploitable , Type : "" },
17+ {ID : - 1 , Name : params . ProposedNotExploitable , Type : "" },
18+ {ID : - 1 , Name : params . CONFIRMED , Type : "" },
19+ {ID : - 1 , Name : params . URGENT , Type : "" },
2120}
2221
23- func NewResultsPredicatesCommand (resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper , featureFlagsWrapper wrappers.FeatureFlagsWrapper , customStatesWrapper wrappers.CustomStatesWrapper ) * cobra.Command {
22+ func NewResultsPredicatesCommand (resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper , featureFlagsWrapper wrappers.FeatureFlagsWrapper , customStatesWrapper wrappers.CustomStatesWrapper ) * cobra.Command {
2423 triageCmd := & cobra.Command {
2524 Use : "triage" ,
2625 Short : "Manage results" ,
2726 Long : "The 'triage' command enables the ability to manage results in Checkmarx One." ,
2827 }
2928 triageShowCmd := triageShowSubCommand (resultsPredicatesWrapper )
30- triageUpdateCmd := triageUpdateSubCommand (resultsPredicatesWrapper , featureFlagsWrapper )
29+ triageUpdateCmd := triageUpdateSubCommand (resultsPredicatesWrapper , featureFlagsWrapper , customStatesWrapper )
3130 triageGetStatesCmd := triageGetStatesSubCommand (customStatesWrapper , featureFlagsWrapper )
3231
33-
3432 addFormatFlagToMultipleCommands (
3533 []* cobra.Command {triageShowCmd },
3634 printer .FormatList , printer .FormatTable , printer .FormatJSON ,
@@ -44,7 +42,7 @@ func triageGetStatesSubCommand(customStatesWrapper wrappers.CustomStatesWrapper,
4442 triageGetStatesCmd := & cobra.Command {
4543 Use : "get-states" ,
4644 Short : "Show the custom states that have been configured in your tenant" ,
47- Long : "The get-states command shows information about each of the custom states that have been configured in your tenant account" ,
45+ Long : "The get-states command shows information about each of the custom states that have been configured in your tenant account" ,
4846 Example : heredoc .Doc (
4947 `
5048 $ cx triage get-states
@@ -63,21 +61,19 @@ func runTriageGetStates(customStatesWrapper wrappers.CustomStatesWrapper, featur
6361 return func (cmd * cobra.Command , _ []string ) error {
6462 flagResponse , _ := wrappers .GetSpecificFeatureFlag (featureFlagsWrapper , wrappers .CustomStatesFeatureFlag )
6563 if ! flagResponse .Status {
66- return printer .Print (cmd .OutOrStdout (), constantsStates , printer .FormatJSON )
64+ return printer .Print (cmd .OutOrStdout (), systemStates , printer .FormatJSON )
6765 }
6866 includeDeleted , _ := cmd .Flags ().GetBool (params .AllStatesFlag )
6967 states , err := customStatesWrapper .GetAllCustomStates (includeDeleted )
7068 if err != nil {
7169 return errors .Wrap (err , "Failed to fetch custom states" )
7270 }
73- states = append (states , constantsStates ... )
71+ states = append (states , systemStates ... )
7472 err = printer .Print (cmd .OutOrStdout (), states , printer .FormatJSON )
7573 return err
7674 }
7775}
7876
79-
80-
8177func triageShowSubCommand (resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper ) * cobra.Command {
8278 triageShowCmd := & cobra.Command {
8379 Use : "show" ,
@@ -103,7 +99,7 @@ func triageShowSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWra
10399 return triageShowCmd
104100}
105101
106- func triageUpdateSubCommand (resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper , featureFlagsWrapper wrappers.FeatureFlagsWrapper ) * cobra.Command {
102+ func triageUpdateSubCommand (resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper , featureFlagsWrapper wrappers.FeatureFlagsWrapper , customStatesWrapper wrappers. CustomStatesWrapper ) * cobra.Command {
107103 triageUpdateCmd := & cobra.Command {
108104 Use : "update" ,
109105 Short : "Update the state, severity or comment for the given issue" ,
@@ -113,26 +109,27 @@ func triageUpdateSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesW
113109 $ cx triage update
114110 --similarity-id <SimilarityID>
115111 --project-id <ProjectID>
116- --state <TO_VERIFY|NOT_EXPLOITABLE|PROPOSED_NOT_EXPLOITABLE|CONFIRMED|URGENT>
112+ --state <TO_VERIFY|NOT_EXPLOITABLE|PROPOSED_NOT_EXPLOITABLE|CONFIRMED|URGENT|custom state>
113+ --state-id <custom state ID>
117114 --severity <CRITICAL|HIGH|MEDIUM|LOW|INFO>
118115 --comment <Comment(Optional)>
119116 --scan-type <SAST|IAC-SECURITY>
120117 ` ,
121118 ),
122- RunE : runTriageUpdate (resultsPredicatesWrapper , featureFlagsWrapper ),
119+ RunE : runTriageUpdate (resultsPredicatesWrapper , featureFlagsWrapper , customStatesWrapper ),
123120 }
124121
125122 triageUpdateCmd .PersistentFlags ().String (params .SimilarityIDFlag , "" , "Similarity ID" )
126123 triageUpdateCmd .PersistentFlags ().String (params .SeverityFlag , "" , "Severity" )
127124 triageUpdateCmd .PersistentFlags ().String (params .ProjectIDFlag , "" , "Project ID." )
128- triageUpdateCmd .PersistentFlags ().String (params .StateFlag , "" , "State" )
125+ triageUpdateCmd .PersistentFlags ().String (params .StateFlag , "" , "Specify the state that you would like to apply. Can be a pre-configured state (e.g., not_exploitable) or a custom state created in your account." )
126+ triageUpdateCmd .PersistentFlags ().Int (params .CustomStateIDFlag , - 1 , "Specify the ID of the states that you would like to apply to this result." )
129127 triageUpdateCmd .PersistentFlags ().String (params .CommentFlag , "" , "Optional comment." )
130128 triageUpdateCmd .PersistentFlags ().String (params .ScanTypeFlag , "" , "Scan Type" )
131129
132130 markFlagAsRequired (triageUpdateCmd , params .SimilarityIDFlag )
133131 markFlagAsRequired (triageUpdateCmd , params .SeverityFlag )
134132 markFlagAsRequired (triageUpdateCmd , params .ProjectIDFlag )
135- markFlagAsRequired (triageUpdateCmd , params .StateFlag )
136133 markFlagAsRequired (triageUpdateCmd , params .ScanTypeFlag )
137134
138135 return triageUpdateCmd
@@ -182,12 +179,13 @@ func runTriageShow(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) f
182179 }
183180}
184181
185- func runTriageUpdate (resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper , featureFlagsWrapper wrappers.FeatureFlagsWrapper ) func (* cobra.Command , []string ) error {
182+ func runTriageUpdate (resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper , featureFlagsWrapper wrappers.FeatureFlagsWrapper , customStatesWrapper wrappers. CustomStatesWrapper ) func (* cobra.Command , []string ) error {
186183 return func (cmd * cobra.Command , _ []string ) error {
187184 similarityID , _ := cmd .Flags ().GetString (params .SimilarityIDFlag )
188185 projectID , _ := cmd .Flags ().GetString (params .ProjectIDFlag )
189186 severity , _ := cmd .Flags ().GetString (params .SeverityFlag )
190187 state , _ := cmd .Flags ().GetString (params .StateFlag )
188+ customStateID , _ := cmd .Flags ().GetInt (params .CustomStateIDFlag )
191189 comment , _ := cmd .Flags ().GetString (params .CommentFlag )
192190 scanType , _ := cmd .Flags ().GetString (params .ScanTypeFlag )
193191 // check if the current tenant has critical severity available
@@ -196,22 +194,82 @@ func runTriageUpdate(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper,
196194 if ! criticalEnabled && strings .EqualFold (severity , "critical" ) {
197195 return errors .Errorf ("%s" , "Critical severity is not available for your tenant.This severity status will be enabled shortly" )
198196 }
197+
198+ var err error
199+ state , customStateID , err = determineSystemOrCustomState (customStatesWrapper , featureFlagsWrapper , state , customStateID )
200+ if err != nil {
201+ return err
202+ }
203+
199204 predicate := & wrappers.PredicateRequest {
200205 SimilarityID : similarityID ,
201206 ProjectID : projectID ,
202207 Severity : severity ,
203- State : state ,
204208 Comment : comment ,
205209 }
206210
207- _ , err := resultsPredicatesWrapper .PredicateSeverityAndState (predicate , scanType )
211+ if state != "" {
212+ predicate .State = & state
213+ } else {
214+ predicate .CustomStateID = & customStateID
215+ }
216+
217+ _ , err = resultsPredicatesWrapper .PredicateSeverityAndState (predicate , scanType )
208218 if err != nil {
209219 return errors .Wrapf (err , "%s" , "Failed updating the predicate" )
210220 }
211221
212222 return nil
213223 }
214224}
225+ func determineSystemOrCustomState (customStatesWrapper wrappers.CustomStatesWrapper , featureFlagsWrapper wrappers.FeatureFlagsWrapper , state string , customStateID int ) (string , int , error ) {
226+ if ! isCustomState (state ) {
227+ return state , - 1 , nil
228+ }
229+
230+ flagResponse , _ := wrappers .GetSpecificFeatureFlag (featureFlagsWrapper , wrappers .SastCustomStateEnabled )
231+ sastCustomStateEnabled := flagResponse .Status
232+ if ! sastCustomStateEnabled {
233+ return "" , - 1 , errors .Errorf ("%s" , "Custom state is not available for your tenant." )
234+ }
235+
236+ if customStateID == - 1 {
237+ if state == "" {
238+ return "" , - 1 , errors .Errorf ("state-id is required when state is not provided" )
239+ }
240+
241+ var err error
242+ customStateID , err = getCustomStateID (customStatesWrapper , state )
243+ if err != nil {
244+ return "" , - 1 , errors .Wrapf (err , "Failed to get custom state ID for state: %s" , state )
245+ }
246+ }
247+ return "" , customStateID , nil
248+ }
249+ func isCustomState (state string ) bool {
250+ if state == "" {
251+ return true
252+ }
253+ for _ , systemState := range systemStates {
254+ if strings .EqualFold (state , systemState .Name ) {
255+ return false
256+ }
257+ }
258+ return true
259+ }
260+
261+ func getCustomStateID (customStatesWrapper wrappers.CustomStatesWrapper , state string ) (int , error ) {
262+ customStates , err := customStatesWrapper .GetAllCustomStates (false )
263+ if err != nil {
264+ return - 1 , errors .Wrap (err , "Failed to fetch custom states" )
265+ }
266+ for _ , customState := range customStates {
267+ if customState .Name == state {
268+ return customState .ID , nil
269+ }
270+ }
271+ return - 1 , errors .Errorf ("No matching state found for %s" , state )
272+ }
215273
216274type predicateView struct {
217275 ID string `format:"name:ID"`
0 commit comments