Skip to content

Added new command engines list-api which returns list of engine apis (AST-92873) #1117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func main() {
accessManagementWrapper := wrappers.NewAccessManagementHTTPWrapper(accessManagementPath)
byorWrapper := wrappers.NewByorHTTPWrapper(byorPath)
containerResolverWrapper := wrappers.NewContainerResolverWrapper()
enginesWrapper := wrappers.NewHTTPEnginesWrapper()

astCli := commands.NewAstCLI(
applicationsWrapper,
Expand Down Expand Up @@ -127,6 +128,7 @@ func main() {
accessManagementWrapper,
byorWrapper,
containerResolverWrapper,
enginesWrapper,
)
exitListener()
err = astCli.Execute()
Expand Down
184 changes: 184 additions & 0 deletions internal/commands/engines.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package commands

import (
"github.com/MakeNowJust/heredoc"
"github.com/checkmarx/ast-cli/internal/commands/util/printer"
"github.com/checkmarx/ast-cli/internal/params"
"github.com/checkmarx/ast-cli/internal/services"
"github.com/checkmarx/ast-cli/internal/wrappers"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

func NewEnginesCommand(
enginesWrapper wrappers.EnginesWrapper,
) *cobra.Command {
enginesCmd := &cobra.Command{
Use: "engines",
Short: "Fetch supported API of scanner engines",
Long: "The engines command enables the ability to fetch engines APIs list in Checkmarx One.",
Annotations: map[string]string{
"command:doc": heredoc.Doc(
`
https://checkmarx.com/resource/documents/en/34965-68643-scan.html
`,
),
},
}
listEngineAPIcmd := enginesListAPISubCommand(enginesWrapper)
enginesCmd.AddCommand(listEngineAPIcmd)
return enginesCmd
}

func enginesListAPISubCommand(
enginesWrapper wrappers.EnginesWrapper,
) *cobra.Command {
enginesListAPIcmd := &cobra.Command{
Use: "list-api",
Short: "fetch the API list of scanner engines",
Long: "The create list-api fetch the API list of scanner engines in Checkmarx One.",
Example: heredoc.Doc(
`
$ cx engines list-api --engine-name <Engine Name>
`,
),
Annotations: map[string]string{
"command:doc": heredoc.Doc(
`
https://checkmarx.com/resource/documents/en/34965-68643-scan.html#UUID-a0bb20d5-5182-3fb4-3da0-0e263344ffe7
`,
),
},
RunE: runEnginesListAPICommand(enginesWrapper),
}
enginesListAPIcmd.PersistentFlags().String("engine-name", "", "The name of the Checkmarx scanner engine to use.")

addOutputFormatFlag(
enginesListAPIcmd,
printer.FormatTable,
printer.FormatJSON,
printer.FormatYAML,
)
return enginesListAPIcmd
}

func runEnginesListAPICommand(enginesWrapper wrappers.EnginesWrapper) func(cmd *cobra.Command, args []string) error {
//fmt.Println("Inside the command execution runEnginesListAPICommand function")
return func(cmd *cobra.Command, args []string) error {
var apiModels []wrappers.ApiModel
var errorModel *wrappers.ErrorModel
//fmt.Println("Before flag")
engineName, err := cmd.Flags().GetString("engine-name")
if err != nil {
return errors.Wrapf(err, "%s", "Invalid 'engine-name' flag")
}
apiModels, errorModel, err = enginesWrapper.GetAllAPIs(engineName)
if err != nil {
return errors.Wrapf(err, "%s\n", "Failed to fetch all engines APIs")
}

//fmt.Println(apiModels)
// Checking the response
if errorModel != nil {
return errors.Errorf(services.ErrorCodeFormat, "Failed to Getting All apis in error model", errorModel.Code, errorModel.Message)
} else if apiModels != nil && len(apiModels) > 0 {
f1, _ := cmd.Flags().GetString(params.OutputFormatFlag)
if f1 == "table" {
views := toAPIsViews(apiModels)
if err != nil {
return err
}
err = printByOutputFormat(cmd, views)
if err != nil {
return err
}
} else {
views := toEnginesView(apiModels)
if err != nil {
return err
}
err = printByOutputFormat(cmd, views)
if err != nil {
return err
}
}
}
return nil
}

}

type Engine struct {
EngineID string `json:"engine_id"`
EngineName string `json:"engine_name"`
APIs []API `json:"apis"`
}

type API struct {
ApiUrl string `json:"api_url"`
ApiName string `json:"api_name"`
Description string `json:"description"`
}

type EnginesView struct {
Engines []Engine `json:"engines"`
}

func toEnginesView(models []wrappers.ApiModel) EnginesView {
engineMap := make(map[string]Engine)

// Group APIs by engine
for _, model := range models {
api := API{
ApiUrl: model.ApiUrl,
ApiName: model.ApiName,
Description: model.Description,
}

engine, exists := engineMap[model.EngineId]
if !exists {
engine = Engine{
EngineID: model.EngineId,
EngineName: model.EngineName,
APIs: []API{},
}
}
engine.APIs = append(engine.APIs, api)
engineMap[model.EngineId] = engine
}

// Collect all engines
var engines []Engine
for _, engine := range engineMap {
engines = append(engines, engine)
}

return EnginesView{
Engines: engines,
}
}

func toAPIsViews(models []wrappers.ApiModel) []apiView {
result := make([]apiView, len(models))
for i := 0; i < len(models); i++ {
result[i] = toAPIView(models[i])
}
return result
}
func toAPIView(model wrappers.ApiModel) apiView {
return apiView{
ApiName: model.ApiName,
Description: model.Description,
ApiUrl: model.ApiUrl,
EngineName: model.EngineName,
EngineId: model.EngineId,
}
}

type apiView struct {
ApiName string
Description string
ApiUrl string
EngineName string
EngineId string
}
98 changes: 98 additions & 0 deletions internal/commands/engines_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package commands

import (
"github.com/checkmarx/ast-cli/internal/wrappers/mock"
"gotest.tools/assert"
"testing"
)

func TestNewEnginesCommand(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "")
assert.NilError(t, err)
}

func TestNewEnginesCommandHelp(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "help")
assert.NilError(t, err)
}

