Skip to content

Commit 9af3e93

Browse files
author
Sumit Morchhale
committed
engines list-api feature added
1 parent 8541016 commit 9af3e93

12 files changed

Lines changed: 502 additions & 0 deletions

File tree

cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func main() {
9191
accessManagementWrapper := wrappers.NewAccessManagementHTTPWrapper(accessManagementPath)
9292
byorWrapper := wrappers.NewByorHTTPWrapper(byorPath)
9393
containerResolverWrapper := wrappers.NewContainerResolverWrapper()
94+
enginesWrapper := wrappers.NewHTTPEnginesWrapper()
9495

9596
astCli := commands.NewAstCLI(
9697
applicationsWrapper,
@@ -127,6 +128,7 @@ func main() {
127128
accessManagementWrapper,
128129
byorWrapper,
129130
containerResolverWrapper,
131+
enginesWrapper,
130132
)
131133
exitListener()
132134
err = astCli.Execute()

internal/commands/engines.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package commands
2+
3+
import (
4+
"github.com/MakeNowJust/heredoc"
5+
"github.com/checkmarx/ast-cli/internal/commands/util/printer"
6+
"github.com/checkmarx/ast-cli/internal/params"
7+
"github.com/checkmarx/ast-cli/internal/services"
8+
"github.com/checkmarx/ast-cli/internal/wrappers"
9+
"github.com/pkg/errors"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
func NewEnginesCommand(
14+
enginesWrapper wrappers.EnginesWrapper,
15+
) *cobra.Command {
16+
enginesCmd := &cobra.Command{
17+
Use: "engines",
18+
Short: "Fetch supported API of scanner engines",
19+
Long: "The engines command enables the ability to fetch engines APIs list in Checkmarx One.",
20+
Annotations: map[string]string{
21+
"command:doc": heredoc.Doc(
22+
`
23+
https://checkmarx.com/resource/documents/en/34965-68643-scan.html
24+
`,
25+
),
26+
},
27+
}
28+
listEngineAPIcmd := enginesListAPISubCommand(enginesWrapper)
29+
enginesCmd.AddCommand(listEngineAPIcmd)
30+
return enginesCmd
31+
}
32+
33+
func enginesListAPISubCommand(
34+
enginesWrapper wrappers.EnginesWrapper,
35+
) *cobra.Command {
36+
enginesListAPIcmd := &cobra.Command{
37+
Use: "list-api",
38+
Short: "fetch the API list of scanner engines",
39+
Long: "The create list-api fetch the API list of scanner engines in Checkmarx One.",
40+
Example: heredoc.Doc(
41+
`
42+
$ cx engines list-api --engine-name <Engine Name>
43+
`,
44+
),
45+
Annotations: map[string]string{
46+
"command:doc": heredoc.Doc(
47+
`
48+
https://checkmarx.com/resource/documents/en/34965-68643-scan.html#UUID-a0bb20d5-5182-3fb4-3da0-0e263344ffe7
49+
`,
50+
),
51+
},
52+
RunE: runEnginesListAPICommand(enginesWrapper),
53+
}
54+
enginesListAPIcmd.PersistentFlags().String("engine-name", "", "The name of the Checkmarx scanner engine to use.")
55+
56+
addOutputFormatFlag(
57+
enginesListAPIcmd,
58+
printer.FormatTable,
59+
printer.FormatJSON,
60+
printer.FormatYAML,
61+
)
62+
return enginesListAPIcmd
63+
}
64+
65+
func runEnginesListAPICommand(enginesWrapper wrappers.EnginesWrapper) func(cmd *cobra.Command, args []string) error {
66+
//fmt.Println("Inside the command execution runEnginesListAPICommand function")
67+
return func(cmd *cobra.Command, args []string) error {
68+
var apiModels []wrappers.ApiModel
69+
var errorModel *wrappers.ErrorModel
70+
//fmt.Println("Before flag")
71+
engineName, err := cmd.Flags().GetString("engine-name")
72+
if err != nil {
73+
return errors.Wrapf(err, "%s", "Invalid 'engine-name' flag")
74+
}
75+
apiModels, errorModel, err = enginesWrapper.GetAllAPIs(engineName)
76+
if err != nil {
77+
return errors.Wrapf(err, "%s\n", "Failed to fetch all engines APIs")
78+
}
79+
80+
//fmt.Println(apiModels)
81+
// Checking the response
82+
if errorModel != nil {
83+
return errors.Errorf(services.ErrorCodeFormat, "Failed to Getting All apis in error model", errorModel.Code, errorModel.Message)
84+
} else if apiModels != nil && len(apiModels) > 0 {
85+
f1, _ := cmd.Flags().GetString(params.OutputFormatFlag)
86+
if f1 == "table" {
87+
views := toAPIsViews(apiModels)
88+
if err != nil {
89+
return err
90+
}
91+
err = printByOutputFormat(cmd, views)
92+
if err != nil {
93+
return err
94+
}
95+
} else {
96+
views := toEnginesView(apiModels)
97+
if err != nil {
98+
return err
99+
}
100+
err = printByOutputFormat(cmd, views)
101+
if err != nil {
102+
return err
103+
}
104+
}
105+
}
106+
return nil
107+
}
108+
109+
}
110+
111+
type Engine struct {
112+
EngineID string `json:"engine_id"`
113+
EngineName string `json:"engine_name"`
114+
APIs []API `json:"apis"`
115+
}
116+
117+
type API struct {
118+
ApiUrl string `json:"api_url"`
119+
ApiName string `json:"api_name"`
120+
Description string `json:"description"`
121+
}
122+
123+
type EnginesView struct {
124+
Engines []Engine `json:"engines"`
125+
}
126+
127+
func toEnginesView(models []wrappers.ApiModel) EnginesView {
128+
engineMap := make(map[string]Engine)
129+
130+
// Group APIs by engine
131+
for _, model := range models {
132+
api := API{
133+
ApiUrl: model.ApiUrl,
134+
ApiName: model.ApiName,
135+
Description: model.Description,
136+
}
137+
138+
engine, exists := engineMap[model.EngineId]
139+
if !exists {
140+
engine = Engine{
141+
EngineID: model.EngineId,
142+
EngineName: model.EngineName,
143+
APIs: []API{},
144+
}
145+
}
146+
engine.APIs = append(engine.APIs, api)
147+
engineMap[model.EngineId] = engine
148+
}
149+
150+
// Collect all engines
151+
var engines []Engine
152+
for _, engine := range engineMap {
153+
engines = append(engines, engine)
154+
}
155+
156+
return EnginesView{
157+
Engines: engines,
158+
}
159+
}
160+
161+
func toAPIsViews(models []wrappers.ApiModel) []apiView {
162+
result := make([]apiView, len(models))
163+
for i := 0; i < len(models); i++ {
164+
result[i] = toAPIView(models[i])
165+
}
166+
return result
167+
}
168+
func toAPIView(model wrappers.ApiModel) apiView {
169+
return apiView{
170+
ApiName: model.ApiName,
171+
Description: model.Description,
172+
ApiUrl: model.ApiUrl,
173+
EngineName: model.EngineName,
174+
EngineId: model.EngineId,
175+
}
176+
}
177+
178+
type apiView struct {
179+
ApiName string
180+
Description string
181+
ApiUrl string
182+
EngineName string
183+
EngineId string
184+
}

internal/commands/engines_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package commands
2+
3+
import (
4+
"github.com/checkmarx/ast-cli/internal/wrappers/mock"
5+
"gotest.tools/assert"
6+
"testing"
7+
)
8+
9+
func TestNewEnginesCommand(t *testing.T) {
10+
11+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
12+
err := executeTestCommand(cmd, "")
13+
assert.NilError(t, err)
14+
}
15+
16+
func TestNewEnginesCommandHelp(t *testing.T) {
17+
18+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
19+
err := executeTestCommand(cmd, "help")
20+
assert.NilError(t, err)
21+
}
22+
23+
func TestNewEnginesSubCommand(t *testing.T) {
24+
25+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
26+
err := executeTestCommand(cmd, "list-api")
27+
assert.NilError(t, err)
28+
}
29+
30+
func TestNewEnginesSubCommandHelp(t *testing.T) {
31+
32+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
33+
err := executeTestCommand(cmd, "list-api", "--help")
34+
assert.NilError(t, err)
35+
}
36+
37+
func TestSubCommandEngineType1(t *testing.T) {
38+
39+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
40+
err := executeTestCommand(cmd, "list-api", "--engine-name", "SAST")
41+
assert.NilError(t, err)
42+
}
43+
44+
func TestSubCommandEngineType2(t *testing.T) {
45+
46+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
47+
err := executeTestCommand(cmd, "list-api", "--engine-name", "SCA")
48+
assert.NilError(t, err)
49+
}
50+
51+
func TestSubCommandEngineType3(t *testing.T) {
52+
53+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
54+
err := executeTestCommand(cmd, "list-api", "--engine-name", "Iac")
55+
assert.NilError(t, err)
56+
}
57+
58+
func TestSubCommandOutPutFormat1(t *testing.T) {
59+
60+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
61+
err := executeTestCommand(cmd, "list-api", "--output-format", "json")
62+
assert.NilError(t, err)
63+
}
64+
65+
func TestSubCommandOutPutFormat2(t *testing.T) {
66+
67+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
68+
err := executeTestCommand(cmd, "list-api", "--output-format", "yaml")
69+
assert.NilError(t, err)
70+
}
71+
72+
func TestSubCommandOutPutFormat3(t *testing.T) {
73+
74+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
75+
err := executeTestCommand(cmd, "list-api", "--output-format", "table")
76+
assert.NilError(t, err)
77+
}
78+
79+
func TestSubCommandEngineError1(t *testing.T) {
80+
81+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
82+
err := executeTestCommand(cmd, "list-api", "--chibute", "SAST")
83+
assert.Assert(t, err != nil)
84+
}
85+
86+
func TestSubCommandEngineError2(t *testing.T) {
87+
88+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
89+
err := executeTestCommand(cmd, "list-api", "--engine-name", "SASTS")
90+
assert.NilError(t, err)
91+
}
92+
93+
func TestSubCommandEngineError3(t *testing.T) {
94+
95+
cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
96+
err := executeTestCommand(cmd, "list-api", "--output-format", "jsonsa")
97+
assert.Assert(t, err != nil)
98+
}

internal/commands/root.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func NewAstCLI(
5555
accessManagementWrapper wrappers.AccessManagementWrapper,
5656
byorWrapper wrappers.ByorWrapper,
5757
containerResolverWrapper wrappers.ContainerResolverWrapper,
58+
enginesWrapper wrappers.EnginesWrapper,
5859
) *cobra.Command {
5960
// Create the root
6061
rootCmd := &cobra.Command{
@@ -203,6 +204,8 @@ func NewAstCLI(
203204
chatCmd := NewChatCommand(chatWrapper, tenantWrapper)
204205
hooksCmd := NewHooksCommand(jwtWrapper)
205206

207+
enginesCmd := NewEnginesCommand(enginesWrapper)
208+
206209
rootCmd.AddCommand(
207210
scanCmd,
208211
projectCmd,
@@ -214,6 +217,7 @@ func NewAstCLI(
214217
configCmd,
215218
chatCmd,
216219
hooksCmd,
220+
enginesCmd,
217221
)
218222

219223
rootCmd.SilenceUsage = true
@@ -296,6 +300,13 @@ func addResultFormatFlag(cmd *cobra.Command, defaultFormat string, otherAvailabl
296300
)
297301
}
298302

303+
func addOutputFormatFlag(cmd *cobra.Command, defaultFormat string, otherAvailableFormats ...string) {
304+
cmd.PersistentFlags().String(
305+
params.OutputFormatFlag, defaultFormat,
306+
fmt.Sprintf(params.FormatFlagUsageFormat, append(otherAvailableFormats, defaultFormat)),
307+
)
308+
}
309+
299310
func markFlagAsRequired(cmd *cobra.Command, flag string) {
300311
err := cmd.MarkPersistentFlagRequired(flag)
301312
if err != nil {
@@ -319,6 +330,12 @@ func printByFormat(cmd *cobra.Command, view interface{}) error {
319330
f, _ := cmd.Flags().GetString(params.FormatFlag)
320331
return printer.Print(cmd.OutOrStdout(), view, f)
321332
}
333+
334+
func printByOutputFormat(cmd *cobra.Command, view interface{}) error {
335+
f, _ := cmd.Flags().GetString(params.OutputFormatFlag)
336+
return printer.Print(cmd.OutOrStdout(), view, f)
337+
}
338+
322339
func printByScanInfoFormat(cmd *cobra.Command, view interface{}) error {
323340
f, _ := cmd.Flags().GetString(params.ScanInfoFormatFlag)
324341
return printer.Print(cmd.OutOrStdout(), view, f)

internal/commands/root_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func createASTTestCommand() *cobra.Command {
6868
byorWrapper := &mock.ByorMockWrapper{}
6969
containerResolverMockWrapper := &mock.ContainerResolverMockWrapper{}
7070
customStatesMockWrapper := &mock.CustomStatesMockWrapper{}
71+
newHTTPEnginesMockWrapper := &mock.NewHTTPEnginesMockWrapper{}
7172
return NewAstCLI(
7273
applicationWrapper,
7374
scansMockWrapper,
@@ -103,6 +104,7 @@ func createASTTestCommand() *cobra.Command {
103104
accessManagementWrapper,
104105
byorWrapper,
105106
containerResolverMockWrapper,
107+
newHTTPEnginesMockWrapper,
106108
)
107109
}
108110

internal/commands/util/printer/printer.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package printer
33
import (
44
"encoding/json"
55
"fmt"
6+
yaml "gopkg.in/yaml.v3"
67
"io"
78
"reflect"
89
"strconv"
@@ -30,6 +31,7 @@ const (
3031
FormatXML = "xml"
3132
FormatGLSast = "gl-sast"
3233
FormatGLSca = "gl-sca"
34+
FormatYAML = "yaml"
3335
)
3436

3537
func Print(w io.Writer, view interface{}, format string) error {
@@ -51,6 +53,12 @@ func Print(w io.Writer, view interface{}, format string) error {
5153
} else if IsFormat(format, FormatTable) {
5254
entities := toEntities(view)
5355
printTable(w, entities)
56+
} else if IsFormat(format, FormatYAML) {
57+
viewYaml, err := yaml.Marshal(view)
58+
if err != nil {
59+
return err
60+
}
61+
_, _ = fmt.Fprintln(w, string(viewYaml))
5462
} else {
5563
return errors.Errorf("Invalid format %s", format)
5664
}

0 commit comments

Comments
 (0)