Skip to content

Commit 3626dfd

Browse files
cx-anjali-deorecx-sumit-morchhale
authored andcommitted
Support DA_MIGRATION and configuration for direct association of application(AST-139430) (#1451)
* - Added DA_MIGRATION FLAG implementation for direct association
1 parent 8461e53 commit 3626dfd

13 files changed

Lines changed: 89 additions & 14 deletions

File tree

.golangci.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# .golangci.yml
22

3+
34
run:
45
timeout: 5m
56
issues:
@@ -37,7 +38,7 @@ linters:
3738
- unused # covers deadcode/varcheck/structcheck
3839
- whitespace
3940

40-
linters-settings:
41+
linters.settings:
4142
depguard:
4243
list-type: blacklist
4344
rules:

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module github.com/checkmarx/ast-cli
22

33
go 1.24.13
44

5+
56
require (
67
github.com/Checkmarx/containers-resolver v1.0.33
78
github.com/Checkmarx/containers-types v1.0.9

internal/commands/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ func NewAstCLI(
197197
featureFlagsWrapper,
198198
containerResolverWrapper,
199199
realTimeWrapper,
200+
tenantWrapper,
200201
)
201202
projectCmd := NewProjectCommand(applicationsWrapper, projectsWrapper, groupsWrapper, accessManagementWrapper, featureFlagsWrapper)
202203
dastEnvironmentsCmd := dast.NewDastEnvironmentsCommand(dastEnvironmentsWrapper)

internal/commands/scan.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ func NewScanCommand(
187187
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
188188
containerResolverWrapper wrappers.ContainerResolverWrapper,
189189
realtimeScannerWrapper wrappers.RealtimeScannerWrapper,
190+
tenantWrapper wrappers.TenantConfigurationWrapper,
190191
) *cobra.Command {
191192
scanCmd := &cobra.Command{
192193
Use: "scan",
@@ -217,6 +218,7 @@ func NewScanCommand(
217218
accessManagementWrapper,
218219
applicationsWrapper,
219220
featureFlagsWrapper,
221+
tenantWrapper,
220222
)
221223
containerResolver = containerResolverWrapper
222224

@@ -674,6 +676,7 @@ func scanCreateSubCommand(
674676
accessManagementWrapper wrappers.AccessManagementWrapper,
675677
applicationsWrapper wrappers.ApplicationsWrapper,
676678
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
679+
tenantWrapper wrappers.TenantConfigurationWrapper,
677680
) *cobra.Command {
678681
createScanCmd := &cobra.Command{
679682
Use: "create",
@@ -707,6 +710,7 @@ func scanCreateSubCommand(
707710
accessManagementWrapper,
708711
applicationsWrapper,
709712
featureFlagsWrapper,
713+
tenantWrapper,
710714
),
711715
}
712716
createScanCmd.PersistentFlags().Bool(commonParams.AsyncFlag, false, "Do not wait for scan completion")
@@ -945,6 +949,7 @@ func setupScanTypeProjectAndConfig(
945949
accessManagementWrapper wrappers.AccessManagementWrapper,
946950
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
947951
jwtWrapper wrappers.JWTWrapper,
952+
tenantWrapper wrappers.TenantConfigurationWrapper,
948953
) error {
949954
userAllowedEngines, _ := jwtWrapper.GetAllowedEngines(featureFlagsWrapper)
950955
var info map[string]interface{}
@@ -973,6 +978,7 @@ func setupScanTypeProjectAndConfig(
973978
accessManagementWrapper,
974979
applicationsWrapper,
975980
featureFlagsWrapper,
981+
tenantWrapper,
976982
)
977983
if findProjectErr != nil {
978984
return findProjectErr
@@ -2413,6 +2419,7 @@ func runCreateScanCommand(
24132419
accessManagementWrapper wrappers.AccessManagementWrapper,
24142420
applicationsWrapper wrappers.ApplicationsWrapper,
24152421
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
2422+
tenantWrapper wrappers.TenantConfigurationWrapper,
24162423
) func(cmd *cobra.Command, args []string) error {
24172424
return func(cmd *cobra.Command, args []string) error {
24182425
err := validateScanTypes(cmd, jwtWrapper, featureFlagsWrapper)
@@ -2462,6 +2469,7 @@ func runCreateScanCommand(
24622469
applicationsWrapper,
24632470
featureFlagsWrapper,
24642471
jwtWrapper,
2472+
tenantWrapper,
24652473
)
24662474
logger.PrintIfVerbose(fmt.Sprintf("Scan model: %v", scanModel))
24672475
defer cleanUpTempZip(zipFilePath)
@@ -2561,11 +2569,12 @@ func createScanModel(
25612569
applicationsWrapper wrappers.ApplicationsWrapper,
25622570
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
25632571
jwtWrapper wrappers.JWTWrapper,
2572+
tenantWrapper wrappers.TenantConfigurationWrapper,
25642573
) (*wrappers.Scan, string, error) {
25652574
var input = []byte("{}")
25662575

25672576
// Define type, project and config in scan model
2568-
err := setupScanTypeProjectAndConfig(&input, cmd, projectsWrapper, groupsWrapper, scansWrapper, applicationsWrapper, accessManagementWrapper, featureFlagsWrapper, jwtWrapper)
2577+
err := setupScanTypeProjectAndConfig(&input, cmd, projectsWrapper, groupsWrapper, scansWrapper, applicationsWrapper, accessManagementWrapper, featureFlagsWrapper, jwtWrapper, tenantWrapper)
25692578
if err != nil {
25702579
return nil, "", err
25712580
}

internal/commands/scan_test.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4472,7 +4472,7 @@ func Test_CreateScanWithExistingProjectAssign_to_Application_FF_DirectAssociatio
44724472
file := createOutputFile(t, outputFileName)
44734473
defer deleteOutputFile(file)
44744474
defer logger.SetOutput(os.Stdout)
4475-
4475+
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.DaMigrationEnabled, Status: false}
44764476
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.DirectAssociationEnabled, Status: true}
44774477
baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", ".", "--branch", "main", "--debug", "--application-name", mock.ExistingApplication}
44784478
execCmdNilAssertion(
@@ -4486,6 +4486,24 @@ func Test_CreateScanWithExistingProjectAssign_to_Application_FF_DirectAssociatio
44864486
assert.Equal(t, strings.Contains(stdoutString, "Successfully updated the application"), true, "Expected output: %s", "Successfully updated the application")
44874487
}
44884488

4489+
func Test_Create_Scan_With_DA_MIGRATION_And_ConfigurationEnabled_ShouldPass(t *testing.T) {
4490+
file := createOutputFile(t, outputFileName)
4491+
defer deleteOutputFile(file)
4492+
defer logger.SetOutput(os.Stdout)
4493+
4494+
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.DaMigrationEnabled, Status: true}
4495+
baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", ".", "--branch", "main", "--debug", "--application-name", mock.ExistingApplication}
4496+
execCmdNilAssertion(
4497+
t,
4498+
baseArgs...,
4499+
)
4500+
stdoutString, err := util.ReadFileAsString(file.Name())
4501+
if err != nil {
4502+
t.Fatalf("Failed to read log file: %v", err)
4503+
}
4504+
assert.Equal(t, strings.Contains(stdoutString, "Successfully updated the application"), true, "Expected output: %s", "Successfully updated the application")
4505+
}
4506+
44894507
// TestIsTarFileReference tests the tar file detection logic.
44904508
// Container-security scan-type related test function.
44914509
func TestIsTarFileReference(t *testing.T) {

internal/commands/util/import.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func NewImportCommand(
2121
accessManagementWrapper wrappers.AccessManagementWrapper,
2222
byorWrapper wrappers.ByorWrapper,
2323
applicationsWrapper wrappers.ApplicationsWrapper,
24-
featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
24+
featureFlagsWrapper wrappers.FeatureFlagsWrapper, tenantWrapper wrappers.TenantConfigurationWrapper) *cobra.Command {
2525
cmd := &cobra.Command{
2626
Use: "import",
2727
Short: "Import SAST scan results",
@@ -37,7 +37,7 @@ func NewImportCommand(
3737
`,
3838
),
3939
},
40-
RunE: runImportCommand(projectsWrapper, uploadsWrapper, groupsWrapper, accessManagementWrapper, applicationsWrapper, byorWrapper, featureFlagsWrapper),
40+
RunE: runImportCommand(projectsWrapper, uploadsWrapper, groupsWrapper, accessManagementWrapper, applicationsWrapper, byorWrapper, featureFlagsWrapper, tenantWrapper),
4141
}
4242

4343
cmd.PersistentFlags().String(commonParams.ImportFilePath, "", "Path to the import file (sarif file or zip archive containing sarif files)")
@@ -53,7 +53,7 @@ func runImportCommand(
5353
accessManagementWrapper wrappers.AccessManagementWrapper,
5454
applicationsWrapper wrappers.ApplicationsWrapper,
5555
byorWrapper wrappers.ByorWrapper,
56-
featureFlagsWrapper wrappers.FeatureFlagsWrapper) func(cmd *cobra.Command, args []string) error {
56+
featureFlagsWrapper wrappers.FeatureFlagsWrapper, tenantWrapper wrappers.TenantConfigurationWrapper) func(cmd *cobra.Command, args []string) error {
5757
return func(cmd *cobra.Command, args []string) error {
5858
importFilePath, err := validateFilePath(cmd)
5959
if err != nil {
@@ -65,7 +65,7 @@ func runImportCommand(
6565
return errors.Errorf(errorConstants.ProjectNameIsRequired)
6666
}
6767

68-
projectID, err := services.FindProject(projectName, cmd, projectsWrapper, groupsWrapper, accessManagementWrapper, applicationsWrapper, featureFlagsWrapper)
68+
projectID, err := services.FindProject(projectName, cmd, projectsWrapper, groupsWrapper, accessManagementWrapper, applicationsWrapper, featureFlagsWrapper, tenantWrapper)
6969
if err != nil {
7070
return err
7171
}

internal/commands/util/import_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func TestImport_ImportSarifFileWithCorrectFlags_CreateImportSuccessfully(t *test
2020
&mock.ByorMockWrapper{},
2121
mock.ApplicationsMockWrapper{},
2222
&mock.FeatureFlagsMockWrapper{},
23+
&mock.TenantConfigurationMockWrapper{},
2324
)
2425
cmd.SetArgs([]string{"utils", "import", "--project-name", "my-project", "--import-file-path", "my-path.sarif"})
2526
err := cmd.Execute()
@@ -36,6 +37,7 @@ func TestImport_ImportSarifFileProjectDoesntExist_CreateImportWithProvidedNewNam
3637
&mock.ByorMockWrapper{},
3738
mock.ApplicationsMockWrapper{},
3839
&mock.FeatureFlagsMockWrapper{},
40+
&mock.TenantConfigurationMockWrapper{},
3941
)
4042
cmd.SetArgs([]string{"utils", "import", "--project-name", "MOCK-PROJECT-NOT-EXIST", "--import-file-path", "my-path.sarif"})
4143
err := cmd.Execute()
@@ -52,6 +54,7 @@ func TestImport_ImportSarifFileMissingImportFilePath_CreateImportReturnsErrorWit
5254
&mock.ByorMockWrapper{},
5355
mock.ApplicationsMockWrapper{},
5456
&mock.FeatureFlagsMockWrapper{},
57+
&mock.TenantConfigurationMockWrapper{},
5558
)
5659
cmd.SetArgs([]string{"utils", "import", "--project-name", "my-project"})
5760
err := cmd.Execute()
@@ -67,6 +70,7 @@ func TestImport_ImportSarifFileEmptyImportFilePathValue_CreateImportReturnsError
6770
&mock.ByorMockWrapper{},
6871
mock.ApplicationsMockWrapper{},
6972
&mock.FeatureFlagsMockWrapper{},
73+
&mock.TenantConfigurationMockWrapper{},
7074
)
7175
cmd.SetArgs([]string{"utils", "import", "--project-name", "my-project", "--import-file-path", ""})
7276
err := cmd.Execute()
@@ -82,6 +86,7 @@ func TestImport_ImportSarifFileMissingImportProjectName_CreateImportReturnsError
8286
&mock.ByorMockWrapper{},
8387
mock.ApplicationsMockWrapper{},
8488
&mock.FeatureFlagsMockWrapper{},
89+
&mock.TenantConfigurationMockWrapper{},
8590
)
8691
cmd.SetArgs([]string{"utils", "import", "--import-file-path", "my-path.zip"})
8792
err := cmd.Execute()
@@ -97,6 +102,7 @@ func TestImport_ImportSarifFileProjectNameNotProvided_CreateImportWithProvidedNe
97102
&mock.ByorMockWrapper{},
98103
mock.ApplicationsMockWrapper{},
99104
&mock.FeatureFlagsMockWrapper{},
105+
&mock.TenantConfigurationMockWrapper{},
100106
)
101107
cmd.SetArgs([]string{"utils", "import", "--project-name", "", "--import-file-path", "my-path.sarif"})
102108
err := cmd.Execute()
@@ -112,6 +118,7 @@ func TestImport_ImportSarifFileUnacceptedFileExtension_CreateImportReturnsErrorW
112118
&mock.ByorMockWrapper{},
113119
mock.ApplicationsMockWrapper{},
114120
&mock.FeatureFlagsMockWrapper{},
121+
&mock.TenantConfigurationMockWrapper{},
115122
)
116123
cmd.SetArgs([]string{"utils", "import", "--project-name", "MOCK-PROJECT-NOT-EXIST", "--import-file-path", "my-path.txt"})
117124
err := cmd.Execute()
@@ -127,6 +134,7 @@ func TestImport_ImportSarifFileMissingExtension_CreateImportReturnsErrorWithCorr
127134
&mock.ByorMockWrapper{},
128135
mock.ApplicationsMockWrapper{},
129136
&mock.FeatureFlagsMockWrapper{},
137+
&mock.TenantConfigurationMockWrapper{},
130138
)
131139
cmd.SetArgs([]string{"utils", "import", "--project-name", "MOCK-PROJECT-NOT-EXIST", "--import-file-path", "some/path/no/extension/my-path"})
132140
err := cmd.Execute()

internal/commands/util/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func NewUtilsCommand(
6565
},
6666
}
6767

68-
importCmd := NewImportCommand(projectsWrapper, uploadsWrapper, groupsWrapper, accessManagementWrapper, byorWrapper, applicationsWrapper, featureFlagsWrapper)
68+
importCmd := NewImportCommand(projectsWrapper, uploadsWrapper, groupsWrapper, accessManagementWrapper, byorWrapper, applicationsWrapper, featureFlagsWrapper, tenantWrapper)
6969

7070
envCheckCmd := NewEnvCheckCommand()
7171

internal/services/applications.go

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

1111
const (
12-
ApplicationRuleType = "project.name.in"
12+
ApplicationRuleType = "project.name.in"
13+
DirectAssociationKey = "scan.config.applications.directAssociations"
14+
trueString = "true"
1315
)
1416

1517
func createApplicationIds(applicationID, existingApplicationIds []string) []string {
@@ -64,7 +66,7 @@ func verifyApplicationNameExactMatch(applicationName string, resp *wrappers.Appl
6466
return application
6567
}
6668

67-
func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper, projectName, projectID string, featureFlagsWrapper wrappers.FeatureFlagsWrapper) error {
69+
func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper, projectName, projectID string, featureFlagsWrapper wrappers.FeatureFlagsWrapper, tenantWrapper wrappers.TenantConfigurationWrapper) error {
6870
if applicationName == "" {
6971
logger.PrintfIfVerbose("No application name provided. Skipping application update")
7072
return nil
@@ -77,8 +79,11 @@ func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappe
7779
return errors.Errorf("%s: %s", errorConstants.ApplicationNotFound, applicationName)
7880
}
7981

80-
directAssociationEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.DirectAssociationEnabled)
81-
if directAssociationEnabled.Status {
82+
isEnabled, err := checkDirectAssociationEnabled(featureFlagsWrapper, tenantWrapper)
83+
if err != nil {
84+
return errors.Wrap(err, "error while checking if direct association is enabled")
85+
}
86+
if isEnabled {
8287
err = associateProjectToApplication(applicationResp.ID, projectID, applicationResp.ProjectIds, applicationsWrapper)
8388
if err != nil {
8489
return err
@@ -107,6 +112,28 @@ func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappe
107112
return nil
108113
}
109114

115+
func checkDirectAssociationEnabled(featureFlagsWrapper wrappers.FeatureFlagsWrapper, tenantWrapper wrappers.TenantConfigurationWrapper) (bool, error) {
116+
directAssociationEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.DirectAssociationEnabled)
117+
daMigrationEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.DaMigrationEnabled)
118+
var isDAConfigurationEnabled bool
119+
if daMigrationEnabled.Status {
120+
tenantConfigurationResponse, errorModel, err := tenantWrapper.GetTenantConfiguration()
121+
if err != nil {
122+
return false, err
123+
}
124+
if errorModel != nil {
125+
return false, errors.New(errorModel.Message)
126+
}
127+
if tenantConfigurationResponse != nil {
128+
for _, resp := range *tenantConfigurationResponse {
129+
if resp.Key == DirectAssociationKey && resp.Value == trueString {
130+
isDAConfigurationEnabled = true
131+
}
132+
}
133+
}
134+
}
135+
return (daMigrationEnabled.Status && isDAConfigurationEnabled) || directAssociationEnabled.Status, nil
136+
}
110137
func updateApplication(applicationModel *wrappers.ApplicationConfiguration, applicationWrapper wrappers.ApplicationsWrapper, applicationID string) error {
111138
errorModel, err := applicationWrapper.Update(applicationID, applicationModel)
112139
return handleApplicationUpdateResponse(errorModel, err)

internal/services/projects.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func FindProject(
3232
accessManagementWrapper wrappers.AccessManagementWrapper,
3333
applicationWrapper wrappers.ApplicationsWrapper,
3434
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
35+
tenantWrapper wrappers.TenantConfigurationWrapper,
3536
) (string, error) {
3637
var isBranchPrimary bool
3738
resp, err := GetProjectsCollectionByProjectName(projectName, projectsWrapper)
@@ -44,7 +45,7 @@ func FindProject(
4445
for i := 0; i < len(resp.Projects); i++ {
4546
project := resp.Projects[i]
4647
if project.Name == projectName {
47-
err = findApplicationAndUpdate(applicationName, applicationWrapper, projectName, project.ID, featureFlagsWrapper)
48+
err = findApplicationAndUpdate(applicationName, applicationWrapper, projectName, project.ID, featureFlagsWrapper, tenantWrapper)
4849
if err != nil {
4950
return "", err
5051
}

0 commit comments

Comments
 (0)