func TestNewEnginesSubCommand(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api")
assert.NilError(t, err)
}

func TestNewEnginesSubCommandHelp(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--help")
assert.NilError(t, err)
}

func TestSubCommandEngineType1(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--engine-name", "SAST")
assert.NilError(t, err)
}

func TestSubCommandEngineType2(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--engine-name", "SCA")
assert.NilError(t, err)
}

func TestSubCommandEngineType3(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--engine-name", "Iac")
assert.NilError(t, err)
}

func TestSubCommandOutPutFormat1(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--output-format", "json")
assert.NilError(t, err)
}

func TestSubCommandOutPutFormat2(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--output-format", "yaml")
assert.NilError(t, err)
}

func TestSubCommandOutPutFormat3(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--output-format", "table")
assert.NilError(t, err)
}

func TestSubCommandEngineError1(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--chibute", "SAST")
assert.Assert(t, err != nil)
}

func TestSubCommandEngineError2(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--engine-name", "SASTS")
assert.NilError(t, err)
}

func TestSubCommandEngineError3(t *testing.T) {

cmd := NewEnginesCommand(&mock.NewHTTPEnginesMockWrapper{})
err := executeTestCommand(cmd, "list-api", "--output-format", "jsonsa")
assert.Assert(t, err != nil)
}
27 changes: 20 additions & 7 deletions internal/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/spf13/viper"
)

