From 5d957d924fb195a41c0a3a3a389679e90f3c0f0e Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Mon, 12 Jan 2026 12:13:20 +0200 Subject: [PATCH 01/28] start adding code and test --- internal/commands/util/license.go | 65 +++++++++++++++++++++++ internal/commands/util/license_test.go | 35 ++++++++++++ internal/wrappers/jwt-helper.go | 34 ++++++++++++ internal/wrappers/mock/jwt-helper-mock.go | 15 ++++++ 4 files changed, 149 insertions(+) create mode 100644 internal/commands/util/license.go create mode 100644 internal/commands/util/license_test.go diff --git a/internal/commands/util/license.go b/internal/commands/util/license.go new file mode 100644 index 000000000..24cffc97c --- /dev/null +++ b/internal/commands/util/license.go @@ -0,0 +1,65 @@ +package util + +import ( + "fmt" + + "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/wrappers" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +func NewLicenseCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command { + cmd := &cobra.Command{ + Use: "license", + Short: "Shows the license details from the JWT token", + Long: "Returns license information extracted from the JWT token", + Example: heredoc.Doc( + ` + $ cx utils license + $ cx utils license --format json + `, + ), + Annotations: map[string]string{ + "command:doc": heredoc.Doc( + ` + https://checkmarx.com/resource/documents/en/todo + `, + ), + }, + RunE: runLicenseCmd(jwtWrapper), + } + cmd.PersistentFlags().String( + params.FormatFlag, + "", + fmt.Sprintf( + params.FormatFlagUsageFormat, + []string{printer.FormatTable, printer.FormatJSON, printer.FormatList}, + ), + ) + return cmd +} + +func runLicenseCmd(jwtWrapper wrappers.JWTWrapper) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + jwtClaims, err := jwtWrapper.GetAllJwtClaims() + if err != nil { + return errors.Wrap(err, "Failed to get license details from JWT token") + } + + if jwtClaims != nil { + format, _ := cmd.Flags().GetString(params.FormatFlag) + + if format == "" { + format = defaultFormat + } + err = printer.Print(cmd.OutOrStdout(), jwtClaims, format) + if err != nil { + return err + } + } + return nil + } +} diff --git a/internal/commands/util/license_test.go b/internal/commands/util/license_test.go new file mode 100644 index 000000000..78aff29f5 --- /dev/null +++ b/internal/commands/util/license_test.go @@ -0,0 +1,35 @@ +package util + +import ( + "bytes" + "strings" + "testing" + + "github.com/checkmarx/ast-cli/internal/wrappers/mock" + "gotest.tools/assert" +) + +func TestLicenseCommandDefaultListFormat(t *testing.T) { + mockJWT := &mock.JWTMockWrapper{ + DastEnabled: true, + } + + cmd := NewLicenseCommand(mockJWT) + + // Capture output + var buf bytes.Buffer + cmd.SetOut(&buf) + + err := cmd.Execute() + assert.NilError(t, err, "License command should run with no errors") + + output := buf.String() + + // Verify output contains expected fields in list format + assert.Assert(t, strings.Contains(output, "TenantName"), "Output should contain TenantName") + assert.Assert(t, strings.Contains(output, "test-tenant"), "Output should contain test-tenant value") + assert.Assert(t, strings.Contains(output, "DastEnabled"), "Output should contain DastEnabled") + assert.Assert(t, strings.Contains(output, "true"), "Output should contain true for DastEnabled") + assert.Assert(t, strings.Contains(output, "AllowedEngines"), "Output should contain AllowedEngines") +} + diff --git a/internal/wrappers/jwt-helper.go b/internal/wrappers/jwt-helper.go index 25012ed28..c0130dbc5 100644 --- a/internal/wrappers/jwt-helper.go +++ b/internal/wrappers/jwt-helper.go @@ -22,15 +22,25 @@ type JWTStruct struct { LicenseData struct { AllowedEngines []string `json:"allowedEngines"` } `json:"LicenseData"` + DastEnabled bool `json:"dastEnabled"` } `json:"ast-license"` ASTRoles []string `json:"roles_ast"` jwt.RegisteredClaims // Embedding the standard claims } +// JwtClaims represents all license-related information extracted from the JWT token +type JwtClaims struct { + TenantName string `json:"tenantName"` + DastEnabled bool `json:"dastEnabled"` + AllowedEngines []string `json:"allowedEngines"` +} + type JWTWrapper interface { GetAllowedEngines(featureFlagsWrapper FeatureFlagsWrapper) (allowedEngines map[string]bool, err error) GetLicenseDetails() (licenseDetails map[string]string, err error) + GetAllJwtClaims() (*JwtClaims, error) IsAllowedEngine(engine string) (bool, error) + IsDastEnabled() (bool, error) ExtractTenantFromToken() (tenant string, err error) CheckPermissionByAccessToken(requiredPermission string) (permission bool, err error) } @@ -133,6 +143,30 @@ func (*JWTStruct) IsAllowedEngine(engine string) (bool, error) { return false, nil } +// IsDastEnabled will return if DAST is enabled in the user license +func (*JWTStruct) IsDastEnabled() (bool, error) { + jwtStruct, err := getJwtStruct() + if err != nil { + return false, err + } + + return jwtStruct.AstLicense.DastEnabled, nil +} + +// GetAllJwtClaims returns all license-related information from the JWT token +func (*JWTStruct) GetAllJwtClaims() (*JwtClaims, error) { + jwtStruct, err := getJwtStruct() + if err != nil { + return nil, err + } + + return &JwtClaims{ + TenantName: jwtStruct.Tenant, + DastEnabled: jwtStruct.AstLicense.DastEnabled, + AllowedEngines: jwtStruct.AstLicense.LicenseData.AllowedEngines, + }, nil +} + func prepareEngines(engines []string, scsLicensingV2 bool) map[string]bool { m := make(map[string]bool) for _, value := range engines { diff --git a/internal/wrappers/mock/jwt-helper-mock.go b/internal/wrappers/mock/jwt-helper-mock.go index eeb751aba..4e9121e04 100644 --- a/internal/wrappers/mock/jwt-helper-mock.go +++ b/internal/wrappers/mock/jwt-helper-mock.go @@ -13,6 +13,7 @@ type JWTMockWrapper struct { EnterpriseSecretsEnabled int SecretDetectionEnabled int CheckmarxOneAssistEnabled int + DastEnabled bool CustomGetAllowedEngines func(wrappers.FeatureFlagsWrapper) (map[string]bool, error) } @@ -79,6 +80,20 @@ func (j *JWTMockWrapper) CheckPermissionByAccessToken(requiredPermission string) return true, nil } +// IsDastEnabled mock for tests +func (j *JWTMockWrapper) IsDastEnabled() (bool, error) { + return j.DastEnabled, nil +} + +// GetAllJwtClaims mock for tests +func (j *JWTMockWrapper) GetAllJwtClaims() (*wrappers.JwtClaims, error) { + return &wrappers.JwtClaims{ + TenantName: "test-tenant", + DastEnabled: j.DastEnabled, + AllowedEngines: engines, + }, nil +} + func (j *JWTMockWrapper) GetLicenseDetails() (licenseDetails map[string]string, err error) { licenseDetails = make(map[string]string) From c717b9ce70fa4a33bd52491149222f2ac18d506e Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Mon, 12 Jan 2026 12:20:19 +0200 Subject: [PATCH 02/28] add to test --- internal/commands/util/license_test.go | 15 ++++++++------- internal/wrappers/mock/jwt-helper-mock.go | 16 +++++++++++----- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/internal/commands/util/license_test.go b/internal/commands/util/license_test.go index 78aff29f5..5d225182b 100644 --- a/internal/commands/util/license_test.go +++ b/internal/commands/util/license_test.go @@ -11,25 +11,26 @@ import ( func TestLicenseCommandDefaultListFormat(t *testing.T) { mockJWT := &mock.JWTMockWrapper{ - DastEnabled: true, + TenantName: "test-tenant", + DastEnabled: false, + AllowedEngines: []string{"sast", "sca"}, } cmd := NewLicenseCommand(mockJWT) - + // Capture output var buf bytes.Buffer cmd.SetOut(&buf) - + err := cmd.Execute() assert.NilError(t, err, "License command should run with no errors") - + output := buf.String() - + // Verify output contains expected fields in list format assert.Assert(t, strings.Contains(output, "TenantName"), "Output should contain TenantName") assert.Assert(t, strings.Contains(output, "test-tenant"), "Output should contain test-tenant value") assert.Assert(t, strings.Contains(output, "DastEnabled"), "Output should contain DastEnabled") - assert.Assert(t, strings.Contains(output, "true"), "Output should contain true for DastEnabled") + assert.Assert(t, strings.Contains(output, "false"), "Output should contain false for DastEnabled") assert.Assert(t, strings.Contains(output, "AllowedEngines"), "Output should contain AllowedEngines") } - diff --git a/internal/wrappers/mock/jwt-helper-mock.go b/internal/wrappers/mock/jwt-helper-mock.go index 4e9121e04..3bcd0f179 100644 --- a/internal/wrappers/mock/jwt-helper-mock.go +++ b/internal/wrappers/mock/jwt-helper-mock.go @@ -14,6 +14,8 @@ type JWTMockWrapper struct { SecretDetectionEnabled int CheckmarxOneAssistEnabled int DastEnabled bool + TenantName string + AllowedEngines []string CustomGetAllowedEngines func(wrappers.FeatureFlagsWrapper) (map[string]bool, error) } @@ -33,15 +35,19 @@ func (j *JWTMockWrapper) GetAllowedEngines(featureFlagsWrapper wrappers.FeatureF return allowedEngines, err } allowedEngines = make(map[string]bool) + enginesToCopy := engines + if j.AllowedEngines != nil { + enginesToCopy = j.AllowedEngines + } - for _, value := range engines { + for _, value := range enginesToCopy { allowedEngines[strings.ToLower(value)] = true } return allowedEngines, nil } -func (*JWTMockWrapper) ExtractTenantFromToken() (tenant string, err error) { - return "test-tenant", nil +func (j *JWTMockWrapper) ExtractTenantFromToken() (tenant string, err error) { + return j.TenantName, nil } // IsAllowedEngine mock for tests @@ -88,9 +94,9 @@ func (j *JWTMockWrapper) IsDastEnabled() (bool, error) { // GetAllJwtClaims mock for tests func (j *JWTMockWrapper) GetAllJwtClaims() (*wrappers.JwtClaims, error) { return &wrappers.JwtClaims{ - TenantName: "test-tenant", + TenantName: j.TenantName, DastEnabled: j.DastEnabled, - AllowedEngines: engines, + AllowedEngines: j.AllowedEngines, }, nil } From 07fe2292c8030a5af3e9d76e5e5a83eb44a35116 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Mon, 12 Jan 2026 13:13:15 +0200 Subject: [PATCH 03/28] improve test --- internal/commands/util/license_test.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/internal/commands/util/license_test.go b/internal/commands/util/license_test.go index 5d225182b..3eb785426 100644 --- a/internal/commands/util/license_test.go +++ b/internal/commands/util/license_test.go @@ -2,11 +2,13 @@ package util import ( "bytes" - "strings" + "encoding/json" "testing" + "github.com/checkmarx/ast-cli/internal/params" + "github.com/checkmarx/ast-cli/internal/wrappers" "github.com/checkmarx/ast-cli/internal/wrappers/mock" - "gotest.tools/assert" + "github.com/stretchr/testify/require" ) func TestLicenseCommandDefaultListFormat(t *testing.T) { @@ -17,20 +19,22 @@ func TestLicenseCommandDefaultListFormat(t *testing.T) { } cmd := NewLicenseCommand(mockJWT) + cmd.SetArgs([]string{"--" + params.FormatFlag, "json"}) // Capture output var buf bytes.Buffer cmd.SetOut(&buf) err := cmd.Execute() - assert.NilError(t, err, "License command should run with no errors") + require.NoError(t, err) - output := buf.String() + // Parse JSON output + var result wrappers.JwtClaims + err = json.Unmarshal(buf.Bytes(), &result) + require.NoError(t, err) - // Verify output contains expected fields in list format - assert.Assert(t, strings.Contains(output, "TenantName"), "Output should contain TenantName") - assert.Assert(t, strings.Contains(output, "test-tenant"), "Output should contain test-tenant value") - assert.Assert(t, strings.Contains(output, "DastEnabled"), "Output should contain DastEnabled") - assert.Assert(t, strings.Contains(output, "false"), "Output should contain false for DastEnabled") - assert.Assert(t, strings.Contains(output, "AllowedEngines"), "Output should contain AllowedEngines") + // Verify structured output + require.Equal(t, "test-tenant", result.TenantName) + require.Equal(t, false, result.DastEnabled) + require.ElementsMatch(t, result.AllowedEngines, []string{"sast", "sca"}) } From d73c7bbaeb8df028fb92373f6e46ba7d0e98a0ac Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Mon, 12 Jan 2026 14:53:37 +0200 Subject: [PATCH 04/28] fix --- internal/commands/util/utils.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index c16db6f93..7a643d789 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -81,6 +81,8 @@ func NewUtilsCommand( maskSecretsCmd := NewMaskSecretsCommand(chatWrapper) + licenseCmd := NewLicenseCommand(jwtWrapper) + utilsCmd.AddCommand( completionCmd, envCheckCmd, @@ -96,6 +98,7 @@ func NewUtilsCommand( remediationCmd, tenantCmd, maskSecretsCmd, + licenseCmd, importCmd, ) From 07c3e1329db235904a6c73b3cbc95d621a0cf1f4 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Mon, 12 Jan 2026 15:29:49 +0200 Subject: [PATCH 05/28] fix --- internal/wrappers/jwt-helper.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/wrappers/jwt-helper.go b/internal/wrappers/jwt-helper.go index c0130dbc5..b09621534 100644 --- a/internal/wrappers/jwt-helper.go +++ b/internal/wrappers/jwt-helper.go @@ -21,8 +21,8 @@ type JWTStruct struct { AstLicense struct { LicenseData struct { AllowedEngines []string `json:"allowedEngines"` + DastEnabled bool `json:"dastEnabled"` } `json:"LicenseData"` - DastEnabled bool `json:"dastEnabled"` } `json:"ast-license"` ASTRoles []string `json:"roles_ast"` jwt.RegisteredClaims // Embedding the standard claims @@ -150,7 +150,7 @@ func (*JWTStruct) IsDastEnabled() (bool, error) { return false, err } - return jwtStruct.AstLicense.DastEnabled, nil + return jwtStruct.AstLicense.LicenseData.DastEnabled, nil } // GetAllJwtClaims returns all license-related information from the JWT token @@ -162,7 +162,7 @@ func (*JWTStruct) GetAllJwtClaims() (*JwtClaims, error) { return &JwtClaims{ TenantName: jwtStruct.Tenant, - DastEnabled: jwtStruct.AstLicense.DastEnabled, + DastEnabled: jwtStruct.AstLicense.LicenseData.DastEnabled, AllowedEngines: jwtStruct.AstLicense.LicenseData.AllowedEngines, }, nil } From b1d0c5f43c82885a22ab25d02ebbc62be7d7565a Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Mon, 12 Jan 2026 15:46:27 +0200 Subject: [PATCH 06/28] use assert instead of require --- internal/commands/util/license_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/commands/util/license_test.go b/internal/commands/util/license_test.go index 3eb785426..bff26905b 100644 --- a/internal/commands/util/license_test.go +++ b/internal/commands/util/license_test.go @@ -8,7 +8,7 @@ import ( "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/wrappers" "github.com/checkmarx/ast-cli/internal/wrappers/mock" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" ) func TestLicenseCommandDefaultListFormat(t *testing.T) { @@ -26,15 +26,15 @@ func TestLicenseCommandDefaultListFormat(t *testing.T) { cmd.SetOut(&buf) err := cmd.Execute() - require.NoError(t, err) + assert.NoError(t, err) // Parse JSON output var result wrappers.JwtClaims err = json.Unmarshal(buf.Bytes(), &result) - require.NoError(t, err) + assert.NoError(t, err) // Verify structured output - require.Equal(t, "test-tenant", result.TenantName) - require.Equal(t, false, result.DastEnabled) - require.ElementsMatch(t, result.AllowedEngines, []string{"sast", "sca"}) + assert.Equal(t, "test-tenant", result.TenantName) + assert.Equal(t, false, result.DastEnabled) + assert.ElementsMatch(t, []string{"sast", "sca"}, result.AllowedEngines) } From f8e4c08cce69e2ebde3351d45716f5fdd24051cd Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 10:17:21 +0200 Subject: [PATCH 07/28] use tenant command --- internal/commands/util/license.go | 65 ----------------------- internal/commands/util/license_test.go | 40 -------------- internal/params/flags.go | 7 +++ internal/wrappers/jwt-helper.go | 38 ++----------- internal/wrappers/mock/jwt-helper-mock.go | 19 ++----- 5 files changed, 13 insertions(+), 156 deletions(-) delete mode 100644 internal/commands/util/license.go delete mode 100644 internal/commands/util/license_test.go diff --git a/internal/commands/util/license.go b/internal/commands/util/license.go deleted file mode 100644 index 24cffc97c..000000000 --- a/internal/commands/util/license.go +++ /dev/null @@ -1,65 +0,0 @@ -package util - -import ( - "fmt" - - "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/wrappers" - "github.com/pkg/errors" - "github.com/spf13/cobra" -) - -func NewLicenseCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command { - cmd := &cobra.Command{ - Use: "license", - Short: "Shows the license details from the JWT token", - Long: "Returns license information extracted from the JWT token", - Example: heredoc.Doc( - ` - $ cx utils license - $ cx utils license --format json - `, - ), - Annotations: map[string]string{ - "command:doc": heredoc.Doc( - ` - https://checkmarx.com/resource/documents/en/todo - `, - ), - }, - RunE: runLicenseCmd(jwtWrapper), - } - cmd.PersistentFlags().String( - params.FormatFlag, - "", - fmt.Sprintf( - params.FormatFlagUsageFormat, - []string{printer.FormatTable, printer.FormatJSON, printer.FormatList}, - ), - ) - return cmd -} - -func runLicenseCmd(jwtWrapper wrappers.JWTWrapper) func(cmd *cobra.Command, args []string) error { - return func(cmd *cobra.Command, args []string) error { - jwtClaims, err := jwtWrapper.GetAllJwtClaims() - if err != nil { - return errors.Wrap(err, "Failed to get license details from JWT token") - } - - if jwtClaims != nil { - format, _ := cmd.Flags().GetString(params.FormatFlag) - - if format == "" { - format = defaultFormat - } - err = printer.Print(cmd.OutOrStdout(), jwtClaims, format) - if err != nil { - return err - } - } - return nil - } -} diff --git a/internal/commands/util/license_test.go b/internal/commands/util/license_test.go deleted file mode 100644 index bff26905b..000000000 --- a/internal/commands/util/license_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package util - -import ( - "bytes" - "encoding/json" - "testing" - - "github.com/checkmarx/ast-cli/internal/params" - "github.com/checkmarx/ast-cli/internal/wrappers" - "github.com/checkmarx/ast-cli/internal/wrappers/mock" - "github.com/stretchr/testify/assert" -) - -func TestLicenseCommandDefaultListFormat(t *testing.T) { - mockJWT := &mock.JWTMockWrapper{ - TenantName: "test-tenant", - DastEnabled: false, - AllowedEngines: []string{"sast", "sca"}, - } - - cmd := NewLicenseCommand(mockJWT) - cmd.SetArgs([]string{"--" + params.FormatFlag, "json"}) - - // Capture output - var buf bytes.Buffer - cmd.SetOut(&buf) - - err := cmd.Execute() - assert.NoError(t, err) - - // Parse JSON output - var result wrappers.JwtClaims - err = json.Unmarshal(buf.Bytes(), &result) - assert.NoError(t, err) - - // Verify structured output - assert.Equal(t, "test-tenant", result.TenantName) - assert.Equal(t, false, result.DastEnabled) - assert.ElementsMatch(t, []string{"sast", "sca"}, result.AllowedEngines) -} diff --git a/internal/params/flags.go b/internal/params/flags.go index 85abf3a4c..169a2aace 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -291,6 +291,13 @@ const ( ResultPolicyDefaultTimeout = 1 ) +// License +const ( + CxOneAssistEnabledKey = "scan.config.plugins.cxoneassist" + CxDevAssistEnabledKey = "scan.config.plugins.cxdevassist" + DastEnabledKey = "scan.config.plugins.dastenabled" +) + // Results const ( SastType = "sast" diff --git a/internal/wrappers/jwt-helper.go b/internal/wrappers/jwt-helper.go index b09621534..fd10eb883 100644 --- a/internal/wrappers/jwt-helper.go +++ b/internal/wrappers/jwt-helper.go @@ -28,19 +28,10 @@ type JWTStruct struct { jwt.RegisteredClaims // Embedding the standard claims } -// JwtClaims represents all license-related information extracted from the JWT token -type JwtClaims struct { - TenantName string `json:"tenantName"` - DastEnabled bool `json:"dastEnabled"` - AllowedEngines []string `json:"allowedEngines"` -} - type JWTWrapper interface { GetAllowedEngines(featureFlagsWrapper FeatureFlagsWrapper) (allowedEngines map[string]bool, err error) GetLicenseDetails() (licenseDetails map[string]string, err error) - GetAllJwtClaims() (*JwtClaims, error) IsAllowedEngine(engine string) (bool, error) - IsDastEnabled() (bool, error) ExtractTenantFromToken() (tenant string, err error) CheckPermissionByAccessToken(requiredPermission string) (permission bool, err error) } @@ -105,8 +96,9 @@ func (*JWTStruct) GetLicenseDetails() (licenseDetails map[string]string, err err containsIgnoreCase(jwtStruct.AstLicense.LicenseData.AllowedEngines, commonParams.AIProtectionType) devAssistEnabled := containsIgnoreCase(jwtStruct.AstLicense.LicenseData.AllowedEngines, commonParams.CheckmarxDevAssistType) - licenseDetails["scan.config.plugins.cxoneassist"] = strconv.FormatBool(assistEnabled) - licenseDetails["scan.config.plugins.cxdevassist"] = strconv.FormatBool(devAssistEnabled) + licenseDetails[commonParams.CxOneAssistEnabledKey] = strconv.FormatBool(assistEnabled) + licenseDetails[commonParams.CxDevAssistEnabledKey] = strconv.FormatBool(devAssistEnabled) + licenseDetails[commonParams.DastEnabledKey] = strconv.FormatBool(jwtStruct.AstLicense.LicenseData.DastEnabled) return licenseDetails, nil } @@ -143,30 +135,6 @@ func (*JWTStruct) IsAllowedEngine(engine string) (bool, error) { return false, nil } -// IsDastEnabled will return if DAST is enabled in the user license -func (*JWTStruct) IsDastEnabled() (bool, error) { - jwtStruct, err := getJwtStruct() - if err != nil { - return false, err - } - - return jwtStruct.AstLicense.LicenseData.DastEnabled, nil -} - -// GetAllJwtClaims returns all license-related information from the JWT token -func (*JWTStruct) GetAllJwtClaims() (*JwtClaims, error) { - jwtStruct, err := getJwtStruct() - if err != nil { - return nil, err - } - - return &JwtClaims{ - TenantName: jwtStruct.Tenant, - DastEnabled: jwtStruct.AstLicense.LicenseData.DastEnabled, - AllowedEngines: jwtStruct.AstLicense.LicenseData.AllowedEngines, - }, nil -} - func prepareEngines(engines []string, scsLicensingV2 bool) map[string]bool { m := make(map[string]bool) for _, value := range engines { diff --git a/internal/wrappers/mock/jwt-helper-mock.go b/internal/wrappers/mock/jwt-helper-mock.go index 3bcd0f179..c4fc38958 100644 --- a/internal/wrappers/mock/jwt-helper-mock.go +++ b/internal/wrappers/mock/jwt-helper-mock.go @@ -86,28 +86,15 @@ func (j *JWTMockWrapper) CheckPermissionByAccessToken(requiredPermission string) return true, nil } -// IsDastEnabled mock for tests -func (j *JWTMockWrapper) IsDastEnabled() (bool, error) { - return j.DastEnabled, nil -} - -// GetAllJwtClaims mock for tests -func (j *JWTMockWrapper) GetAllJwtClaims() (*wrappers.JwtClaims, error) { - return &wrappers.JwtClaims{ - TenantName: j.TenantName, - DastEnabled: j.DastEnabled, - AllowedEngines: j.AllowedEngines, - }, nil -} - func (j *JWTMockWrapper) GetLicenseDetails() (licenseDetails map[string]string, err error) { licenseDetails = make(map[string]string) assistEnabled := (j.CheckmarxOneAssistEnabled != CheckmarxOneAssistDisabled) || (j.AIEnabled != AIProtectionDisabled) - licenseDetails["scan.config.plugins.cxoneassist"] = strconv.FormatBool(assistEnabled) + licenseDetails[params.CxOneAssistEnabledKey] = strconv.FormatBool(assistEnabled) standaloneEnabled := true - licenseDetails["scan.config.plugins.cxdevassist"] = strconv.FormatBool(standaloneEnabled) + licenseDetails[params.CxDevAssistEnabledKey] = strconv.FormatBool(standaloneEnabled) + licenseDetails[params.DastEnabledKey] = strconv.FormatBool(j.DastEnabled) for _, engine := range engines { licenseDetails[engine] = licenseEnabledValue From 698a9f564b406c9e008e228bd249be7ed5beabcf Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 10:19:07 +0200 Subject: [PATCH 08/28] remove command --- internal/commands/util/utils.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index 7a643d789..c16db6f93 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -81,8 +81,6 @@ func NewUtilsCommand( maskSecretsCmd := NewMaskSecretsCommand(chatWrapper) - licenseCmd := NewLicenseCommand(jwtWrapper) - utilsCmd.AddCommand( completionCmd, envCheckCmd, @@ -98,7 +96,6 @@ func NewUtilsCommand( remediationCmd, tenantCmd, maskSecretsCmd, - licenseCmd, importCmd, ) From 63882fa79078f5c328f5cfe989e9b405ef7095b4 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 11:04:46 +0200 Subject: [PATCH 09/28] add test --- internal/wrappers/jwt-helper.go | 18 +++++- internal/wrappers/jwt-helper_test.go | 88 ++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 3 deletions(-) diff --git a/internal/wrappers/jwt-helper.go b/internal/wrappers/jwt-helper.go index fd10eb883..77d52de59 100644 --- a/internal/wrappers/jwt-helper.go +++ b/internal/wrappers/jwt-helper.go @@ -85,12 +85,15 @@ func (*JWTStruct) GetAllowedEngines(featureFlagsWrapper FeatureFlagsWrapper) (al } func (*JWTStruct) GetLicenseDetails() (licenseDetails map[string]string, err error) { - licenseDetails = make(map[string]string) - jwtStruct, err := getJwtStruct() if err != nil { return nil, err } + return buildLicenseDetailsFromJWT(jwtStruct), nil +} + +func buildLicenseDetailsFromJWT(jwtStruct *JWTStruct) map[string]string { + licenseDetails := make(map[string]string) assistEnabled := containsIgnoreCase(jwtStruct.AstLicense.LicenseData.AllowedEngines, commonParams.CheckmarxOneAssistType) || containsIgnoreCase(jwtStruct.AstLicense.LicenseData.AllowedEngines, commonParams.AIProtectionType) @@ -99,7 +102,8 @@ func (*JWTStruct) GetLicenseDetails() (licenseDetails map[string]string, err err licenseDetails[commonParams.CxOneAssistEnabledKey] = strconv.FormatBool(assistEnabled) licenseDetails[commonParams.CxDevAssistEnabledKey] = strconv.FormatBool(devAssistEnabled) licenseDetails[commonParams.DastEnabledKey] = strconv.FormatBool(jwtStruct.AstLicense.LicenseData.DastEnabled) - return licenseDetails, nil + + return licenseDetails } // containsIgnoreCase returns true if target exists in arr using case-insensitive comparison @@ -112,7 +116,15 @@ func containsIgnoreCase(arr []string, target string) bool { return false } +// getJwtStructFunc is a variable that holds the function to get JWT struct +// This allows for dependency injection in tests +var getJwtStructFunc = getJwtStructImpl + func getJwtStruct() (*JWTStruct, error) { + return getJwtStructFunc() +} + +func getJwtStructImpl() (*JWTStruct, error) { accessToken, err := GetAccessToken() if err != nil { return nil, err diff --git a/internal/wrappers/jwt-helper_test.go b/internal/wrappers/jwt-helper_test.go index ca51c1e19..4a63ec0c2 100644 --- a/internal/wrappers/jwt-helper_test.go +++ b/internal/wrappers/jwt-helper_test.go @@ -115,3 +115,91 @@ func TestGetUniqueID(t *testing.T) { assert.Assert(t, !strings.Contains(parts[1], "\\"), "Username should not contain backslash") }) } + +func TestBuildLicenseDetailsFromJWT(t *testing.T) { + tests := []struct { + name string + allowedEngines []string + dastEnabled bool + expectedCxOneAssist string + expectedCxDevAssist string + expectedDast string + }{ + { + name: "all features enabled", + allowedEngines: []string{"sast", "sca", commonParams.CheckmarxOneAssistType, commonParams.CheckmarxDevAssistType}, + dastEnabled: true, + expectedCxOneAssist: "true", + expectedCxDevAssist: "true", + expectedDast: "true", + }, + { + name: "all features enabled - AIProtection", + allowedEngines: []string{"sast", "sca", commonParams.CheckmarxOneAssistType, commonParams.AIProtectionType}, + dastEnabled: true, + expectedCxOneAssist: "true", + expectedCxDevAssist: "false", + expectedDast: "true", + }, + { + name: "only dev assist enabled", + allowedEngines: []string{"sast", commonParams.CheckmarxDevAssistType}, + dastEnabled: false, + expectedCxOneAssist: "false", + expectedCxDevAssist: "true", + expectedDast: "false", + }, + { + name: "no assist features enabled", + allowedEngines: []string{"sast", "sca", "iac-security"}, + dastEnabled: false, + expectedCxOneAssist: "false", + expectedCxDevAssist: "false", + expectedDast: "false", + }, + { + name: "only dast enabled", + allowedEngines: []string{"sast"}, + dastEnabled: true, + expectedCxOneAssist: "false", + expectedCxDevAssist: "false", + expectedDast: "true", + }, + { + name: "case insensitive matching", + allowedEngines: []string{"checkmarx one assist", "ai protection"}, + dastEnabled: false, + expectedCxOneAssist: "true", + expectedCxDevAssist: "true", + expectedDast: "false", + }, + { + name: "empty allowed engines", + allowedEngines: []string{}, + dastEnabled: false, + expectedCxOneAssist: "false", + expectedCxDevAssist: "false", + expectedDast: "false", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a JWT struct with test data + jwtStruct := &JWTStruct{} + jwtStruct.AstLicense.LicenseData.AllowedEngines = tt.allowedEngines + jwtStruct.AstLicense.LicenseData.DastEnabled = tt.dastEnabled + + // Call the function under test + licenseDetails := buildLicenseDetailsFromJWT(jwtStruct) + + // Assert the results + assert.Equal(t, tt.expectedCxOneAssist, licenseDetails[commonParams.CxOneAssistEnabledKey], + "CxOneAssist should be %s", tt.expectedCxOneAssist) + assert.Equal(t, tt.expectedCxDevAssist, licenseDetails[commonParams.CxDevAssistEnabledKey], + "CxDevAssist should be %s", tt.expectedCxDevAssist) + assert.Equal(t, tt.expectedDast, licenseDetails[commonParams.DastEnabledKey], + "Dast should be %s", tt.expectedDast) + }) + } +} From d3f3c3365db27c24bcdd8a94b3eeb38d3bf133a1 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 11:07:06 +0200 Subject: [PATCH 10/28] fix test --- internal/wrappers/jwt-helper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/wrappers/jwt-helper_test.go b/internal/wrappers/jwt-helper_test.go index 4a63ec0c2..cae93448d 100644 --- a/internal/wrappers/jwt-helper_test.go +++ b/internal/wrappers/jwt-helper_test.go @@ -167,7 +167,7 @@ func TestBuildLicenseDetailsFromJWT(t *testing.T) { }, { name: "case insensitive matching", - allowedEngines: []string{"checkmarx one assist", "ai protection"}, + allowedEngines: []string{"checkmarx one assist", "checkmarx developer assist"}, dastEnabled: false, expectedCxOneAssist: "true", expectedCxDevAssist: "true", From ee6af7d281ed82d980e2209df54ec7f607860270 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 11:16:01 +0200 Subject: [PATCH 11/28] undo change --- internal/wrappers/jwt-helper.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/internal/wrappers/jwt-helper.go b/internal/wrappers/jwt-helper.go index 77d52de59..5ef0c1d15 100644 --- a/internal/wrappers/jwt-helper.go +++ b/internal/wrappers/jwt-helper.go @@ -116,15 +116,7 @@ func containsIgnoreCase(arr []string, target string) bool { return false } -// getJwtStructFunc is a variable that holds the function to get JWT struct -// This allows for dependency injection in tests -var getJwtStructFunc = getJwtStructImpl - func getJwtStruct() (*JWTStruct, error) { - return getJwtStructFunc() -} - -func getJwtStructImpl() (*JWTStruct, error) { accessToken, err := GetAccessToken() if err != nil { return nil, err From 7e638ffcc721c528e3834d22eddd37fb2174054d Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 11:17:08 +0200 Subject: [PATCH 12/28] undo changes --- internal/wrappers/mock/jwt-helper-mock.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/internal/wrappers/mock/jwt-helper-mock.go b/internal/wrappers/mock/jwt-helper-mock.go index c4fc38958..2de24e675 100644 --- a/internal/wrappers/mock/jwt-helper-mock.go +++ b/internal/wrappers/mock/jwt-helper-mock.go @@ -14,8 +14,6 @@ type JWTMockWrapper struct { SecretDetectionEnabled int CheckmarxOneAssistEnabled int DastEnabled bool - TenantName string - AllowedEngines []string CustomGetAllowedEngines func(wrappers.FeatureFlagsWrapper) (map[string]bool, error) } @@ -35,19 +33,15 @@ func (j *JWTMockWrapper) GetAllowedEngines(featureFlagsWrapper wrappers.FeatureF return allowedEngines, err } allowedEngines = make(map[string]bool) - enginesToCopy := engines - if j.AllowedEngines != nil { - enginesToCopy = j.AllowedEngines - } - for _, value := range enginesToCopy { + for _, value := range engines { allowedEngines[strings.ToLower(value)] = true } return allowedEngines, nil } func (j *JWTMockWrapper) ExtractTenantFromToken() (tenant string, err error) { - return j.TenantName, nil + return "test-tenant", nil } // IsAllowedEngine mock for tests From d1058d23f7e4994dbe3d3bc1c7a1b538d85724b6 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 11:17:33 +0200 Subject: [PATCH 13/28] undo --- internal/wrappers/mock/jwt-helper-mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/wrappers/mock/jwt-helper-mock.go b/internal/wrappers/mock/jwt-helper-mock.go index 2de24e675..9991b9629 100644 --- a/internal/wrappers/mock/jwt-helper-mock.go +++ b/internal/wrappers/mock/jwt-helper-mock.go @@ -40,7 +40,7 @@ func (j *JWTMockWrapper) GetAllowedEngines(featureFlagsWrapper wrappers.FeatureF return allowedEngines, nil } -func (j *JWTMockWrapper) ExtractTenantFromToken() (tenant string, err error) { +func (*JWTMockWrapper) ExtractTenantFromToken() (tenant string, err error) { return "test-tenant", nil } From c7cfcb4f27cda1a337bb0a4a549c79aff798c510 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 11:37:03 +0200 Subject: [PATCH 14/28] lint --- internal/params/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/params/flags.go b/internal/params/flags.go index 169a2aace..13f43f4bd 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -295,7 +295,7 @@ const ( const ( CxOneAssistEnabledKey = "scan.config.plugins.cxoneassist" CxDevAssistEnabledKey = "scan.config.plugins.cxdevassist" - DastEnabledKey = "scan.config.plugins.dastenabled" + DastEnabledKey = "scan.config.plugins.dastenabled" ) // Results From 8a4831ccb3e97c3f4a7104cd09cb5580bf35cbf4 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 11:37:26 +0200 Subject: [PATCH 15/28] lint --- internal/wrappers/jwt-helper_test.go | 96 ++++++++++++++-------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/internal/wrappers/jwt-helper_test.go b/internal/wrappers/jwt-helper_test.go index cae93448d..ea01fb041 100644 --- a/internal/wrappers/jwt-helper_test.go +++ b/internal/wrappers/jwt-helper_test.go @@ -118,68 +118,68 @@ func TestGetUniqueID(t *testing.T) { func TestBuildLicenseDetailsFromJWT(t *testing.T) { tests := []struct { - name string - allowedEngines []string - dastEnabled bool - expectedCxOneAssist string - expectedCxDevAssist string - expectedDast string + name string + allowedEngines []string + dastEnabled bool + expectedCxOneAssist string + expectedCxDevAssist string + expectedDast string }{ { - name: "all features enabled", - allowedEngines: []string{"sast", "sca", commonParams.CheckmarxOneAssistType, commonParams.CheckmarxDevAssistType}, - dastEnabled: true, - expectedCxOneAssist: "true", - expectedCxDevAssist: "true", - expectedDast: "true", + name: "all features enabled", + allowedEngines: []string{"sast", "sca", commonParams.CheckmarxOneAssistType, commonParams.CheckmarxDevAssistType}, + dastEnabled: true, + expectedCxOneAssist: "true", + expectedCxDevAssist: "true", + expectedDast: "true", }, { - name: "all features enabled - AIProtection", - allowedEngines: []string{"sast", "sca", commonParams.CheckmarxOneAssistType, commonParams.AIProtectionType}, - dastEnabled: true, - expectedCxOneAssist: "true", - expectedCxDevAssist: "false", - expectedDast: "true", + name: "all features enabled - AIProtection", + allowedEngines: []string{"sast", "sca", commonParams.CheckmarxOneAssistType, commonParams.AIProtectionType}, + dastEnabled: true, + expectedCxOneAssist: "true", + expectedCxDevAssist: "false", + expectedDast: "true", }, { - name: "only dev assist enabled", - allowedEngines: []string{"sast", commonParams.CheckmarxDevAssistType}, - dastEnabled: false, - expectedCxOneAssist: "false", - expectedCxDevAssist: "true", - expectedDast: "false", + name: "only dev assist enabled", + allowedEngines: []string{"sast", commonParams.CheckmarxDevAssistType}, + dastEnabled: false, + expectedCxOneAssist: "false", + expectedCxDevAssist: "true", + expectedDast: "false", }, { - name: "no assist features enabled", - allowedEngines: []string{"sast", "sca", "iac-security"}, - dastEnabled: false, - expectedCxOneAssist: "false", - expectedCxDevAssist: "false", - expectedDast: "false", + name: "no assist features enabled", + allowedEngines: []string{"sast", "sca", "iac-security"}, + dastEnabled: false, + expectedCxOneAssist: "false", + expectedCxDevAssist: "false", + expectedDast: "false", }, { - name: "only dast enabled", - allowedEngines: []string{"sast"}, - dastEnabled: true, - expectedCxOneAssist: "false", - expectedCxDevAssist: "false", - expectedDast: "true", + name: "only dast enabled", + allowedEngines: []string{"sast"}, + dastEnabled: true, + expectedCxOneAssist: "false", + expectedCxDevAssist: "false", + expectedDast: "true", }, { - name: "case insensitive matching", - allowedEngines: []string{"checkmarx one assist", "checkmarx developer assist"}, - dastEnabled: false, - expectedCxOneAssist: "true", - expectedCxDevAssist: "true", - expectedDast: "false", + name: "case insensitive matching", + allowedEngines: []string{"checkmarx one assist", "checkmarx developer assist"}, + dastEnabled: false, + expectedCxOneAssist: "true", + expectedCxDevAssist: "true", + expectedDast: "false", }, { - name: "empty allowed engines", - allowedEngines: []string{}, - dastEnabled: false, - expectedCxOneAssist: "false", - expectedCxDevAssist: "false", - expectedDast: "false", + name: "empty allowed engines", + allowedEngines: []string{}, + dastEnabled: false, + expectedCxOneAssist: "false", + expectedCxDevAssist: "false", + expectedDast: "false", }, } From 4dc61d53c339c79c4b7deb7727278c27d40e5b7d Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 14:01:55 +0200 Subject: [PATCH 16/28] start adding environments command --- cmd/main.go | 3 + internal/commands/environments.go | 162 ++++++++++++++++++++ internal/commands/root.go | 3 + internal/commands/root_test.go | 2 + internal/params/binds.go | 1 + internal/params/envs.go | 1 + internal/params/flags.go | 1 + internal/params/keys.go | 1 + internal/wrappers/environments-http.go | 62 ++++++++ internal/wrappers/environments.go | 62 ++++++++ internal/wrappers/mock/environments-mock.go | 26 ++++ 11 files changed, 324 insertions(+) create mode 100644 internal/commands/environments.go create mode 100644 internal/wrappers/environments-http.go create mode 100644 internal/wrappers/environments.go create mode 100644 internal/wrappers/mock/environments-mock.go diff --git a/cmd/main.go b/cmd/main.go index c1a66f0f9..3b17cecd3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -59,6 +59,7 @@ func main() { accessManagementPath := viper.GetString(params.AccessManagementPathKey) byorPath := viper.GetString(params.ByorPathKey) realtimeScannerPath := viper.GetString(params.RealtimeScannerPathKey) + environmentsPath := viper.GetString(params.EnvironmentsPathKey) customStatesWrapper := wrappers.NewCustomStatesHTTPWrapper() scansWrapper := wrappers.NewHTTPScansWrapper(scans) @@ -97,6 +98,7 @@ func main() { containerResolverWrapper := wrappers.NewContainerResolverWrapper() realTimeWrapper := wrappers.NewRealtimeScannerHTTPWrapper(realtimeScannerPath, jwtWrapper, featureFlagsWrapper) telemetryWrapper := wrappers.NewHTTPTelemetryAIWrapper(realtimeScannerPath) + environmentsWrapper := wrappers.NewHTTPEnvironmentsWrapper(environmentsPath) astCli := commands.NewAstCLI( applicationsWrapper, @@ -136,6 +138,7 @@ func main() { containerResolverWrapper, realTimeWrapper, telemetryWrapper, + environmentsWrapper, ) exitListener() err = astCli.Execute() diff --git a/internal/commands/environments.go b/internal/commands/environments.go new file mode 100644 index 000000000..0dd5b5821 --- /dev/null +++ b/internal/commands/environments.go @@ -0,0 +1,162 @@ +package commands + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/MakeNowJust/heredoc" + "github.com/checkmarx/ast-cli/internal/commands/util/printer" + "github.com/checkmarx/ast-cli/internal/services" + "github.com/checkmarx/ast-cli/internal/wrappers" + commonParams "github.com/checkmarx/ast-cli/internal/params" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +const ( + failedGettingEnvironments = "Failed getting environments" +) + +var ( + filterEnvironmentsListFlagUsage = fmt.Sprintf( + "Filter the list of environments. Use ';' as the delimiter for arrays. Available filters are: %s", + strings.Join( + []string{ + commonParams.LimitQueryParam, + commonParams.OffsetQueryParam, + commonParams.FromDateQueryParam, + commonParams.ToDateQueryParam, + commonParams.SearchQueryParam, + commonParams.SortQueryParam, + }, ",", + ), + ) +) + +// NewEnvironmentsCommand creates the environments command +func NewEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) *cobra.Command { + environmentsCmd := &cobra.Command{ + Use: "environments", + Short: "Manage DAST environments", + Long: "The environments command enables the ability to manage DAST environments in Checkmarx One", + Annotations: map[string]string{ + "command:doc": heredoc.Doc( + ` + https://checkmarx.com/resource/documents/en/34965-68634-environments.html + `, + ), + }, + } + + listEnvironmentsCmd := &cobra.Command{ + Use: "list", + Short: "List all DAST environments in the system", + Example: heredoc.Doc( + ` + $ cx environments list --format list + $ cx environments list --filter "from=2024-01-01,to=2024-12-31" + $ cx environments list --filter "search=production,sort=created" + `, + ), + Annotations: map[string]string{ + "command:doc": heredoc.Doc( + ` + https://checkmarx.com/resource/documents/en/34965-68634-environments.html + `, + ), + }, + RunE: runListEnvironmentsCommand(environmentsWrapper), + } + listEnvironmentsCmd.PersistentFlags().StringSlice(commonParams.FilterFlag, []string{}, filterEnvironmentsListFlagUsage) + + addFormatFlagToMultipleCommands( + []*cobra.Command{listEnvironmentsCmd}, + printer.FormatTable, + printer.FormatJSON, + printer.FormatList, + ) + + environmentsCmd.AddCommand(listEnvironmentsCmd) + return environmentsCmd +} + +func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + var allEnvironmentsModel *wrappers.EnvironmentsCollectionResponseModel + var errorModel *wrappers.ErrorModel + + params, err := getFilters(cmd) + if err != nil { + return errors.Wrapf(err, "%s", failedGettingEnvironments) + } + + // Map filter parameters to API query parameters + // The API expects: from, to, search, sort + if from, ok := params[commonParams.FromDateQueryParam]; ok { + params["from"] = from + delete(params, commonParams.FromDateQueryParam) + } + if to, ok := params[commonParams.ToDateQueryParam]; ok { + params["to"] = to + delete(params, commonParams.ToDateQueryParam) + } + if search, ok := params[commonParams.SearchQueryParam]; ok { + params["search"] = search + delete(params, commonParams.SearchQueryParam) + } + if sort, ok := params[commonParams.SortQueryParam]; ok { + params["sort"] = sort + delete(params, commonParams.SortQueryParam) + } + + allEnvironmentsModel, errorModel, err = environmentsWrapper.Get(params) + if err != nil { + return errors.Wrapf(err, "%s\n", failedGettingEnvironments) + } + + // Checking the response + if errorModel != nil { + return errors.Errorf(services.ErrorCodeFormat, failedGettingEnvironments, errorModel.Code, errorModel.Message) + } else if allEnvironmentsModel != nil && allEnvironmentsModel.Environments != nil { + err = printByFormat(cmd, toEnvironmentViews(allEnvironmentsModel.Environments)) + if err != nil { + return err + } + } + return nil + } +} + +func toEnvironmentViews(models []wrappers.EnvironmentResponseModel) []environmentView { + result := make([]environmentView, len(models)) + for i := 0; i < len(models); i++ { + result[i] = toEnvironmentView(models[i]) + } + return result +} + +func toEnvironmentView(model wrappers.EnvironmentResponseModel) environmentView { + return environmentView{ + EnvironmentID: model.EnvironmentID, + Domain: model.Domain, + URL: model.URL, + ScanType: model.ScanType, + Created: model.Created, + RiskRating: model.RiskRating, + LastScanTime: model.LastScanTime, + LastStatus: model.LastStatus, + } +} + +type environmentView struct { + EnvironmentID string `format:"name:Environment ID"` + Domain string + URL string + ScanType string `format:"name:Scan Type"` + Created string + RiskRating string `format:"name:Risk Rating"` + LastScanTime string `format:"name:Last Scan Time"` + LastStatus string `format:"name:Last Status"` +} + diff --git a/internal/commands/root.go b/internal/commands/root.go index 453070073..999e9b67e 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -61,6 +61,7 @@ func NewAstCLI( containerResolverWrapper wrappers.ContainerResolverWrapper, realTimeWrapper wrappers.RealtimeScannerWrapper, telemetryWrapper wrappers.TelemetryWrapper, + environmentsWrapper wrappers.EnvironmentsWrapper, ) *cobra.Command { // Create the root rootCmd := &cobra.Command{ @@ -187,6 +188,7 @@ func NewAstCLI( realTimeWrapper, ) projectCmd := NewProjectCommand(applicationsWrapper, projectsWrapper, groupsWrapper, accessManagementWrapper, featureFlagsWrapper) + environmentsCmd := NewEnvironmentsCommand(environmentsWrapper) resultsCmd := NewResultsCommand( resultsWrapper, @@ -237,6 +239,7 @@ func NewAstCLI( rootCmd.AddCommand( scanCmd, projectCmd, + environmentsCmd, resultsCmd, triageCmd, versionCmd, diff --git a/internal/commands/root_test.go b/internal/commands/root_test.go index 654594c5b..3b0e6d014 100644 --- a/internal/commands/root_test.go +++ b/internal/commands/root_test.go @@ -73,6 +73,7 @@ func createASTTestCommand() *cobra.Command { customStatesMockWrapper := &mock.CustomStatesMockWrapper{} realTimeWrapper := &mock.RealtimeScannerMockWrapper{} telemetryWrapper := &mock.TelemetryMockWrapper{} + environmentsWrapper := &mock.EnvironmentsMockWrapper{} return NewAstCLI( applicationWrapper, scansMockWrapper, @@ -111,6 +112,7 @@ func createASTTestCommand() *cobra.Command { containerResolverMockWrapper, realTimeWrapper, telemetryWrapper, + environmentsWrapper, ) } diff --git a/internal/params/binds.go b/internal/params/binds.go index d65f595e7..79a9b0319 100644 --- a/internal/params/binds.go +++ b/internal/params/binds.go @@ -82,6 +82,7 @@ var EnvVarsBinds = []struct { {RiskManagementPathKey, RiskManagementPathEnv, "api/risk-management/projects/%s/results?scanID=%s"}, {ConfigFilePathKey, ConfigFilePathEnv, ""}, {RealtimeScannerPathKey, RealtimeScannerPathEnv, "api/realtime-scanner"}, + {EnvironmentsPathKey, EnvironmentsPathEnv, "api/dast/scans/environments"}, {StartMultiPartUploadPathKey, StartMultiPartUploadPathEnv, "api/uploads/start-multipart-upload"}, {MultipartPresignedPathKey, MultipartPresignedPathEnv, "api/uploads/multipart-presigned"}, {CompleteMultiPartUploadPathKey, CompleteMultipartUploadPathEnv, "api/uploads/complete-multipart-upload"}, diff --git a/internal/params/envs.go b/internal/params/envs.go index 614792cbf..976ac62f0 100644 --- a/internal/params/envs.go +++ b/internal/params/envs.go @@ -84,6 +84,7 @@ const ( RiskManagementPathEnv = "CX_RISK_MANAGEMENT_PATH" ConfigFilePathEnv = "CX_CONFIG_FILE_PATH" RealtimeScannerPathEnv = "CX_REALTIME_SCANNER_PATH" + EnvironmentsPathEnv = "CX_ENVIRONMENTS_PATH" UniqueIDEnv = "CX_UNIQUE_ID" StartMultiPartUploadPathEnv = "CX_START_MULTIPART_UPLOAD_PATH" MultipartPresignedPathEnv = "CX_MULTIPART_PRESIGNED_URL_PATH" diff --git a/internal/params/flags.go b/internal/params/flags.go index 13f43f4bd..16cdb246c 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -282,6 +282,7 @@ const ( NodeIDsQueryParam = "node-ids" IncludeNodesQueryParam = "include-nodes" SortQueryParam = "sort" + SearchQueryParam = "search" Profile = "default" BaseURI = "" BaseIAMURI = "" diff --git a/internal/params/keys.go b/internal/params/keys.go index 09aeea2c8..c440f8954 100644 --- a/internal/params/keys.go +++ b/internal/params/keys.go @@ -83,6 +83,7 @@ var ( RiskManagementPathKey = strings.ToLower(RiskManagementPathEnv) ConfigFilePathKey = strings.ToLower(ConfigFilePathEnv) RealtimeScannerPathKey = strings.ToLower(RealtimeScannerPathEnv) + EnvironmentsPathKey = strings.ToLower(EnvironmentsPathEnv) UniqueIDConfigKey = strings.ToLower(UniqueIDEnv) StartMultiPartUploadPathKey = strings.ToLower(StartMultiPartUploadPathEnv) MultipartPresignedPathKey = strings.ToLower(MultipartPresignedPathEnv) diff --git a/internal/wrappers/environments-http.go b/internal/wrappers/environments-http.go new file mode 100644 index 000000000..a11ddb203 --- /dev/null +++ b/internal/wrappers/environments-http.go @@ -0,0 +1,62 @@ +package wrappers + +import ( + "encoding/json" + "net/http" + + commonParams "github.com/checkmarx/ast-cli/internal/params" + "github.com/pkg/errors" + "github.com/spf13/viper" +) + +const ( + failedToParseEnvironments = "Failed to parse environments" +) + +// EnvironmentsHTTPWrapper implements the EnvironmentsWrapper interface +type EnvironmentsHTTPWrapper struct { + path string +} + +// NewHTTPEnvironmentsWrapper creates a new HTTP environments wrapper +func NewHTTPEnvironmentsWrapper(path string) EnvironmentsWrapper { + return &EnvironmentsHTTPWrapper{ + path: path, + } +} + +// Get retrieves environments with optional query parameters +func (e *EnvironmentsHTTPWrapper) Get(params map[string]string) (*EnvironmentsCollectionResponseModel, *ErrorModel, error) { + clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) + + resp, err := SendHTTPRequestWithQueryParams(http.MethodGet, e.path, params, nil, clientTimeout) + if err != nil { + return nil, nil, err + } + + defer func() { + _ = resp.Body.Close() + }() + + decoder := json.NewDecoder(resp.Body) + + switch resp.StatusCode { + case http.StatusBadRequest, http.StatusInternalServerError: + errorModel := ErrorModel{} + err = decoder.Decode(&errorModel) + if err != nil { + return nil, nil, errors.Wrapf(err, failedToParseEnvironments) + } + return nil, &errorModel, nil + case http.StatusOK: + model := EnvironmentsCollectionResponseModel{} + err = decoder.Decode(&model) + if err != nil { + return nil, nil, errors.Wrapf(err, failedToParseEnvironments) + } + return &model, nil, nil + default: + return nil, nil, errors.Errorf("response status code %d", resp.StatusCode) + } +} + diff --git a/internal/wrappers/environments.go b/internal/wrappers/environments.go new file mode 100644 index 000000000..eb489cae3 --- /dev/null +++ b/internal/wrappers/environments.go @@ -0,0 +1,62 @@ +package wrappers + +import "encoding/json" + +// EnvironmentsWrapper defines the interface for environments operations +type EnvironmentsWrapper interface { + // Get retrieves environments with optional query parameters (from, to, search, sort) + Get(params map[string]string) (*EnvironmentsCollectionResponseModel, *ErrorModel, error) +} + +// EnvironmentsCollectionResponseModel represents the response from the environments API +type EnvironmentsCollectionResponseModel struct { + Environments []EnvironmentResponseModel `json:"environments"` + MisconfiguredCount int `json:"misconfiguredCount"` + TotalItems int `json:"totalItems"` + ZrokHost string `json:"zrokHost"` +} + +// EnvironmentResponseModel represents a single environment +type EnvironmentResponseModel struct { + EnvironmentID string `json:"environmentId"` + TunnelID string `json:"tunnelId"` + Created string `json:"created"` + Domain string `json:"domain"` + URL string `json:"url"` + ScanType string `json:"scanType"` + ProjectIds []string `json:"projectIds"` + Tags []string `json:"tags"` + Groups []string `json:"groups"` + Applications []EnvironmentApp `json:"applications"` + RiskLevel RiskLevel `json:"riskLevel"` + RiskRating string `json:"riskRating"` + AlertRiskLevel RiskLevel `json:"alertRiskLevel"` + LastScanID string `json:"lastScanID"` + LastScanTime string `json:"lastScanTime"` + LastStatus string `json:"lastStatus"` + AuthSuccess bool `json:"authSuccess"` + IsPublic bool `json:"isPublic"` + AuthMethod string `json:"authMethod"` + LastAuthUUID string `json:"lastAuthUUID"` + LastAuthSuccess bool `json:"lastAuthSuccess"` + Settings json.RawMessage `json:"settings"` // Keep as raw JSON + HasReport bool `json:"hasReport"` + HasAuth bool `json:"hasAuth"` + TunnelState string `json:"tunnelState"` + ScanConfig json.RawMessage `json:"scanConfig"` // Keep as raw JSON +} + +// EnvironmentApp represents an application associated with an environment +type EnvironmentApp struct { + ApplicationID string `json:"applicationId"` + IsPrimary bool `json:"isPrimary"` +} + +// RiskLevel represents risk counts by severity +type RiskLevel struct { + CriticalCount int `json:"criticalCount"` + HighCount int `json:"highCount"` + MediumCount int `json:"mediumCount"` + LowCount int `json:"lowCount"` + InfoCount int `json:"infoCount"` +} diff --git a/internal/wrappers/mock/environments-mock.go b/internal/wrappers/mock/environments-mock.go new file mode 100644 index 000000000..4fc695077 --- /dev/null +++ b/internal/wrappers/mock/environments-mock.go @@ -0,0 +1,26 @@ +package mock + +import "github.com/checkmarx/ast-cli/internal/wrappers" + +// EnvironmentsMockWrapper is a mock implementation of EnvironmentsWrapper +type EnvironmentsMockWrapper struct{} + +// Get mocks the Get method +func (e *EnvironmentsMockWrapper) Get(params map[string]string) (*wrappers.EnvironmentsCollectionResponseModel, *wrappers.ErrorModel, error) { + return &wrappers.EnvironmentsCollectionResponseModel{ + Environments: []wrappers.EnvironmentResponseModel{ + { + EnvironmentID: "test-env-id", + Domain: "test-domain", + URL: "https://test.example.com", + ScanType: "DAST", + Created: "2024-01-01T00:00:00Z", + RiskRating: "Low risk", + LastScanTime: "2024-01-02T00:00:00Z", + LastStatus: "Finished@Scan finished successfully", + }, + }, + TotalItems: 1, + }, nil, nil +} + From 76ebb37670af7b4f34c976d6e36f4960dc1a656d Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Tue, 13 Jan 2026 14:13:40 +0200 Subject: [PATCH 17/28] filters and test --- internal/commands/environments.go | 34 +++++------------------- internal/commands/environments_test.go | 36 ++++++++++++++++++++++++++ internal/params/flags.go | 2 ++ 3 files changed, 45 insertions(+), 27 deletions(-) create mode 100644 internal/commands/environments_test.go diff --git a/internal/commands/environments.go b/internal/commands/environments.go index 0dd5b5821..dce67fe8f 100644 --- a/internal/commands/environments.go +++ b/internal/commands/environments.go @@ -1,15 +1,14 @@ package commands import ( - "encoding/json" "fmt" "strings" "github.com/MakeNowJust/heredoc" "github.com/checkmarx/ast-cli/internal/commands/util/printer" + commonParams "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/services" "github.com/checkmarx/ast-cli/internal/wrappers" - commonParams "github.com/checkmarx/ast-cli/internal/params" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -23,10 +22,8 @@ var ( "Filter the list of environments. Use ';' as the delimiter for arrays. Available filters are: %s", strings.Join( []string{ - commonParams.LimitQueryParam, - commonParams.OffsetQueryParam, - commonParams.FromDateQueryParam, - commonParams.ToDateQueryParam, + commonParams.FromQueryParam, + commonParams.ToQueryParam, commonParams.SearchQueryParam, commonParams.SortQueryParam, }, ",", @@ -43,7 +40,7 @@ func NewEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) *c Annotations: map[string]string{ "command:doc": heredoc.Doc( ` - https://checkmarx.com/resource/documents/en/34965-68634-environments.html + https://checkmarx.com/resource/documents/en/todo `, ), }, @@ -55,14 +52,14 @@ func NewEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) *c Example: heredoc.Doc( ` $ cx environments list --format list - $ cx environments list --filter "from=2024-01-01,to=2024-12-31" + $ cx environments list --filter "from=1,to=10" $ cx environments list --filter "search=production,sort=created" `, ), Annotations: map[string]string{ "command:doc": heredoc.Doc( ` - https://checkmarx.com/resource/documents/en/34965-68634-environments.html + https://checkmarx.com/resource/documents/en/todo `, ), }, @@ -91,25 +88,8 @@ func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper return errors.Wrapf(err, "%s", failedGettingEnvironments) } - // Map filter parameters to API query parameters // The API expects: from, to, search, sort - if from, ok := params[commonParams.FromDateQueryParam]; ok { - params["from"] = from - delete(params, commonParams.FromDateQueryParam) - } - if to, ok := params[commonParams.ToDateQueryParam]; ok { - params["to"] = to - delete(params, commonParams.ToDateQueryParam) - } - if search, ok := params[commonParams.SearchQueryParam]; ok { - params["search"] = search - delete(params, commonParams.SearchQueryParam) - } - if sort, ok := params[commonParams.SortQueryParam]; ok { - params["sort"] = sort - delete(params, commonParams.SortQueryParam) - } - + // from and to are pagination parameters (e.g., from=1, to=10 for first page) allEnvironmentsModel, errorModel, err = environmentsWrapper.Get(params) if err != nil { return errors.Wrapf(err, "%s\n", failedGettingEnvironments) diff --git a/internal/commands/environments_test.go b/internal/commands/environments_test.go new file mode 100644 index 000000000..e0a498a93 --- /dev/null +++ b/internal/commands/environments_test.go @@ -0,0 +1,36 @@ +//go:build !integration + +package commands + +import ( + "testing" +) + +func TestEnvironmentsHelp(t *testing.T) { + execCmdNilAssertion(t, "help", "environments") +} + +func TestEnvironmentsNoSub(t *testing.T) { + execCmdNilAssertion(t, "environments") +} + +func TestEnvironmentsList(t *testing.T) { + execCmdNilAssertion(t, "environments", "list") +} + +func TestEnvironmentsListWithFormat(t *testing.T) { + execCmdNilAssertion(t, "environments", "list", "--format", "json") +} + +func TestEnvironmentsListWithFilters(t *testing.T) { + execCmdNilAssertion(t, "environments", "list", "--filter", "from=1,to=10") +} + +func TestEnvironmentsListWithSearch(t *testing.T) { + execCmdNilAssertion(t, "environments", "list", "--filter", "search=test") +} + +func TestEnvironmentsListWithSort(t *testing.T) { + execCmdNilAssertion(t, "environments", "list", "--filter", "sort=domain:asc") +} + diff --git a/internal/params/flags.go b/internal/params/flags.go index 16cdb246c..82b5f8449 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -275,6 +275,8 @@ const ( ProjectIDQueryParam = "project-id" FromDateQueryParam = "from-date" ToDateQueryParam = "to-date" + FromQueryParam = "from" + ToQueryParam = "to" SeverityQueryParam = "severity" StateQueryParam = "state" GroupQueryParam = "group" From b66c9481c082a103aade8447d209b4efede29d18 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Wed, 14 Jan 2026 15:30:59 +0200 Subject: [PATCH 18/28] lint --- internal/commands/environments.go | 1 - internal/commands/environments_test.go | 1 - internal/wrappers/mock/environments-mock.go | 1 - 3 files changed, 3 deletions(-) diff --git a/internal/commands/environments.go b/internal/commands/environments.go index dce67fe8f..396a6efb4 100644 --- a/internal/commands/environments.go +++ b/internal/commands/environments.go @@ -139,4 +139,3 @@ type environmentView struct { LastScanTime string `format:"name:Last Scan Time"` LastStatus string `format:"name:Last Status"` } - diff --git a/internal/commands/environments_test.go b/internal/commands/environments_test.go index e0a498a93..fce6d174e 100644 --- a/internal/commands/environments_test.go +++ b/internal/commands/environments_test.go @@ -33,4 +33,3 @@ func TestEnvironmentsListWithSearch(t *testing.T) { func TestEnvironmentsListWithSort(t *testing.T) { execCmdNilAssertion(t, "environments", "list", "--filter", "sort=domain:asc") } - diff --git a/internal/wrappers/mock/environments-mock.go b/internal/wrappers/mock/environments-mock.go index 4fc695077..1dafb953f 100644 --- a/internal/wrappers/mock/environments-mock.go +++ b/internal/wrappers/mock/environments-mock.go @@ -23,4 +23,3 @@ func (e *EnvironmentsMockWrapper) Get(params map[string]string) (*wrappers.Envir TotalItems: 1, }, nil, nil } - From 926b0957e5967b2700f91e3447219a4327096f81 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Wed, 14 Jan 2026 15:36:34 +0200 Subject: [PATCH 19/28] lint --- internal/commands/environments.go | 4 ++-- internal/wrappers/environments-http.go | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/commands/environments.go b/internal/commands/environments.go index 396a6efb4..320e5f85f 100644 --- a/internal/commands/environments.go +++ b/internal/commands/environments.go @@ -111,12 +111,12 @@ func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper func toEnvironmentViews(models []wrappers.EnvironmentResponseModel) []environmentView { result := make([]environmentView, len(models)) for i := 0; i < len(models); i++ { - result[i] = toEnvironmentView(models[i]) + result[i] = toEnvironmentView(&models[i]) } return result } -func toEnvironmentView(model wrappers.EnvironmentResponseModel) environmentView { +func toEnvironmentView(model *wrappers.EnvironmentResponseModel) environmentView { return environmentView{ EnvironmentID: model.EnvironmentID, Domain: model.Domain, diff --git a/internal/wrappers/environments-http.go b/internal/wrappers/environments-http.go index a11ddb203..2b0608549 100644 --- a/internal/wrappers/environments-http.go +++ b/internal/wrappers/environments-http.go @@ -59,4 +59,3 @@ func (e *EnvironmentsHTTPWrapper) Get(params map[string]string) (*EnvironmentsCo return nil, nil, errors.Errorf("response status code %d", resp.StatusCode) } } - From d451fb3538ed8d25db11ec3012bf29d2d20b6663 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Wed, 14 Jan 2026 15:48:45 +0200 Subject: [PATCH 20/28] fix --- test/integration/util_command.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/integration/util_command.go b/test/integration/util_command.go index 92f2aa904..eaaf8cc70 100644 --- a/test/integration/util_command.go +++ b/test/integration/util_command.go @@ -127,6 +127,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { containerResolverWrapper := wrappers.NewContainerResolverWrapper() realtimeScannerWrapper := wrappers.NewRealtimeScannerHTTPWrapper(realtimeScannerPath, jwtWrapper, featureFlagsWrapper) telemetryWrapper := wrappers.NewHTTPTelemetryAIWrapper(realtimeScannerPath) + environmentsWrapper := wrappers.NewHTTPEnvironmentsWrapper(environmentsPath) astCli := commands.NewAstCLI( applicationsWrapper, @@ -166,6 +167,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { containerResolverWrapper, realtimeScannerWrapper, telemetryWrapper, + environmentsWrapper, ) return astCli } From 323a78c370adb25948400e54d8147594ffe1a632 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Wed, 14 Jan 2026 15:53:14 +0200 Subject: [PATCH 21/28] fix --- test/integration/util_command.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/util_command.go b/test/integration/util_command.go index eaaf8cc70..22ae94ca9 100644 --- a/test/integration/util_command.go +++ b/test/integration/util_command.go @@ -89,6 +89,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { accessManagementPath := viper.GetString(params.AccessManagementPathKey) byorPath := viper.GetString(params.ByorPathKey) realtimeScannerPath := viper.GetString(params.RealtimeScannerPathKey) + environmentsPath := viper.GetString(params.EnvironmentsPathKey) scansWrapper := wrappers.NewHTTPScansWrapper(scans) applicationsWrapper := wrappers.NewApplicationsHTTPWrapper(applications) From 47e53b317992e9eeb094e74821268eb11687ca99 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Thu, 15 Jan 2026 09:07:22 +0200 Subject: [PATCH 22/28] move commands to commandutils --- .../commands/commandutils/commandutils.go | 27 +++++++++++++++++++ internal/commands/environments.go | 5 ++-- internal/commands/predicates.go | 7 ++--- internal/commands/project.go | 9 ++++--- internal/commands/result.go | 13 ++++----- internal/commands/root.go | 17 ------------ internal/commands/scan.go | 9 ++++--- 7 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 internal/commands/commandutils/commandutils.go diff --git a/internal/commands/commandutils/commandutils.go b/internal/commands/commandutils/commandutils.go new file mode 100644 index 000000000..c6289937a --- /dev/null +++ b/internal/commands/commandutils/commandutils.go @@ -0,0 +1,27 @@ +package commandutils + +import ( + "fmt" + + "github.com/checkmarx/ast-cli/internal/commands/util/printer" + "github.com/checkmarx/ast-cli/internal/params" + "github.com/spf13/cobra" +) + +func AddFormatFlagToMultipleCommands(commands []*cobra.Command, defaultFormat string, otherAvailableFormats ...string) { + for _, c := range commands { + AddFormatFlag(c, defaultFormat, otherAvailableFormats...) + } +} + +func AddFormatFlag(cmd *cobra.Command, defaultFormat string, otherAvailableFormats ...string) { + cmd.PersistentFlags().String( + params.FormatFlag, defaultFormat, + fmt.Sprintf(params.FormatFlagUsageFormat, append(otherAvailableFormats, defaultFormat)), + ) +} + +func PrintByFormat(cmd *cobra.Command, view interface{}) error { + f, _ := cmd.Flags().GetString(params.FormatFlag) + return printer.Print(cmd.OutOrStdout(), view, f) +} diff --git a/internal/commands/environments.go b/internal/commands/environments.go index 320e5f85f..e0e8cb31e 100644 --- a/internal/commands/environments.go +++ b/internal/commands/environments.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/MakeNowJust/heredoc" + "github.com/checkmarx/ast-cli/internal/commands/commandutils" "github.com/checkmarx/ast-cli/internal/commands/util/printer" commonParams "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/services" @@ -67,7 +68,7 @@ func NewEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) *c } listEnvironmentsCmd.PersistentFlags().StringSlice(commonParams.FilterFlag, []string{}, filterEnvironmentsListFlagUsage) - addFormatFlagToMultipleCommands( + commandutils.AddFormatFlagToMultipleCommands( []*cobra.Command{listEnvironmentsCmd}, printer.FormatTable, printer.FormatJSON, @@ -99,7 +100,7 @@ func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper if errorModel != nil { return errors.Errorf(services.ErrorCodeFormat, failedGettingEnvironments, errorModel.Code, errorModel.Message) } else if allEnvironmentsModel != nil && allEnvironmentsModel.Environments != nil { - err = printByFormat(cmd, toEnvironmentViews(allEnvironmentsModel.Environments)) + err = commandutils.PrintByFormat(cmd, toEnvironmentViews(allEnvironmentsModel.Environments)) if err != nil { return err } diff --git a/internal/commands/predicates.go b/internal/commands/predicates.go index c292f8f3e..306cc605e 100644 --- a/internal/commands/predicates.go +++ b/internal/commands/predicates.go @@ -9,6 +9,7 @@ import ( "encoding/json" "github.com/MakeNowJust/heredoc" + "github.com/checkmarx/ast-cli/internal/commands/commandutils" "github.com/checkmarx/ast-cli/internal/commands/util/printer" "github.com/checkmarx/ast-cli/internal/logger" "github.com/checkmarx/ast-cli/internal/params" @@ -35,7 +36,7 @@ func NewResultsPredicatesCommand(resultsPredicatesWrapper wrappers.ResultsPredic triageUpdateCmd := triageUpdateSubCommand(resultsPredicatesWrapper, featureFlagsWrapper, customStatesWrapper) triageGetStatesCmd := triageGetStatesSubCommand(customStatesWrapper, featureFlagsWrapper) - addFormatFlagToMultipleCommands( + commandutils.AddFormatFlagToMultipleCommands( []*cobra.Command{triageShowCmd}, printer.FormatList, printer.FormatTable, printer.FormatJSON, ) @@ -184,7 +185,7 @@ func runTriageShow(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) f if err != nil { return errors.Wrapf(err, "%s", "Failed showing the predicate") } - err = printByFormat(cmd, toScaPredicateResultView(scaPredicates)) + err = commandutils.PrintByFormat(cmd, toScaPredicateResultView(scaPredicates)) if err != nil { return err } @@ -203,7 +204,7 @@ func runTriageShow(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) f errorModel.Message, ) } else if predicatesCollection != nil { - err = printByFormat(cmd, toPredicatesView(*predicatesCollection)) + err = commandutils.PrintByFormat(cmd, toPredicatesView(*predicatesCollection)) if err != nil { return err } diff --git a/internal/commands/project.go b/internal/commands/project.go index 4f6cbb957..1ae334f95 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -7,6 +7,7 @@ import ( "time" "github.com/MakeNowJust/heredoc" + "github.com/checkmarx/ast-cli/internal/commands/commandutils" "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/checkmarx/ast-cli/internal/commands/util/printer" errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" @@ -196,7 +197,7 @@ func NewProjectCommand(applicationsWrapper wrappers.ApplicationsWrapper, project RunE: runGetProjectsTagsCommand(projectsWrapper), } - addFormatFlagToMultipleCommands( + commandutils.AddFormatFlagToMultipleCommands( []*cobra.Command{showProjectCmd, listProjectsCmd, createProjCmd}, printer.FormatTable, printer.FormatJSON, @@ -281,7 +282,7 @@ func runCreateProjectCommand( if errorModel != nil { return errors.Errorf(services.ErrorCodeFormat, services.FailedCreatingProj, errorModel.Code, errorModel.Message) } else if projResponseModel != nil { - err = printByFormat(cmd, toProjectView(*projResponseModel)) + err = commandutils.PrintByFormat(cmd, toProjectView(*projResponseModel)) if err != nil { return errors.Wrapf(err, "%s", services.FailedCreatingProj) } @@ -414,7 +415,7 @@ func runListProjectsCommand(projectsWrapper wrappers.ProjectsWrapper) func(cmd * if errorModel != nil { return errors.Errorf(services.ErrorCodeFormat, failedGettingAll, errorModel.Code, errorModel.Message) } else if allProjectsModel != nil && allProjectsModel.Projects != nil { - err = printByFormat(cmd, toProjectViews(allProjectsModel.Projects)) + err = commandutils.PrintByFormat(cmd, toProjectViews(allProjectsModel.Projects)) if err != nil { return err } @@ -484,7 +485,7 @@ func runGetProjectByIDCommand(projectsWrapper wrappers.ProjectsWrapper) func(cmd resp := GetProjectByName(projectResponseModel.Name, projectsWrapper) projectResponseModel.Groups = resp.Groups - err = printByFormat(cmd, toProjectView(*projectResponseModel)) + err = commandutils.PrintByFormat(cmd, toProjectView(*projectResponseModel)) if err != nil { return err } diff --git a/internal/commands/result.go b/internal/commands/result.go index f37c5e46b..efce5b148 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -16,6 +16,7 @@ import ( "time" "github.com/MakeNowJust/heredoc" + "github.com/checkmarx/ast-cli/internal/commands/commandutils" "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/checkmarx/ast-cli/internal/commands/util/printer" errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" @@ -250,7 +251,7 @@ func riskManagementSubCommand(riskManagement wrappers.RiskManagementWrapper, fea riskManagementCmd.PersistentFlags().String(commonParams.ScanIDFlag, "", "Scan ID") riskManagementCmd.PersistentFlags().Int(commonParams.LimitFlag, -1, "Limit") - addFormatFlag(riskManagementCmd, printer.FormatJSON, printer.FormatTable, printer.FormatList) + commandutils.AddFormatFlag(riskManagementCmd, printer.FormatJSON, printer.FormatTable, printer.FormatList) return riskManagementCmd } @@ -334,7 +335,7 @@ func resultBflSubCommand(bflWrapper wrappers.BflWrapper) *cobra.Command { } addScanIDFlag(resultBflCmd, "ID to report on") addQueryIDFlag(resultBflCmd, "Query Id from the result") - addFormatFlag(resultBflCmd, printer.FormatList, printer.FormatJSON) + commandutils.AddFormatFlag(resultBflCmd, printer.FormatList, printer.FormatJSON) markFlagAsRequired(resultBflCmd, commonParams.ScanIDFlag) markFlagAsRequired(resultBflCmd, commonParams.QueryIDFlag) @@ -380,7 +381,7 @@ func runRiskManagementCommand(riskManagement wrappers.RiskManagementWrapper, fea return err } results.Results = utils.LimitSlice(results.Results, limit) - err = printByFormat(cmd, results) + err = commandutils.PrintByFormat(cmd, results) return err } } @@ -513,7 +514,7 @@ func runGetBestFixLocationCommand(bflWrapper wrappers.BflWrapper) func(cmd *cobr if errorModel != nil { return errors.Errorf("%s: CODE: %d, %s", failedGettingBfl, errorModel.Code, errorModel.Message) } else if bflResponseModel != nil { - err = printByFormat(cmd, toBflView(*bflResponseModel)) + err = commandutils.PrintByFormat(cmd, toBflView(*bflResponseModel)) if err != nil { return err } @@ -574,7 +575,7 @@ func resultCodeBashing(codeBashingWrapper wrappers.CodeBashingWrapper) *cobra.Co if err != nil { log.Fatal(err) } - addFormatFlag(resultCmd, printer.FormatJSON, printer.FormatTable, printer.FormatList) + commandutils.AddFormatFlag(resultCmd, printer.FormatJSON, printer.FormatTable, printer.FormatList) return resultCmd } @@ -1132,7 +1133,7 @@ func runGetCodeBashingCommand( if webError != nil { return errors.New(webError.Message) } - err = printByFormat(cmd, *CodeBashingModel) + err = commandutils.PrintByFormat(cmd, *CodeBashingModel) if err != nil { return errors.Wrapf(err, "%s", failedListingCodeBashing) } diff --git a/internal/commands/root.go b/internal/commands/root.go index 999e9b67e..4005f6bfc 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -307,19 +307,6 @@ func validateExtraFilters(filterKeyVal []string) []string { return filterKeyVal } -func addFormatFlagToMultipleCommands(commands []*cobra.Command, defaultFormat string, otherAvailableFormats ...string) { - for _, c := range commands { - addFormatFlag(c, defaultFormat, otherAvailableFormats...) - } -} - -func addFormatFlag(cmd *cobra.Command, defaultFormat string, otherAvailableFormats ...string) { - cmd.PersistentFlags().String( - params.FormatFlag, defaultFormat, - fmt.Sprintf(params.FormatFlagUsageFormat, append(otherAvailableFormats, defaultFormat)), - ) -} - func addScanInfoFormatFlag(cmd *cobra.Command, defaultFormat string, otherAvailableFormats ...string) { cmd.PersistentFlags().String( params.ScanInfoFormatFlag, defaultFormat, @@ -353,10 +340,6 @@ func addQueryIDFlag(cmd *cobra.Command, helpMsg string) { cmd.PersistentFlags().String(params.QueryIDFlag, "", helpMsg) } -func printByFormat(cmd *cobra.Command, view interface{}) error { - f, _ := cmd.Flags().GetString(params.FormatFlag) - 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) diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 2dd7c3ca4..2d88000aa 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -23,6 +23,7 @@ import ( "unicode" "github.com/checkmarx/ast-cli/internal/commands/asca" + "github.com/checkmarx/ast-cli/internal/commands/commandutils" "github.com/checkmarx/ast-cli/internal/commands/scarealtime" "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/checkmarx/ast-cli/internal/commands/util/printer" @@ -245,7 +246,7 @@ func NewScanCommand( iacRealtimeCmd := scanIacRealtimeSubCommand(jwtWrapper, featureFlagsWrapper) - addFormatFlagToMultipleCommands( + commandutils.AddFormatFlagToMultipleCommands( []*cobra.Command{listScansCmd, showScanCmd, workflowScanCmd}, printer.FormatTable, printer.FormatList, printer.FormatJSON, ) @@ -3047,7 +3048,7 @@ func runListScansCommand(scansWrapper wrappers.ScansWrapper, sastMetadataWrapper if err != nil { return err } - err = printByFormat(cmd, views) + err = commandutils.PrintByFormat(cmd, views) if err != nil { return err } @@ -3073,7 +3074,7 @@ func runGetScanByIDCommand(scansWrapper wrappers.ScansWrapper) func(cmd *cobra.C if errorModel != nil { return errors.Errorf("%s: CODE: %d, %s", failedGetting, errorModel.Code, errorModel.Message) } else if scanResponseModel != nil { - err = printByFormat(cmd, toScanView(scanResponseModel)) + err = commandutils.PrintByFormat(cmd, toScanView(scanResponseModel)) if err != nil { return err } @@ -3099,7 +3100,7 @@ func runScanWorkflowByIDCommand(scansWrapper wrappers.ScansWrapper) func(cmd *co if errorModel != nil { return errors.Errorf("%s: CODE: %d, %s", failedGetting, errorModel.Code, errorModel.Message) } else if taskResponseModel != nil { - err = printByFormat(cmd, taskResponseModel) + err = commandutils.PrintByFormat(cmd, taskResponseModel) if err != nil { return err } From 61fd3b2538d79dbf48eec50acae8e627a441265c Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Thu, 15 Jan 2026 09:09:34 +0200 Subject: [PATCH 23/28] use simpler GetFilters function --- internal/commands/commandutils/commandutils.go | 18 ++++++++++++++++++ internal/commands/environments.go | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/internal/commands/commandutils/commandutils.go b/internal/commands/commandutils/commandutils.go index c6289937a..de9528fda 100644 --- a/internal/commands/commandutils/commandutils.go +++ b/internal/commands/commandutils/commandutils.go @@ -1,7 +1,9 @@ package commandutils import ( + "errors" "fmt" + "strings" "github.com/checkmarx/ast-cli/internal/commands/util/printer" "github.com/checkmarx/ast-cli/internal/params" @@ -25,3 +27,19 @@ func PrintByFormat(cmd *cobra.Command, view interface{}) error { f, _ := cmd.Flags().GetString(params.FormatFlag) return printer.Print(cmd.OutOrStdout(), view, f) } + +func GetFilters(cmd *cobra.Command) (map[string]string, error) { + filters, _ := cmd.Flags().GetStringSlice(params.FilterFlag) + allFilters := make(map[string]string) + for _, filter := range filters { + filterKeyVal := strings.Split(filter, "=") + if len(filterKeyVal) != params.KeyValuePairSize { + return nil, errors.New("Invalid filters. Filters should be in a KEY=VALUE format") + } + allFilters[filterKeyVal[0]] = strings.Replace( + filterKeyVal[1], ";", ",", + strings.Count(filterKeyVal[1], ";"), + ) + } + return allFilters, nil +} diff --git a/internal/commands/environments.go b/internal/commands/environments.go index e0e8cb31e..dd65723ef 100644 --- a/internal/commands/environments.go +++ b/internal/commands/environments.go @@ -84,7 +84,7 @@ func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper var allEnvironmentsModel *wrappers.EnvironmentsCollectionResponseModel var errorModel *wrappers.ErrorModel - params, err := getFilters(cmd) + params, err := commandutils.GetFilters(cmd) if err != nil { return errors.Wrapf(err, "%s", failedGettingEnvironments) } From 8d431ea83f2a5720acf64da2005b854e3a8c4ff3 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Thu, 15 Jan 2026 09:36:19 +0200 Subject: [PATCH 24/28] rename environment to dast-environment --- cmd/main.go | 6 +- internal/commands/dast-environments_test.go | 35 +++++++++++ .../dast-environments.go} | 34 +++++----- internal/commands/environments_test.go | 35 ----------- internal/commands/root.go | 7 ++- internal/commands/root_test.go | 4 +- internal/params/binds.go | 2 +- internal/params/envs.go | 2 +- internal/params/keys.go | 2 +- ...ents-http.go => dast-environments-http.go} | 22 +++---- internal/wrappers/dast-environments.go | 62 +++++++++++++++++++ internal/wrappers/environments.go | 62 ------------------- ...ents-mock.go => dast-environments-mock.go} | 10 +-- test/integration/util_command.go | 6 +- 14 files changed, 145 insertions(+), 144 deletions(-) create mode 100644 internal/commands/dast-environments_test.go rename internal/commands/{environments.go => dast/dast-environments.go} (72%) delete mode 100644 internal/commands/environments_test.go rename internal/wrappers/{environments-http.go => dast-environments-http.go} (53%) create mode 100644 internal/wrappers/dast-environments.go delete mode 100644 internal/wrappers/environments.go rename internal/wrappers/mock/{environments-mock.go => dast-environments-mock.go} (54%) diff --git a/cmd/main.go b/cmd/main.go index 3b17cecd3..53d2ae664 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -59,7 +59,7 @@ func main() { accessManagementPath := viper.GetString(params.AccessManagementPathKey) byorPath := viper.GetString(params.ByorPathKey) realtimeScannerPath := viper.GetString(params.RealtimeScannerPathKey) - environmentsPath := viper.GetString(params.EnvironmentsPathKey) + dastEnvironmentsPath := viper.GetString(params.DastEnvironmentsPathKey) customStatesWrapper := wrappers.NewCustomStatesHTTPWrapper() scansWrapper := wrappers.NewHTTPScansWrapper(scans) @@ -98,7 +98,7 @@ func main() { containerResolverWrapper := wrappers.NewContainerResolverWrapper() realTimeWrapper := wrappers.NewRealtimeScannerHTTPWrapper(realtimeScannerPath, jwtWrapper, featureFlagsWrapper) telemetryWrapper := wrappers.NewHTTPTelemetryAIWrapper(realtimeScannerPath) - environmentsWrapper := wrappers.NewHTTPEnvironmentsWrapper(environmentsPath) + dastEnvironmentsWrapper := wrappers.NewHTTPDastEnvironmentsWrapper(dastEnvironmentsPath) astCli := commands.NewAstCLI( applicationsWrapper, @@ -138,7 +138,7 @@ func main() { containerResolverWrapper, realTimeWrapper, telemetryWrapper, - environmentsWrapper, + dastEnvironmentsWrapper, ) exitListener() err = astCli.Execute() diff --git a/internal/commands/dast-environments_test.go b/internal/commands/dast-environments_test.go new file mode 100644 index 000000000..b7ed64338 --- /dev/null +++ b/internal/commands/dast-environments_test.go @@ -0,0 +1,35 @@ +//go:build !integration + +package commands + +import ( + "testing" +) + +func TestDastEnvironmentsHelp(t *testing.T) { + execCmdNilAssertion(t, "help", "dast-environments") +} + +func TestDastEnvironmentsNoSub(t *testing.T) { + execCmdNilAssertion(t, "dast-environments") +} + +func TestDastEnvironmentsList(t *testing.T) { + execCmdNilAssertion(t, "dast-environments", "list") +} + +func TestDastEnvironmentsListWithFormat(t *testing.T) { + execCmdNilAssertion(t, "dast-environments", "list", "--format", "json") +} + +func TestDastEnvironmentsListWithFilters(t *testing.T) { + execCmdNilAssertion(t, "dast-environments", "list", "--filter", "from=1,to=10") +} + +func TestDastEnvironmentsListWithSearch(t *testing.T) { + execCmdNilAssertion(t, "dast-environments", "list", "--filter", "search=test") +} + +func TestDastEnvironmentsListWithSort(t *testing.T) { + execCmdNilAssertion(t, "dast-environments", "list", "--filter", "sort=domain:asc") +} diff --git a/internal/commands/environments.go b/internal/commands/dast/dast-environments.go similarity index 72% rename from internal/commands/environments.go rename to internal/commands/dast/dast-environments.go index dd65723ef..c8c788f12 100644 --- a/internal/commands/environments.go +++ b/internal/commands/dast/dast-environments.go @@ -1,4 +1,4 @@ -package commands +package dast import ( "fmt" @@ -32,10 +32,10 @@ var ( ) ) -// NewEnvironmentsCommand creates the environments command -func NewEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) *cobra.Command { +// NewDastEnvironmentsCommand creates the DAST environments command +func NewDastEnvironmentsCommand(dastEnvironmentsWrapper wrappers.DastEnvironmentsWrapper) *cobra.Command { environmentsCmd := &cobra.Command{ - Use: "environments", + Use: "dast-environments", Short: "Manage DAST environments", Long: "The environments command enables the ability to manage DAST environments in Checkmarx One", Annotations: map[string]string{ @@ -47,14 +47,14 @@ func NewEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) *c }, } - listEnvironmentsCmd := &cobra.Command{ + listDastEnvironmentsCmd := &cobra.Command{ Use: "list", Short: "List all DAST environments in the system", Example: heredoc.Doc( ` - $ cx environments list --format list - $ cx environments list --filter "from=1,to=10" - $ cx environments list --filter "search=production,sort=created" + $ cx dast-environments list --format list + $ cx dast-environments list --filter "from=1,to=10" + $ cx dast-environments list --filter "search=production,sort=created" `, ), Annotations: map[string]string{ @@ -64,24 +64,24 @@ func NewEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) *c `, ), }, - RunE: runListEnvironmentsCommand(environmentsWrapper), + RunE: runListDastEnvironmentsCommand(dastEnvironmentsWrapper), } - listEnvironmentsCmd.PersistentFlags().StringSlice(commonParams.FilterFlag, []string{}, filterEnvironmentsListFlagUsage) + listDastEnvironmentsCmd.PersistentFlags().StringSlice(commonParams.FilterFlag, []string{}, filterEnvironmentsListFlagUsage) commandutils.AddFormatFlagToMultipleCommands( - []*cobra.Command{listEnvironmentsCmd}, + []*cobra.Command{listDastEnvironmentsCmd}, printer.FormatTable, printer.FormatJSON, printer.FormatList, ) - environmentsCmd.AddCommand(listEnvironmentsCmd) + environmentsCmd.AddCommand(listDastEnvironmentsCmd) return environmentsCmd } -func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper) func(cmd *cobra.Command, args []string) error { +func runListDastEnvironmentsCommand(dastEnvironmentsWrapper wrappers.DastEnvironmentsWrapper) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - var allEnvironmentsModel *wrappers.EnvironmentsCollectionResponseModel + var allEnvironmentsModel *wrappers.DastEnvironmentsCollectionResponseModel var errorModel *wrappers.ErrorModel params, err := commandutils.GetFilters(cmd) @@ -91,7 +91,7 @@ func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper // The API expects: from, to, search, sort // from and to are pagination parameters (e.g., from=1, to=10 for first page) - allEnvironmentsModel, errorModel, err = environmentsWrapper.Get(params) + allEnvironmentsModel, errorModel, err = dastEnvironmentsWrapper.Get(params) if err != nil { return errors.Wrapf(err, "%s\n", failedGettingEnvironments) } @@ -109,7 +109,7 @@ func runListEnvironmentsCommand(environmentsWrapper wrappers.EnvironmentsWrapper } } -func toEnvironmentViews(models []wrappers.EnvironmentResponseModel) []environmentView { +func toEnvironmentViews(models []wrappers.DastEnvironmentResponseModel) []environmentView { result := make([]environmentView, len(models)) for i := 0; i < len(models); i++ { result[i] = toEnvironmentView(&models[i]) @@ -117,7 +117,7 @@ func toEnvironmentViews(models []wrappers.EnvironmentResponseModel) []environmen return result } -func toEnvironmentView(model *wrappers.EnvironmentResponseModel) environmentView { +func toEnvironmentView(model *wrappers.DastEnvironmentResponseModel) environmentView { return environmentView{ EnvironmentID: model.EnvironmentID, Domain: model.Domain, diff --git a/internal/commands/environments_test.go b/internal/commands/environments_test.go deleted file mode 100644 index fce6d174e..000000000 --- a/internal/commands/environments_test.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build !integration - -package commands - -import ( - "testing" -) - -func TestEnvironmentsHelp(t *testing.T) { - execCmdNilAssertion(t, "help", "environments") -} - -func TestEnvironmentsNoSub(t *testing.T) { - execCmdNilAssertion(t, "environments") -} - -func TestEnvironmentsList(t *testing.T) { - execCmdNilAssertion(t, "environments", "list") -} - -func TestEnvironmentsListWithFormat(t *testing.T) { - execCmdNilAssertion(t, "environments", "list", "--format", "json") -} - -func TestEnvironmentsListWithFilters(t *testing.T) { - execCmdNilAssertion(t, "environments", "list", "--filter", "from=1,to=10") -} - -func TestEnvironmentsListWithSearch(t *testing.T) { - execCmdNilAssertion(t, "environments", "list", "--filter", "search=test") -} - -func TestEnvironmentsListWithSort(t *testing.T) { - execCmdNilAssertion(t, "environments", "list", "--filter", "sort=domain:asc") -} diff --git a/internal/commands/root.go b/internal/commands/root.go index 4005f6bfc..2b1560b9d 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/MakeNowJust/heredoc" + "github.com/checkmarx/ast-cli/internal/commands/dast" "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/checkmarx/ast-cli/internal/commands/util/printer" "github.com/checkmarx/ast-cli/internal/logger" @@ -61,7 +62,7 @@ func NewAstCLI( containerResolverWrapper wrappers.ContainerResolverWrapper, realTimeWrapper wrappers.RealtimeScannerWrapper, telemetryWrapper wrappers.TelemetryWrapper, - environmentsWrapper wrappers.EnvironmentsWrapper, + dastEnvironmentsWrapper wrappers.DastEnvironmentsWrapper, ) *cobra.Command { // Create the root rootCmd := &cobra.Command{ @@ -188,7 +189,7 @@ func NewAstCLI( realTimeWrapper, ) projectCmd := NewProjectCommand(applicationsWrapper, projectsWrapper, groupsWrapper, accessManagementWrapper, featureFlagsWrapper) - environmentsCmd := NewEnvironmentsCommand(environmentsWrapper) + dastEnvironmentsCmd := dast.NewDastEnvironmentsCommand(dastEnvironmentsWrapper) resultsCmd := NewResultsCommand( resultsWrapper, @@ -239,7 +240,7 @@ func NewAstCLI( rootCmd.AddCommand( scanCmd, projectCmd, - environmentsCmd, + dastEnvironmentsCmd, resultsCmd, triageCmd, versionCmd, diff --git a/internal/commands/root_test.go b/internal/commands/root_test.go index 3b0e6d014..924807aa7 100644 --- a/internal/commands/root_test.go +++ b/internal/commands/root_test.go @@ -73,7 +73,7 @@ func createASTTestCommand() *cobra.Command { customStatesMockWrapper := &mock.CustomStatesMockWrapper{} realTimeWrapper := &mock.RealtimeScannerMockWrapper{} telemetryWrapper := &mock.TelemetryMockWrapper{} - environmentsWrapper := &mock.EnvironmentsMockWrapper{} + dastEnvironmentsWrapper := &mock.DastEnvironmentsMockWrapper{} return NewAstCLI( applicationWrapper, scansMockWrapper, @@ -112,7 +112,7 @@ func createASTTestCommand() *cobra.Command { containerResolverMockWrapper, realTimeWrapper, telemetryWrapper, - environmentsWrapper, + dastEnvironmentsWrapper, ) } diff --git a/internal/params/binds.go b/internal/params/binds.go index 79a9b0319..fe8068701 100644 --- a/internal/params/binds.go +++ b/internal/params/binds.go @@ -82,7 +82,7 @@ var EnvVarsBinds = []struct { {RiskManagementPathKey, RiskManagementPathEnv, "api/risk-management/projects/%s/results?scanID=%s"}, {ConfigFilePathKey, ConfigFilePathEnv, ""}, {RealtimeScannerPathKey, RealtimeScannerPathEnv, "api/realtime-scanner"}, - {EnvironmentsPathKey, EnvironmentsPathEnv, "api/dast/scans/environments"}, + {DastEnvironmentsPathKey, DastEnvironmentsPathEnv, "api/dast/scans/environments"}, {StartMultiPartUploadPathKey, StartMultiPartUploadPathEnv, "api/uploads/start-multipart-upload"}, {MultipartPresignedPathKey, MultipartPresignedPathEnv, "api/uploads/multipart-presigned"}, {CompleteMultiPartUploadPathKey, CompleteMultipartUploadPathEnv, "api/uploads/complete-multipart-upload"}, diff --git a/internal/params/envs.go b/internal/params/envs.go index 976ac62f0..093f93d9f 100644 --- a/internal/params/envs.go +++ b/internal/params/envs.go @@ -84,7 +84,7 @@ const ( RiskManagementPathEnv = "CX_RISK_MANAGEMENT_PATH" ConfigFilePathEnv = "CX_CONFIG_FILE_PATH" RealtimeScannerPathEnv = "CX_REALTIME_SCANNER_PATH" - EnvironmentsPathEnv = "CX_ENVIRONMENTS_PATH" + DastEnvironmentsPathEnv = "CX_DAST_ENVIRONMENTS_PATH" UniqueIDEnv = "CX_UNIQUE_ID" StartMultiPartUploadPathEnv = "CX_START_MULTIPART_UPLOAD_PATH" MultipartPresignedPathEnv = "CX_MULTIPART_PRESIGNED_URL_PATH" diff --git a/internal/params/keys.go b/internal/params/keys.go index c440f8954..1c4e7ccec 100644 --- a/internal/params/keys.go +++ b/internal/params/keys.go @@ -83,7 +83,7 @@ var ( RiskManagementPathKey = strings.ToLower(RiskManagementPathEnv) ConfigFilePathKey = strings.ToLower(ConfigFilePathEnv) RealtimeScannerPathKey = strings.ToLower(RealtimeScannerPathEnv) - EnvironmentsPathKey = strings.ToLower(EnvironmentsPathEnv) + DastEnvironmentsPathKey = strings.ToLower(DastEnvironmentsPathEnv) UniqueIDConfigKey = strings.ToLower(UniqueIDEnv) StartMultiPartUploadPathKey = strings.ToLower(StartMultiPartUploadPathEnv) MultipartPresignedPathKey = strings.ToLower(MultipartPresignedPathEnv) diff --git a/internal/wrappers/environments-http.go b/internal/wrappers/dast-environments-http.go similarity index 53% rename from internal/wrappers/environments-http.go rename to internal/wrappers/dast-environments-http.go index 2b0608549..20b717ddb 100644 --- a/internal/wrappers/environments-http.go +++ b/internal/wrappers/dast-environments-http.go @@ -10,23 +10,23 @@ import ( ) const ( - failedToParseEnvironments = "Failed to parse environments" + failedToParseDastEnvironments = "Failed to parse DAST environments" ) -// EnvironmentsHTTPWrapper implements the EnvironmentsWrapper interface -type EnvironmentsHTTPWrapper struct { +// DastEnvironmentsHTTPWrapper implements the DastEnvironmentsWrapper interface +type DastEnvironmentsHTTPWrapper struct { path string } -// NewHTTPEnvironmentsWrapper creates a new HTTP environments wrapper -func NewHTTPEnvironmentsWrapper(path string) EnvironmentsWrapper { - return &EnvironmentsHTTPWrapper{ +// NewHTTPDastEnvironmentsWrapper creates a new HTTP DAST environments wrapper +func NewHTTPDastEnvironmentsWrapper(path string) DastEnvironmentsWrapper { + return &DastEnvironmentsHTTPWrapper{ path: path, } } -// Get retrieves environments with optional query parameters -func (e *EnvironmentsHTTPWrapper) Get(params map[string]string) (*EnvironmentsCollectionResponseModel, *ErrorModel, error) { +// Get retrieves DAST environments with optional query parameters +func (e *DastEnvironmentsHTTPWrapper) Get(params map[string]string) (*DastEnvironmentsCollectionResponseModel, *ErrorModel, error) { clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) resp, err := SendHTTPRequestWithQueryParams(http.MethodGet, e.path, params, nil, clientTimeout) @@ -45,14 +45,14 @@ func (e *EnvironmentsHTTPWrapper) Get(params map[string]string) (*EnvironmentsCo errorModel := ErrorModel{} err = decoder.Decode(&errorModel) if err != nil { - return nil, nil, errors.Wrapf(err, failedToParseEnvironments) + return nil, nil, errors.Wrapf(err, failedToParseDastEnvironments) } return nil, &errorModel, nil case http.StatusOK: - model := EnvironmentsCollectionResponseModel{} + model := DastEnvironmentsCollectionResponseModel{} err = decoder.Decode(&model) if err != nil { - return nil, nil, errors.Wrapf(err, failedToParseEnvironments) + return nil, nil, errors.Wrapf(err, failedToParseDastEnvironments) } return &model, nil, nil default: diff --git a/internal/wrappers/dast-environments.go b/internal/wrappers/dast-environments.go new file mode 100644 index 000000000..3cdba6b73 --- /dev/null +++ b/internal/wrappers/dast-environments.go @@ -0,0 +1,62 @@ +package wrappers + +import "encoding/json" + +// DastEnvironmentsWrapper defines the interface for DAST environments operations +type DastEnvironmentsWrapper interface { + // Get retrieves environments with optional query parameters (from, to, search, sort) + Get(params map[string]string) (*DastEnvironmentsCollectionResponseModel, *ErrorModel, error) +} + +// DastEnvironmentsCollectionResponseModel represents the response from the DAST environments API +type DastEnvironmentsCollectionResponseModel struct { + Environments []DastEnvironmentResponseModel `json:"environments"` + MisconfiguredCount int `json:"misconfiguredCount"` + TotalItems int `json:"totalItems"` + ZrokHost string `json:"zrokHost"` +} + +// DastEnvironmentResponseModel represents a single DAST environment +type DastEnvironmentResponseModel struct { + EnvironmentID string `json:"environmentId"` + TunnelID string `json:"tunnelId"` + Created string `json:"created"` + Domain string `json:"domain"` + URL string `json:"url"` + ScanType string `json:"scanType"` + ProjectIds []string `json:"projectIds"` + Tags []string `json:"tags"` + Groups []string `json:"groups"` + Applications []DastEnvironmentApp `json:"applications"` + RiskLevel RiskLevel `json:"riskLevel"` + RiskRating string `json:"riskRating"` + AlertRiskLevel RiskLevel `json:"alertRiskLevel"` + LastScanID string `json:"lastScanID"` + LastScanTime string `json:"lastScanTime"` + LastStatus string `json:"lastStatus"` + AuthSuccess bool `json:"authSuccess"` + IsPublic bool `json:"isPublic"` + AuthMethod string `json:"authMethod"` + LastAuthUUID string `json:"lastAuthUUID"` + LastAuthSuccess bool `json:"lastAuthSuccess"` + Settings json.RawMessage `json:"settings"` // Keep as raw JSON + HasReport bool `json:"hasReport"` + HasAuth bool `json:"hasAuth"` + TunnelState string `json:"tunnelState"` + ScanConfig json.RawMessage `json:"scanConfig"` // Keep as raw JSON +} + +// DastEnvironmentApp represents an application associated with a DAST environment +type DastEnvironmentApp struct { + ApplicationID string `json:"applicationId"` + IsPrimary bool `json:"isPrimary"` +} + +// RiskLevel represents risk counts by severity +type RiskLevel struct { + CriticalCount int `json:"criticalCount"` + HighCount int `json:"highCount"` + MediumCount int `json:"mediumCount"` + LowCount int `json:"lowCount"` + InfoCount int `json:"infoCount"` +} diff --git a/internal/wrappers/environments.go b/internal/wrappers/environments.go deleted file mode 100644 index eb489cae3..000000000 --- a/internal/wrappers/environments.go +++ /dev/null @@ -1,62 +0,0 @@ -package wrappers - -import "encoding/json" - -// EnvironmentsWrapper defines the interface for environments operations -type EnvironmentsWrapper interface { - // Get retrieves environments with optional query parameters (from, to, search, sort) - Get(params map[string]string) (*EnvironmentsCollectionResponseModel, *ErrorModel, error) -} - -// EnvironmentsCollectionResponseModel represents the response from the environments API -type EnvironmentsCollectionResponseModel struct { - Environments []EnvironmentResponseModel `json:"environments"` - MisconfiguredCount int `json:"misconfiguredCount"` - TotalItems int `json:"totalItems"` - ZrokHost string `json:"zrokHost"` -} - -// EnvironmentResponseModel represents a single environment -type EnvironmentResponseModel struct { - EnvironmentID string `json:"environmentId"` - TunnelID string `json:"tunnelId"` - Created string `json:"created"` - Domain string `json:"domain"` - URL string `json:"url"` - ScanType string `json:"scanType"` - ProjectIds []string `json:"projectIds"` - Tags []string `json:"tags"` - Groups []string `json:"groups"` - Applications []EnvironmentApp `json:"applications"` - RiskLevel RiskLevel `json:"riskLevel"` - RiskRating string `json:"riskRating"` - AlertRiskLevel RiskLevel `json:"alertRiskLevel"` - LastScanID string `json:"lastScanID"` - LastScanTime string `json:"lastScanTime"` - LastStatus string `json:"lastStatus"` - AuthSuccess bool `json:"authSuccess"` - IsPublic bool `json:"isPublic"` - AuthMethod string `json:"authMethod"` - LastAuthUUID string `json:"lastAuthUUID"` - LastAuthSuccess bool `json:"lastAuthSuccess"` - Settings json.RawMessage `json:"settings"` // Keep as raw JSON - HasReport bool `json:"hasReport"` - HasAuth bool `json:"hasAuth"` - TunnelState string `json:"tunnelState"` - ScanConfig json.RawMessage `json:"scanConfig"` // Keep as raw JSON -} - -// EnvironmentApp represents an application associated with an environment -type EnvironmentApp struct { - ApplicationID string `json:"applicationId"` - IsPrimary bool `json:"isPrimary"` -} - -// RiskLevel represents risk counts by severity -type RiskLevel struct { - CriticalCount int `json:"criticalCount"` - HighCount int `json:"highCount"` - MediumCount int `json:"mediumCount"` - LowCount int `json:"lowCount"` - InfoCount int `json:"infoCount"` -} diff --git a/internal/wrappers/mock/environments-mock.go b/internal/wrappers/mock/dast-environments-mock.go similarity index 54% rename from internal/wrappers/mock/environments-mock.go rename to internal/wrappers/mock/dast-environments-mock.go index 1dafb953f..9af4cae1d 100644 --- a/internal/wrappers/mock/environments-mock.go +++ b/internal/wrappers/mock/dast-environments-mock.go @@ -2,13 +2,13 @@ package mock import "github.com/checkmarx/ast-cli/internal/wrappers" -// EnvironmentsMockWrapper is a mock implementation of EnvironmentsWrapper -type EnvironmentsMockWrapper struct{} +// DastEnvironmentsMockWrapper is a mock implementation of DastEnvironmentsWrapper +type DastEnvironmentsMockWrapper struct{} // Get mocks the Get method -func (e *EnvironmentsMockWrapper) Get(params map[string]string) (*wrappers.EnvironmentsCollectionResponseModel, *wrappers.ErrorModel, error) { - return &wrappers.EnvironmentsCollectionResponseModel{ - Environments: []wrappers.EnvironmentResponseModel{ +func (e *DastEnvironmentsMockWrapper) Get(params map[string]string) (*wrappers.DastEnvironmentsCollectionResponseModel, *wrappers.ErrorModel, error) { + return &wrappers.DastEnvironmentsCollectionResponseModel{ + Environments: []wrappers.DastEnvironmentResponseModel{ { EnvironmentID: "test-env-id", Domain: "test-domain", diff --git a/test/integration/util_command.go b/test/integration/util_command.go index 22ae94ca9..57de7958b 100644 --- a/test/integration/util_command.go +++ b/test/integration/util_command.go @@ -89,7 +89,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { accessManagementPath := viper.GetString(params.AccessManagementPathKey) byorPath := viper.GetString(params.ByorPathKey) realtimeScannerPath := viper.GetString(params.RealtimeScannerPathKey) - environmentsPath := viper.GetString(params.EnvironmentsPathKey) + dastEnvironmentsPath := viper.GetString(params.DastEnvironmentsPathKey) scansWrapper := wrappers.NewHTTPScansWrapper(scans) applicationsWrapper := wrappers.NewApplicationsHTTPWrapper(applications) @@ -128,7 +128,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { containerResolverWrapper := wrappers.NewContainerResolverWrapper() realtimeScannerWrapper := wrappers.NewRealtimeScannerHTTPWrapper(realtimeScannerPath, jwtWrapper, featureFlagsWrapper) telemetryWrapper := wrappers.NewHTTPTelemetryAIWrapper(realtimeScannerPath) - environmentsWrapper := wrappers.NewHTTPEnvironmentsWrapper(environmentsPath) + dastEnvironmentsWrapper := wrappers.NewHTTPDastEnvironmentsWrapper(dastEnvironmentsPath) astCli := commands.NewAstCLI( applicationsWrapper, @@ -168,7 +168,7 @@ func createASTIntegrationTestCommand(t *testing.T) *cobra.Command { containerResolverWrapper, realtimeScannerWrapper, telemetryWrapper, - environmentsWrapper, + dastEnvironmentsWrapper, ) return astCli } From e3b3e4837a8d90cb939fe20ec1761d5bd5f701ea Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Thu, 15 Jan 2026 09:41:00 +0200 Subject: [PATCH 25/28] move tests to package --- internal/commands/dast-environments_test.go | 35 ------------- .../commands/dast/dast-environments_test.go | 52 +++++++++++++++++++ 2 files changed, 52 insertions(+), 35 deletions(-) delete mode 100644 internal/commands/dast-environments_test.go create mode 100644 internal/commands/dast/dast-environments_test.go diff --git a/internal/commands/dast-environments_test.go b/internal/commands/dast-environments_test.go deleted file mode 100644 index b7ed64338..000000000 --- a/internal/commands/dast-environments_test.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build !integration - -package commands - -import ( - "testing" -) - -func TestDastEnvironmentsHelp(t *testing.T) { - execCmdNilAssertion(t, "help", "dast-environments") -} - -func TestDastEnvironmentsNoSub(t *testing.T) { - execCmdNilAssertion(t, "dast-environments") -} - -func TestDastEnvironmentsList(t *testing.T) { - execCmdNilAssertion(t, "dast-environments", "list") -} - -func TestDastEnvironmentsListWithFormat(t *testing.T) { - execCmdNilAssertion(t, "dast-environments", "list", "--format", "json") -} - -func TestDastEnvironmentsListWithFilters(t *testing.T) { - execCmdNilAssertion(t, "dast-environments", "list", "--filter", "from=1,to=10") -} - -func TestDastEnvironmentsListWithSearch(t *testing.T) { - execCmdNilAssertion(t, "dast-environments", "list", "--filter", "search=test") -} - -func TestDastEnvironmentsListWithSort(t *testing.T) { - execCmdNilAssertion(t, "dast-environments", "list", "--filter", "sort=domain:asc") -} diff --git a/internal/commands/dast/dast-environments_test.go b/internal/commands/dast/dast-environments_test.go new file mode 100644 index 000000000..747884fdc --- /dev/null +++ b/internal/commands/dast/dast-environments_test.go @@ -0,0 +1,52 @@ +//go:build !integration + +package dast + +import ( + "testing" + + "github.com/checkmarx/ast-cli/internal/wrappers/mock" + "gotest.tools/assert" +) + +func createTestCommand(args ...string) error { + cmd := NewDastEnvironmentsCommand(&mock.DastEnvironmentsMockWrapper{}) + cmd.SetArgs(args) + return cmd.Execute() +} + +func TestDastEnvironmentsHelp(t *testing.T) { + err := createTestCommand("--help") + assert.NilError(t, err) +} + +func TestDastEnvironmentsNoSub(t *testing.T) { + err := createTestCommand() + assert.NilError(t, err) +} + +func TestDastEnvironmentsList(t *testing.T) { + err := createTestCommand("list") + assert.NilError(t, err) +} + +func TestDastEnvironmentsListWithFormat(t *testing.T) { + err := createTestCommand("list", "--format", "json") + assert.NilError(t, err) +} + +func TestDastEnvironmentsListWithFilters(t *testing.T) { + err := createTestCommand("list", "--filter", "from=1,to=10") + assert.NilError(t, err) +} + +func TestDastEnvironmentsListWithSearch(t *testing.T) { + err := createTestCommand("list", "--filter", "search=test") + assert.NilError(t, err) +} + +func TestDastEnvironmentsListWithSort(t *testing.T) { + err := createTestCommand("list", "--filter", "sort=domain:asc") + assert.NilError(t, err) +} + From ebe7323394baeedaec886f946882f42e58dcf456 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Thu, 15 Jan 2026 10:16:36 +0200 Subject: [PATCH 26/28] rename --- internal/commands/dast/dast-environments.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/commands/dast/dast-environments.go b/internal/commands/dast/dast-environments.go index c8c788f12..824ec309c 100644 --- a/internal/commands/dast/dast-environments.go +++ b/internal/commands/dast/dast-environments.go @@ -19,8 +19,8 @@ const ( ) var ( - filterEnvironmentsListFlagUsage = fmt.Sprintf( - "Filter the list of environments. Use ';' as the delimiter for arrays. Available filters are: %s", + filterDastEnvironmentsListFlagUsage = fmt.Sprintf( + "Filter the list of DAST environments. Use ';' as the delimiter for arrays. Available filters are: %s", strings.Join( []string{ commonParams.FromQueryParam, @@ -66,7 +66,7 @@ func NewDastEnvironmentsCommand(dastEnvironmentsWrapper wrappers.DastEnvironment }, RunE: runListDastEnvironmentsCommand(dastEnvironmentsWrapper), } - listDastEnvironmentsCmd.PersistentFlags().StringSlice(commonParams.FilterFlag, []string{}, filterEnvironmentsListFlagUsage) + listDastEnvironmentsCmd.PersistentFlags().StringSlice(commonParams.FilterFlag, []string{}, filterDastEnvironmentsListFlagUsage) commandutils.AddFormatFlagToMultipleCommands( []*cobra.Command{listDastEnvironmentsCmd}, From ca414a90596a7e0c42b720bec5367532dddff5ad Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Thu, 15 Jan 2026 10:17:16 +0200 Subject: [PATCH 27/28] rename --- internal/commands/dast/dast-environments.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/commands/dast/dast-environments.go b/internal/commands/dast/dast-environments.go index 824ec309c..ce282fe4d 100644 --- a/internal/commands/dast/dast-environments.go +++ b/internal/commands/dast/dast-environments.go @@ -15,7 +15,7 @@ import ( ) const ( - failedGettingEnvironments = "Failed getting environments" + failedGettingDastEnvironments = "Failed getting DAST environments" ) var ( @@ -86,19 +86,19 @@ func runListDastEnvironmentsCommand(dastEnvironmentsWrapper wrappers.DastEnviron params, err := commandutils.GetFilters(cmd) if err != nil { - return errors.Wrapf(err, "%s", failedGettingEnvironments) + return errors.Wrapf(err, "%s", failedGettingDastEnvironments) } // The API expects: from, to, search, sort // from and to are pagination parameters (e.g., from=1, to=10 for first page) allEnvironmentsModel, errorModel, err = dastEnvironmentsWrapper.Get(params) if err != nil { - return errors.Wrapf(err, "%s\n", failedGettingEnvironments) + return errors.Wrapf(err, "%s\n", failedGettingDastEnvironments) } // Checking the response if errorModel != nil { - return errors.Errorf(services.ErrorCodeFormat, failedGettingEnvironments, errorModel.Code, errorModel.Message) + return errors.Errorf(services.ErrorCodeFormat, failedGettingDastEnvironments, errorModel.Code, errorModel.Message) } else if allEnvironmentsModel != nil && allEnvironmentsModel.Environments != nil { err = commandutils.PrintByFormat(cmd, toEnvironmentViews(allEnvironmentsModel.Environments)) if err != nil { From 5b8d645c52b644bf76ec81c10f5a4fc4b416a2a2 Mon Sep 17 00:00:00 2001 From: Ronit Steinberg Date: Thu, 15 Jan 2026 10:57:57 +0200 Subject: [PATCH 28/28] lint --- internal/commands/commandutils/commandutils.go | 2 +- internal/commands/dast/dast-environments_test.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/commands/commandutils/commandutils.go b/internal/commands/commandutils/commandutils.go index de9528fda..64fb4b143 100644 --- a/internal/commands/commandutils/commandutils.go +++ b/internal/commands/commandutils/commandutils.go @@ -34,7 +34,7 @@ func GetFilters(cmd *cobra.Command) (map[string]string, error) { for _, filter := range filters { filterKeyVal := strings.Split(filter, "=") if len(filterKeyVal) != params.KeyValuePairSize { - return nil, errors.New("Invalid filters. Filters should be in a KEY=VALUE format") + return nil, errors.New("invalid filters, filters should be in a KEY=VALUE format") } allFilters[filterKeyVal[0]] = strings.Replace( filterKeyVal[1], ";", ",", diff --git a/internal/commands/dast/dast-environments_test.go b/internal/commands/dast/dast-environments_test.go index 747884fdc..715ad6997 100644 --- a/internal/commands/dast/dast-environments_test.go +++ b/internal/commands/dast/dast-environments_test.go @@ -49,4 +49,3 @@ func TestDastEnvironmentsListWithSort(t *testing.T) { err := createTestCommand("list", "--filter", "sort=domain:asc") assert.NilError(t, err) } -