Skip to content

Commit c1dca0b

Browse files
Update secrets licensing for pre-commit and pre-receive (AST-104600) (#1290)
Updated secrets licensing for pre-commit and pre-receive
1 parent f3a5174 commit c1dca0b

File tree

7 files changed

+123
-47
lines changed

7 files changed

+123
-47
lines changed

internal/commands/hooks.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
// NewHooksCommand creates the hooks command with pre-commit subcommand
12-
func NewHooksCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
12+
func NewHooksCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
1313
hooksCmd := &cobra.Command{
1414
Use: "hooks",
1515
Short: "Manage Git hooks",
@@ -31,19 +31,27 @@ func NewHooksCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
3131
}
3232

3333
// Add pre-commit and pre-receive subcommand
34-
hooksCmd.AddCommand(PreCommitCommand(jwtWrapper))
35-
hooksCmd.AddCommand(PreReceiveCommand(jwtWrapper))
34+
hooksCmd.AddCommand(PreCommitCommand(jwtWrapper, featureFlagsWrapper))
35+
hooksCmd.AddCommand(PreReceiveCommand(jwtWrapper, featureFlagsWrapper))
3636

3737
return hooksCmd
3838
}
3939

40-
func validateLicense(jwtWrapper wrappers.JWTWrapper) error {
41-
allowed, err := jwtWrapper.IsAllowedEngine(params.EnterpriseSecretsLabel)
40+
func validateLicense(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) error {
41+
scsLicensingV2Flag, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.ScsLicensingV2Enabled)
42+
var licenseName string
43+
if scsLicensingV2Flag.Status {
44+
licenseName = params.SecretDetectionLabel
45+
} else {
46+
licenseName = params.EnterpriseSecretsLabel
47+
}
48+
49+
allowed, err := jwtWrapper.IsAllowedEngine(licenseName)
4250
if err != nil {
4351
return errors.Wrapf(err, "Failed checking license")
4452
}
4553
if !allowed {
46-
return errors.New("Error: License validation failed. Please verify your CxOne license includes Enterprise Secrets.")
54+
return errors.Errorf("Error: License validation failed. Please verify your CxOne license includes %s.", licenseName)
4755
}
4856
return nil
4957
}

internal/commands/pre-receive.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const (
1515
SuccessFullSecretsLicenceValidation = "License for pre-receive secret detection has been validated successfully"
1616
)
1717

18-
func PreReceiveCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
18+
func PreReceiveCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
1919
preReceiveCmd := &cobra.Command{
2020
Use: "pre-receive",
2121
Short: "Manage pre-receive hooks and run secret detection scans",
@@ -27,7 +27,7 @@ func PreReceiveCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
2727
),
2828
}
2929
preReceiveCmd.AddCommand(scanSecretsPreReceiveCommand())
30-
preReceiveCmd.AddCommand(validateSecretsLicence(jwtWrapper))
30+
preReceiveCmd.AddCommand(validateSecretsLicence(jwtWrapper, featureFlagsWrapper))
3131

3232
return preReceiveCmd
3333
}
@@ -54,7 +54,7 @@ func scanSecretsPreReceiveCommand() *cobra.Command {
5454
return scanPrereceiveCmd
5555
}
5656