// NewAstCLI Return a Checkmarx One CLI root command to execute
func NewAstCLI(
applicationsWrapper wrappers.ApplicationsWrapper,
scansWrapper wrappers.ScansWrapper,
Expand Down Expand Up @@ -55,8 +54,9 @@ func NewAstCLI(
accessManagementWrapper wrappers.AccessManagementWrapper,
byorWrapper wrappers.ByorWrapper,
containerResolverWrapper wrappers.ContainerResolverWrapper,
enginesWrapper wrappers.EnginesWrapper,
) *cobra.Command {
// Create the root

rootCmd := &cobra.Command{
Use: "cx <command> <subcommand> [flags]",
Short: "Checkmarx One CLI",
Expand All @@ -77,7 +77,6 @@ func NewAstCLI(
},
}

// Load default flags
rootCmd.PersistentFlags().Bool(params.DebugFlag, false, params.DebugUsage)
rootCmd.PersistentFlags().String(params.AccessKeyIDFlag, "", params.AccessKeyIDFlagUsage)
rootCmd.PersistentFlags().String(params.AccessKeySecretFlag, "", params.AccessKeySecretFlagUsage)
Expand All @@ -99,8 +98,6 @@ func NewAstCLI(

_ = rootCmd.PersistentFlags().MarkHidden(params.ApikeyOverrideFlag)

// This monitors and traps situations where "extra/garbage" commands
// are passed to Cobra.
rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
PrintConfiguration()
// Need to check the __complete command to allow correct behavior of the autocomplete
Expand All @@ -109,7 +106,7 @@ func NewAstCLI(
os.Exit(0)
}
}
// Link the environment variable to the CLI argument(s).

_ = viper.BindPFlag(params.AccessKeyIDConfigKey, rootCmd.PersistentFlags().Lookup(params.AccessKeyIDFlag))
_ = viper.BindPFlag(params.AccessKeySecretConfigKey, rootCmd.PersistentFlags().Lookup(params.AccessKeySecretFlag))
_ = viper.BindPFlag(params.BaseURIKey, rootCmd.PersistentFlags().Lookup(params.BaseURIFlag))
Expand Down Expand Up @@ -203,6 +200,8 @@ func NewAstCLI(
chatCmd := NewChatCommand(chatWrapper, tenantWrapper)
hooksCmd := NewHooksCommand(jwtWrapper)

enginesCmd := NewEnginesCommand(enginesWrapper)

rootCmd.AddCommand(
scanCmd,
projectCmd,
Expand All @@ -214,6 +213,7 @@ func NewAstCLI(
configCmd,
chatCmd,
hooksCmd,
enginesCmd,
)

rootCmd.SilenceUsage = true
Expand Down Expand Up @@ -257,7 +257,7 @@ func getFilters(cmd *cobra.Command) (map[string]string, error) {
}

func validateExtraFilters(filterKeyVal []string) []string {
// Add support for state = exclude-not-exploitable, will replace all values of filter flag state to "TO_VERIFY;PROPOSED_NOT_EXPLOITABLE;CONFIRMED;URGENT"

if extraFilter[filterKeyVal[0]] != nil {
for privateFilter, value := range extraFilter[filterKeyVal[0]] {
if strings.Contains(filterKeyVal[1], privateFilter) {
Expand Down Expand Up @@ -296,6 +296,13 @@ func addResultFormatFlag(cmd *cobra.Command, defaultFormat string, otherAvailabl
)
}

func addOutputFormatFlag(cmd *cobra.Command, defaultFormat string, otherAvailableFormats ...string) {
cmd.PersistentFlags().String(
params.OutputFormatFlag, defaultFormat,
fmt.Sprintf(params.FormatFlagUsageFormat, append(otherAvailableFormats, defaultFormat)),
)
}

func markFlagAsRequired(cmd *cobra.Command, flag string) {
err := cmd.MarkPersistentFlagRequired(flag)
if err != nil {
Expand All @@ -319,6 +326,12 @@ func printByFormat(cmd *cobra.Command, view interface{}) error {
f, _ := cmd.Flags().GetString(params.FormatFlag)
return printer.Print(cmd.OutOrStdout(), view, f)
}

func printByOutputFormat(cmd *cobra.Command, view interface{}) error {
f, _ := cmd.Flags().GetString(params.OutputFormatFlag)
return printer.Print(cmd.OutOrStdout(), view, f)
}

func printByScanInfoFormat(cmd *cobra.Command, view interface{}) error {
f, _ := cmd.Flags().GetString(params.ScanInfoFormatFlag)
return printer.Print(cmd.OutOrStdout(), view, f)
Expand Down
Loading
Loading