57-
func validateSecretsLicence(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
57+
func validateSecretsLicence(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
5858
validateLicence := &cobra.Command{
5959
Use: "validate",
6060
Short: "Validates the license for pre-receive secret detection",
@@ -64,19 +64,27 @@ func validateSecretsLicence(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
6464
$ cx hooks pre-receive validate
6565
`,
6666
),
67-
RunE: checkLicence(jwtWrapper),
67+
RunE: checkLicence(jwtWrapper, featureFlagsWrapper),
6868
}
6969
return validateLicence
7070
}
7171

72-
func checkLicence(jwtWrapper wrappers.JWTWrapper) func(cmd *cobra.Command, args []string) error {
72+
func checkLicence(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) func(cmd *cobra.Command, args []string) error {
7373
return func(cmd *cobra.Command, args []string) error {
74-
isAllowed, err := jwtWrapper.IsAllowedEngine(params.EnterpriseSecretsLabel)
74+
scsLicensingV2Flag, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.ScsLicensingV2Enabled)
75+
var licenseName string
76+
if scsLicensingV2Flag.Status {
77+
licenseName = params.SecretDetectionLabel
78+
} else {
79+
licenseName = params.EnterpriseSecretsLabel
80+
}
81+
82+
isAllowed, err := jwtWrapper.IsAllowedEngine(licenseName)
7583
if err != nil {
7684
log.Fatalf("%s: %s", "Failed the licence check", err)
7785
}
7886
if !isAllowed {
79-
log.Fatalf("Error: License validation failed. Please ensure that your Checkmarx One license includes Enterprise Secrets")
87+
log.Fatalf("Error: License validation failed. Please ensure that your Checkmarx One license includes %s", licenseName)
8088
}
8189
_, _ = fmt.Fprintln(cmd.OutOrStdout(), SuccessFullSecretsLicenceValidation)
8290
return nil

internal/commands/pre_commit.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
// PreCommitCommand creates the pre-commit subcommand
1414

15-
func PreCommitCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
15+
func PreCommitCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
1616
preCommitCmd := &cobra.Command{
1717
Use: "pre-commit",
1818
Short: "Manage pre-commit hooks and run secret detection scans",
@@ -26,19 +26,19 @@ func PreCommitCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
2626
}
2727
preCommitCmd.PersistentFlags().Bool("global", false, "Install the hook globally for all repositories")
2828

29-
preCommitCmd.AddCommand(secretsInstallGitHookCommand(jwtWrapper))
30-
preCommitCmd.AddCommand(secretsUninstallGitHookCommand(jwtWrapper))
31-
preCommitCmd.AddCommand(secretsUpdateGitHookCommand(jwtWrapper))
32-
preCommitCmd.AddCommand(secretsScanCommand(jwtWrapper))
33-
preCommitCmd.AddCommand(secretsIgnoreCommand(jwtWrapper))
29+
preCommitCmd.AddCommand(secretsInstallGitHookCommand(jwtWrapper, featureFlagsWrapper))
30+
preCommitCmd.AddCommand(secretsUninstallGitHookCommand())
31+
preCommitCmd.AddCommand(secretsUpdateGitHookCommand(jwtWrapper, featureFlagsWrapper))
32+
preCommitCmd.AddCommand(secretsScanCommand(jwtWrapper, featureFlagsWrapper))
33+
preCommitCmd.AddCommand(secretsIgnoreCommand(jwtWrapper, featureFlagsWrapper))
3434
preCommitCmd.AddCommand(secretsHelpCommand())
3535

3636
return preCommitCmd
3737
}
3838

3939
// / validateLicense verifies the user has the required license for secret detection
4040

41-
func secretsInstallGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
41+
func secretsInstallGitHookCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
4242
cmd := &cobra.Command{
4343
Use: "secrets-install-git-hook",
4444
Short: "Install the pre-commit hook",
@@ -49,7 +49,7 @@ func secretsInstallGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command
4949
`,
5050
),
5151
PreRunE: func(cmd *cobra.Command, args []string) error {
52-
return validateLicense(jwtWrapper)
52+
return validateLicense(jwtWrapper, featureFlagsWrapper)
5353
},
5454
RunE: func(cmd *cobra.Command, args []string) error {
5555
global, _ := cmd.Flags().GetBool("global")
@@ -60,7 +60,7 @@ func secretsInstallGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command
6060
return cmd
6161
}
6262

63-
func secretsUninstallGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
63+
func secretsUninstallGitHookCommand() *cobra.Command {
6464
cmd := &cobra.Command{
6565
Use: "secrets-uninstall-git-hook",
6666
Short: "Uninstall the pre-commit hook",
@@ -79,7 +79,7 @@ func secretsUninstallGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Comma
7979
return cmd
8080
}
8181

82-
func secretsUpdateGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
82+
func secretsUpdateGitHookCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
8383
cmd := &cobra.Command{
8484
Use: "secrets-update-git-hook",
8585
Short: "Update the pre-commit hook",
@@ -90,7 +90,7 @@ func secretsUpdateGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command
9090
`,
9191
),
9292
PreRunE: func(cmd *cobra.Command, args []string) error {
93-
return validateLicense(jwtWrapper)
93+
return validateLicense(jwtWrapper, featureFlagsWrapper)
9494
},
9595
RunE: func(cmd *cobra.Command, args []string) error {
9696
global, _ := cmd.Flags().GetBool("global")
@@ -101,7 +101,7 @@ func secretsUpdateGitHookCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command
101101
return cmd
102102
}
103103

104-
func secretsScanCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
104+
func secretsScanCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
105105
return &cobra.Command{
106106
Use: "secrets-scan",
107107
Short: "Run the real-time secret detection scan",
@@ -112,15 +112,15 @@ func secretsScanCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
112112
`,
113113
),
114114
PreRunE: func(cmd *cobra.Command, args []string) error {
115-
return validateLicense(jwtWrapper)
115+
return validateLicense(jwtWrapper, featureFlagsWrapper)
116116
},
117117
RunE: func(cmd *cobra.Command, args []string) error {
118118
return precommit.Scan()
119119
},
120120
}
121121
}
122122

123-
func secretsIgnoreCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
123+
func secretsIgnoreCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
124124
var resultIds string
125125
var all bool
126126

@@ -135,7 +135,7 @@ func secretsIgnoreCommand(jwtWrapper wrappers.JWTWrapper) *cobra.Command {
135135
`,
136136
),
137137
PreRunE: func(cmd *cobra.Command, args []string) error {
138-
if err := validateLicense(jwtWrapper); err != nil {
138+
if err := validateLicense(jwtWrapper, featureFlagsWrapper); err != nil {
139139
return err
140140
}
141141

internal/commands/pre_commit_test.go

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package commands
33
import (
44
"testing"
55

6+
"github.com/checkmarx/ast-cli/internal/wrappers"
67
"github.com/checkmarx/ast-cli/internal/wrappers/mock"
78
"github.com/stretchr/testify/assert"
89
)
910

1011
func TestNewHooksCommand(t *testing.T) {
1112
mockJWT := &mock.JWTMockWrapper{}
12-
cmd := NewHooksCommand(mockJWT)
13+
mockFF := &mock.FeatureFlagsMockWrapper{}
14+
cmd := NewHooksCommand(mockJWT, mockFF)
1315

1416
assert.NotNil(t, cmd)
1517
assert.Equal(t, "hooks", cmd.Use)
@@ -18,7 +20,8 @@ func TestNewHooksCommand(t *testing.T) {
1820

1921
func TestPreCommitCommand(t *testing.T) {
2022
mockJWT := &mock.JWTMockWrapper{}
21-
cmd := PreCommitCommand(mockJWT)
23+
mockFF := &mock.FeatureFlagsMockWrapper{}
24+
cmd := PreCommitCommand(mockJWT, mockFF)
2225

2326
assert.NotNil(t, cmd)
2427
assert.Equal(t, "pre-commit", cmd.Use)
@@ -45,32 +48,69 @@ func TestPreCommitCommand(t *testing.T) {
4548

4649
func TestValidateLicense(t *testing.T) {
4750
tests := []struct {
48-
name string
49-
aiEnabled int
50-
wantError bool
51+
name string
52+
scsLicensingV2 bool
53+
allowSecretDetection int
54+
allowEnterpriseSecrets int
55+
aiEnabled int
56+
wantErr bool
5157
}{
5258
{
53-
name: "License is valid",
54-
aiEnabled: 0,
55-
wantError: false,
59+
name: "scsLicensing V2 ON and Secret Detection allowed",
60+
scsLicensingV2: true,
61+
allowSecretDetection: 0,
62+
allowEnterpriseSecrets: mock.EnterpriseSecretsDisabled,
63+
wantErr: false,
5664
},
5765
{
58-
name: "License is invalid",
59-
aiEnabled: mock.AIProtectionDisabled,
60-
wantError: true,
66+
name: "scsLicensing V2 ON and Secret Detection denied",
67+
scsLicensingV2: true,
68+
allowSecretDetection: mock.SecretDetectionDisabled,
69+
allowEnterpriseSecrets: 0,
70+
wantErr: true,
71+
},
72+
{
73+
name: "scsLicensing V2 OFF and Enterprise Secrets allowed",
74+
scsLicensingV2: false,
75+
allowSecretDetection: mock.SecretDetectionDisabled,
76+
allowEnterpriseSecrets: 0,
77+
wantErr: false,
78+
},
79+
{
80+
name: "scsLicensing V2 OFF and Enterprise Secrets denied",
81+
scsLicensingV2: false,
82+
allowSecretDetection: 0,
83+
allowEnterpriseSecrets: mock.EnterpriseSecretsDisabled,
84+
wantErr: true,
85+
},
86+
{
87+
name: "AI enabled and secrets license disabled",
88+
aiEnabled: 1,
89+
allowEnterpriseSecrets: mock.EnterpriseSecretsDisabled,
90+
allowSecretDetection: mock.SecretDetectionDisabled,
91+
wantErr: true,
6192
},
6293
}
6394

6495
for _, tt := range tests {
6596
t.Run(tt.name, func(t *testing.T) {
66-
mockJWT := &mock.JWTMockWrapper{
67-
AIEnabled: tt.aiEnabled,
97+
wrappers.ClearCache()
98+
mockFF := &mock.FeatureFlagsMockWrapper{}
99+
mock.Flag = wrappers.FeatureFlagResponseModel{
100+
Name: wrappers.ScsLicensingV2Enabled,
101+
Status: tt.scsLicensingV2,
68102
}
69103

70-
err := validateLicense(mockJWT)
104+
mockJWT := &mock.JWTMockWrapper{}
105+
mockJWT.AIEnabled = tt.aiEnabled
106+
mockJWT.EnterpriseSecretsEnabled = tt.allowEnterpriseSecrets
107+
mockJWT.SecretDetectionEnabled = tt.allowSecretDetection
108+
109+
err := validateLicense(mockJWT, mockFF)
71110

72-
if tt.wantError {
111+
if tt.wantErr {
73112
assert.Error(t, err)
113+
assert.Contains(t, err.Error(), "License validation failed")
74114
} else {
75115
assert.NoError(t, err)
76116
}
@@ -80,7 +120,8 @@ func TestValidateLicense(t *testing.T) {
80120

81121
func TestSecretsIgnoreCommand(t *testing.T) {
82122
mockJWT := &mock.JWTMockWrapper{}
83-
cmd := secretsIgnoreCommand(mockJWT)
123+
mockFF := &mock.FeatureFlagsMockWrapper{}
124+
cmd := secretsIgnoreCommand(mockJWT, mockFF)
84125
assert.NotNil(t, cmd)
85126

86127
resultIdsFlag := cmd.Flag("resultIds")

internal/commands/pre_receive_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import (
1111

1212
func TestPreReceiveCommand(t *testing.T) {
1313
mockJWT := &mock.JWTMockWrapper{}
14-
cmd := PreReceiveCommand(mockJWT)
14+
mockFF := &mock.FeatureFlagsMockWrapper{}
15+
cmd := PreReceiveCommand(mockJWT, mockFF)
1516
assert.NotNil(t, cmd)
1617
assert.Equal(t, "pre-receive", cmd.Use)
1718
subCmds := cmd.Commands()

internal/commands/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ func NewAstCLI(
225225
triageCmd := NewResultsPredicatesCommand(resultsPredicatesWrapper, featureFlagsWrapper, customStatesWrapper)
226226

227227
chatCmd := NewChatCommand(chatWrapper, tenantWrapper)
228-
hooksCmd := NewHooksCommand(jwtWrapper)
228+
hooksCmd := NewHooksCommand(jwtWrapper, featureFlagsWrapper)
229229
telemetryCmd := NewTelemetryCommand(telemetryWrapper)
230230
rootCmd.AddCommand(
231231
scanCmd,

internal/wrappers/mock/jwt-helper-mock.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ import (
99

1010
type JWTMockWrapper struct {
1111
AIEnabled int
12+
EnterpriseSecretsEnabled int
13+
SecretDetectionEnabled int
1214
CheckmarxOneAssistEnabled int
1315
CustomGetAllowedEngines func(wrappers.FeatureFlagsWrapper) (map[string]bool, error)
1416
}
1517

1618
const AIProtectionDisabled = 1
1719
const CheckmarxOneAssistDisabled = 1
20+
const EnterpriseSecretsDisabled = 1
21+
const SecretDetectionDisabled = 1
1822

1923
var engines = []string{"sast", "sca", "api-security", "iac-security", "scs", "containers", "enterprise-secrets"}
2024

@@ -38,13 +42,27 @@ func (*JWTMockWrapper) ExtractTenantFromToken() (tenant string, err error) {
3842

3943
// IsAllowedEngine mock for tests
4044
func (j *JWTMockWrapper) IsAllowedEngine(engine string) (bool, error) {
41-
if engine == params.AiProviderFlag || engine == params.EnterpriseSecretsLabel {
45+
if engine == params.AiProviderFlag {
4246
if j.AIEnabled == AIProtectionDisabled {
4347
return false, nil
4448
}
4549
return true, nil
4650
}
4751

52+
if engine == params.EnterpriseSecretsLabel {
53+
if j.EnterpriseSecretsEnabled == EnterpriseSecretsDisabled {
54+
return false, nil
55+
}
56+
return true, nil
57+
}
58+
59+
if engine == params.SecretDetectionLabel {
60+
if j.SecretDetectionEnabled == SecretDetectionDisabled {
61+
return false, nil
62+
}
63+
return true, nil
64+
}
65+
4866
if engine == params.CheckmarxOneAssistType {
4967
if j.CheckmarxOneAssistEnabled == CheckmarxOneAssistDisabled {
5068
return false, nil

0 commit comments

Comments
 (0)