Skip to content

Commit 16da59b

Browse files
Merge branch 'main' into avis/azure-support
2 parents 6427420 + c383fbf commit 16da59b

File tree

20 files changed

+408
-89
lines changed

20 files changed

+408
-89
lines changed

.github/scripts/signing_win.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ REMOTE_PATH="/tmp"
2121
# HSM credentials
2222
HSM_CREDS=$SIGNING_HSM_CREDS
2323

24+
# Certificate properties
25+
CERT_LABEL="CNGRSAPriv-cx-signing-2024"
26+
CERT_LOCATION="/home/ubuntu/checkmarx_2024.crt"
27+
2428
# Check if OS is windows
2529
if [ "$OS_TYPE" != "windows" ]; then
2630
echo "The artifact is not a windows binary file, exiting."
@@ -53,7 +57,7 @@ if [ $? -ne 0 ]; then
5357
fi
5458

5559
# Sign
56-
ssh -n -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" "osslsigncode sign -certs /home/ubuntu/checkmarx.crt -key 'pkcs11:object=CNGRSAPriv-cx-signing' -pass $HSM_CREDS -pkcs11module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so -t http://timestamp.digicert.com -in '$REMOTE_PATH/$FILENAME' -out '$REMOTE_PATH/$FILENAME_SIGNED'"
60+
ssh -n -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" "osslsigncode sign -certs $CERT_LOCATION -key 'pkcs11:object=$CERT_LABEL' -pass $HSM_CREDS -pkcs11module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so -t http://timestamp.digicert.com -in '$REMOTE_PATH/$FILENAME' -out '$REMOTE_PATH/$FILENAME_SIGNED'"
5761
# Check remote command status
5862
if [ $? -ne 0 ]; then
5963
echo "Failed to sign file $FILENAME"

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ jobs:
7575
AZURE_PROJECT: ${{ secrets.AZURE_PROJECT }}
7676
AZURE_REPOS: ${{ secrets.AZURE_REPOS }}
7777
AZURE_TOKEN: ${{ secrets.AZURE_TOKEN }}
78+
AZURE_NEW_ORG: "azureAccountTests"
79+
AZURE_PROJECT_NAME: "testsProject"
80+
AZURE_PR_NUMBER: 1
81+
AZURE_NEW_TOKEN: ${{ secrets.AZURE_NEW_TOKEN }}
7882
BITBUCKET_WORKSPACE: ${{ secrets.BITBUCKET_WORKSPACE }}
7983
BITBUCKET_REPOS: ${{ secrets.BITBUCKET_REPOS }}
8084
BITBUCKET_USERNAME: ${{ secrets.BITBUCKET_USERNAME }}

.github/workflows/manual-integration-test.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ jobs:
7878
AZURE_PROJECT: ${{ secrets.AZURE_PROJECT }}
7979
AZURE_REPOS: ${{ secrets.AZURE_REPOS }}
8080
AZURE_TOKEN: ${{ secrets.AZURE_TOKEN }}
81+
AZURE_NEW_ORG: "azureAccountTests"
82+
AZURE_PROJECT_NAME: "testsProject"
83+
AZURE_PR_NUMBER: 1
84+
AZURE_NEW_TOKEN: ${{ secrets.AZURE_NEW_TOKEN }}
8185
BITBUCKET_WORKSPACE: ${{ secrets.BITBUCKET_WORKSPACE }}
8286
BITBUCKET_REPOS: ${{ secrets.BITBUCKET_REPOS }}
8387
BITBUCKET_USERNAME: ${{ secrets.BITBUCKET_USERNAME }}

cmd/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func main() {
4242
bfl := viper.GetString(params.BflPathKey)
4343
prDecorationGithubPath := viper.GetString(params.PRDecorationGithubPathKey)
4444
prDecorationGitlabPath := viper.GetString(params.PRDecorationGitlabPathKey)
45+
prDecorationAzurePath := viper.GetString(params.PRDecorationAzurePathKey)
4546
descriptionsPath := viper.GetString(params.DescriptionsPathKey)
4647
tenantConfigurationPath := viper.GetString(params.TenantConfigurationPathKey)
4748
resultsPdfPath := viper.GetString(params.ResultsPdfReportPathKey)
@@ -72,7 +73,7 @@ func main() {
7273
bitBucketServerWrapper := bitbucketserver.NewBitbucketServerWrapper()
7374
gitLabWrapper := wrappers.NewGitLabWrapper()
7475
bflWrapper := wrappers.NewBflHTTPWrapper(bfl)
75-
prWrapper := wrappers.NewHTTPPRWrapper(prDecorationGithubPath, prDecorationGitlabPath)
76+
prWrapper := wrappers.NewHTTPPRWrapper(prDecorationGithubPath, prDecorationGitlabPath, prDecorationAzurePath)
7677
learnMoreWrapper := wrappers.NewHTTPLearnMoreWrapper(descriptionsPath)
7778
tenantConfigurationWrapper := wrappers.NewHTTPTenantConfigurationWrapper(tenantConfigurationPath)
7879
jwtWrapper := wrappers.NewJwtWrapper()

internal/commands/groups.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,24 @@ package commands
33
import (
44
"encoding/json"
55

6-
featureFlagsConstants "github.com/checkmarx/ast-cli/internal/constants/feature-flags"
76
commonParams "github.com/checkmarx/ast-cli/internal/params"
87
"github.com/checkmarx/ast-cli/internal/services"
98
"github.com/checkmarx/ast-cli/internal/wrappers"
109
"github.com/spf13/cobra"
1110
)
1211

13-
func updateGroupValues(input *[]byte, cmd *cobra.Command, groupsWrapper wrappers.GroupsWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) ([]*wrappers.Group, error) {
12+
func updateGroupValues(input *[]byte, cmd *cobra.Command, groupsWrapper wrappers.GroupsWrapper) ([]*wrappers.Group, error) {
1413
groupListStr, _ := cmd.Flags().GetString(commonParams.GroupList)
1514
groups, err := services.CreateGroupsMap(groupListStr, groupsWrapper)
1615
if err != nil {
1716
return groups, err
1817
}
19-
flagResponse, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, featureFlagsConstants.AccessManagementEnabled)
20-
if !flagResponse.Status {
21-
var info map[string]interface{}
22-
_ = json.Unmarshal(*input, &info)
23-
info["groups"] = services.GetGroupIds(groups)
24-
*input, _ = json.Marshal(info)
25-
}
18+
19+
// we're not checking here status of the feature flag, because of refactoring in AM
20+
var info map[string]interface{}
21+
_ = json.Unmarshal(*input, &info)
22+
info["groups"] = services.GetGroupIds(groups)
23+
*input, _ = json.Marshal(info)
24+
2625
return groups, nil
2726
}

internal/commands/project.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ func runCreateProjectCommand(
248248
if err != nil {
249249
return err
250250
}
251-
groups, err := updateGroupValues(&input, cmd, groupsWrapper, featureFlagsWrapper)
251+
groups, err := updateGroupValues(&input, cmd, groupsWrapper)
252252
if err != nil {
253253
return err
254254
}

internal/commands/util/pr.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
const (
1818
failedCreatingGithubPrDecoration = "Failed creating github PR Decoration"
19+
failedCreatingAzurePrDecoration = "Failed creating azure PR Decoration"
1920
failedCreatingGitlabPrDecoration = "Failed creating gitlab MR Decoration"
2021
errorCodeFormat = "%s: CODE: %d, %s\n"
2122
policyErrorFormat = "%s: Failed to get scanID policy information"
@@ -27,6 +28,8 @@ const (
2728
gitlabOnPremURLSuffix = "/api/v4/"
2829
githubCloudURL = "https://api.github.com/repos/"
2930
gitlabCloudURL = "https://gitlab.com" + gitlabOnPremURLSuffix
31+
azureCloudURL = "https://dev.azure.com/"
32+
errorAzureOnPremParams = "code-repository-url must be set when code-repository-username is set"
3033
)
3134

3235
func NewPRDecorationCommand(prWrapper wrappers.PRWrapper, policyWrapper wrappers.PolicyWrapper, scansWrapper wrappers.ScansWrapper) *cobra.Command {
@@ -42,9 +45,11 @@ func NewPRDecorationCommand(prWrapper wrappers.PRWrapper, policyWrapper wrappers
4245

4346
prDecorationGithub := PRDecorationGithub(prWrapper, policyWrapper, scansWrapper)
4447
prDecorationGitlab := PRDecorationGitlab(prWrapper, policyWrapper, scansWrapper)
48+
prDecorationAzure := PRDecorationAzure(prWrapper, policyWrapper, scansWrapper)
4549

4650
cmd.AddCommand(prDecorationGithub)
4751
cmd.AddCommand(prDecorationGitlab)
52+
cmd.AddCommand(prDecorationAzure)
4853
return cmd
4954
}
5055

@@ -159,6 +164,47 @@ func PRDecorationGitlab(prWrapper wrappers.PRWrapper, policyWrapper wrappers.Pol
159164
return prDecorationGitlab
160165
}
161166

167+
func PRDecorationAzure(prWrapper wrappers.PRWrapper, policyWrapper wrappers.PolicyWrapper, scansWrapper wrappers.ScansWrapper) *cobra.Command {
168+
prDecorationAzure := &cobra.Command{
169+
Use: "azure",
170+
Short: "Decorate azure PR with vulnerabilities",
171+
Long: "Decorate azure PR with vulnerabilities",
172+
Example: heredoc.Doc(
173+
`
174+
$ cx utils pr azure --scan-id <scan-id> --token <AAD> --namespace <organization> --project <project-name or project-id>
175+
--pr-number <pr number> --code-repository-url <code-repository-url>
176+
`,
177+
),
178+
Annotations: map[string]string{
179+
"command:doc": heredoc.Doc(
180+
`https://checkmarx.com/resource/documents/en/34965-68653-utils.html
181+
`,
182+
),
183+
},
184+
RunE: runPRDecorationAzure(prWrapper, policyWrapper, scansWrapper),
185+
}
186+
187+
prDecorationAzure.Flags().String(params.ScanIDFlag, "", "Scan ID to retrieve results from")
188+
prDecorationAzure.Flags().String(params.SCMTokenFlag, "", params.AzureTokenUsage)
189+
prDecorationAzure.Flags().String(params.NamespaceFlag, "", fmt.Sprintf(params.NamespaceFlagUsage, "Azure"))
190+
prDecorationAzure.Flags().String(params.AzureProjectFlag, "", fmt.Sprintf(params.AzureProjectFlagUsage))
191+
prDecorationAzure.Flags().Int(params.PRNumberFlag, 0, params.PRNumberFlagUsage)
192+
prDecorationAzure.Flags().String(params.CodeRepositoryFlag, "", params.CodeRepositoryFlagUsage)
193+
prDecorationAzure.Flags().String(params.CodeRespositoryUsernameFlag, "", fmt.Sprintf(params.CodeRespositoryUsernameFlagUsage))
194+
195+
// Set the value for token to mask the scm token
196+
_ = viper.BindPFlag(params.SCMTokenFlag, prDecorationAzure.Flags().Lookup(params.SCMTokenFlag))
197+
198+
// mark some fields as required\
199+
_ = prDecorationAzure.MarkFlagRequired(params.ScanIDFlag)
200+
_ = prDecorationAzure.MarkFlagRequired(params.SCMTokenFlag)
201+
_ = prDecorationAzure.MarkFlagRequired(params.NamespaceFlag)
202+
_ = prDecorationAzure.MarkFlagRequired(params.AzureProjectFlag)
203+
_ = prDecorationAzure.MarkFlagRequired(params.PRNumberFlag)
204+
205+
return prDecorationAzure
206+
}
207+
162208
func runPRDecoration(prWrapper wrappers.PRWrapper, policyWrapper wrappers.PolicyWrapper, scansWrapper wrappers.ScansWrapper) func(cmd *cobra.Command, args []string) error {
163209
return func(cmd *cobra.Command, args []string) error {
164210
scanID, _ := cmd.Flags().GetString(params.ScanIDFlag)
@@ -226,6 +272,13 @@ func updateAPIURLForGitlabOnPrem(apiURL string) string {
226272
return gitlabCloudURL
227273
}
228274

275+
func getAzureAPIURL(apiURL string) string {
276+
if apiURL != "" {
277+
return apiURL
278+
}
279+
return azureCloudURL
280+
}
281+
229282
func runPRDecorationGitlab(prWrapper wrappers.PRWrapper, policyWrapper wrappers.PolicyWrapper, scansWrapper wrappers.ScansWrapper) func(cmd *cobra.Command, args []string) error {
230283
return func(cmd *cobra.Command, args []string) error {
231284
scanID, _ := cmd.Flags().GetString(params.ScanIDFlag)
@@ -283,6 +336,85 @@ func runPRDecorationGitlab(prWrapper wrappers.PRWrapper, policyWrapper wrappers.
283336
}
284337
}
285338

339+
func runPRDecorationAzure(prWrapper wrappers.PRWrapper, policyWrapper wrappers.PolicyWrapper, scansWrapper wrappers.ScansWrapper) func(cmd *cobra.Command, args []string) error {
340+
return func(cmd *cobra.Command, args []string) error {
341+
scanID, _ := cmd.Flags().GetString(params.ScanIDFlag)
342+
scmTokenFlag, _ := cmd.Flags().GetString(params.SCMTokenFlag)
343+
namespaceFlag, _ := cmd.Flags().GetString(params.NamespaceFlag)
344+
projectNameFlag, _ := cmd.Flags().GetString(params.AzureProjectFlag)
345+
prNumberFlag, _ := cmd.Flags().GetInt(params.PRNumberFlag)
346+
apiURL, _ := cmd.Flags().GetString(params.CodeRepositoryFlag)
347+
codeRepositoryUserName, _ := cmd.Flags().GetString(params.CodeRespositoryUsernameFlag)
348+
349+
errParams := validateAzureOnPremParameters(apiURL, codeRepositoryUserName)
350+
if errParams != nil {
351+
return errParams
352+
}
353+
354+
scanRunningOrQueued, err := IsScanRunningOrQueued(scansWrapper, scanID)
355+
356+
if err != nil {
357+
return err
358+
}
359+
360+
if scanRunningOrQueued {
361+
log.Println(noPRDecorationCreated)
362+
return nil
363+
}
364+
365+
// Retrieve policies related to the scan and project to include in the PR decoration
366+
policies, policyError := getScanViolatedPolicies(scansWrapper, policyWrapper, scanID, cmd)
367+
if policyError != nil {
368+
return errors.Errorf(policyErrorFormat, failedCreatingAzurePrDecoration)
369+
}
370+
371+
// Build and post the pr decoration
372+
updatedAPIURL := getAzureAPIURL(apiURL)
373+
updatedScmToken := updateScmTokenForAzure(scmTokenFlag, codeRepositoryUserName)
374+
azureNameSpace := createAzureNameSpace(namespaceFlag, projectNameFlag)
375+
376+
prModel := &wrappers.AzurePRModel{
377+
ScanID: scanID,
378+
ScmToken: updatedScmToken,
379+
Namespace: azureNameSpace,
380+
PrNumber: prNumberFlag,
381+
Policies: policies,
382+
APIURL: updatedAPIURL,
383+
}
384+
prResponse, errorModel, err := prWrapper.PostAzurePRDecoration(prModel)
385+
if err != nil {
386+
return err
387+
}
388+
389+
if errorModel != nil {
390+
return errors.Errorf(errorCodeFormat, failedCreatingAzurePrDecoration, errorModel.Code, errorModel.Message)
391+
}
392+
393+
logger.Print(prResponse)
394+
395+
return nil
396+
}
397+
}
398+
399+
func validateAzureOnPremParameters(apiURL, codeRepositoryUserName string) error {
400+
if apiURL == "" && codeRepositoryUserName != "" {
401+
log.Println(errorAzureOnPremParams)
402+
return errors.New(errorAzureOnPremParams)
403+
}
404+
return nil
405+
}
406+
407+
func createAzureNameSpace(namespace, projectName string) string {
408+
return fmt.Sprintf("%s/%s", namespace, projectName)
409+
}
410+
411+
func updateScmTokenForAzure(scmTokenFlag, codeRepositoryUserName string) string {
412+
if codeRepositoryUserName != "" {
413+
return fmt.Sprintf("%s:%s", codeRepositoryUserName, scmTokenFlag)
414+
}
415+
return scmTokenFlag
416+
}
417+
286418
func getScanViolatedPolicies(scansWrapper wrappers.ScansWrapper, policyWrapper wrappers.PolicyWrapper, scanID string, cmd *cobra.Command) ([]wrappers.PrPolicy, error) {
287419
// retrieve scan model to get the projectID
288420
scanResponseModel, errorScanModel, err := scansWrapper.GetByID(scanID)

internal/commands/util/pr_test.go

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,34 @@ import (
88
"gotest.tools/assert"
99
)
1010

11-
func TestNewPRDecorationCommandMustExist(t *testing.T) {
11+
const (
12+
token = "token"
13+
)
14+
15+
func TestNewGithubPRDecorationCommandMustExist(t *testing.T) {
1216
cmd := PRDecorationGithub(nil, nil, nil)
1317
assert.Assert(t, cmd != nil, "PR decoration command must exist")
1418

1519
err := cmd.Execute()
1620
assert.ErrorContains(t, err, "scan-id")
1721
}
1822

19-
func TestNewMRDecorationCommandMustExist(t *testing.T) {
23+
func TestNewGitlabMRDecorationCommandMustExist(t *testing.T) {
2024
cmd := PRDecorationGitlab(nil, nil, nil)
2125
assert.Assert(t, cmd != nil, "MR decoration command must exist")
2226

2327
err := cmd.Execute()
2428
assert.ErrorContains(t, err, "scan-id")
2529
}
2630

31+
func TestNewAzurePRDecorationCommandMustExist(t *testing.T) {
32+
cmd := PRDecorationAzure(nil, nil, nil)
33+
assert.Assert(t, cmd != nil, "PR decoration command must exist")
34+
35+
err := cmd.Execute()
36+
assert.ErrorContains(t, err, "scan-id")
37+
}
38+
2739
func TestIsScanRunning_WhenScanRunning_ShouldReturnTrue(t *testing.T) {
2840
scansMockWrapper := &mock.ScansMockWrapper{Running: true}
2941

@@ -66,3 +78,43 @@ func TestUpdateAPIURLForGitlabOnPrem_whenAPIURLIsNotSet_ShouldReturnCloudAPIURL(
6678
cloudAPIURL := updateAPIURLForGitlabOnPrem("")
6779
asserts.Equal(t, gitlabCloudURL, cloudAPIURL)
6880
}
81+
82+
func TestGetAzureAPIURL_whenAPIURLIsSet_ShouldUpdateAPIURL(t *testing.T) {
83+
selfHostedURL := "https://azure.example.com"
84+
updatedAPIURL := getAzureAPIURL(selfHostedURL)
85+
asserts.Equal(t, selfHostedURL, updatedAPIURL)
86+
}
87+
88+
func TestGetAzureAPIURL_whenAPIURLIsNotSet_ShouldReturnCloudAPIURL(t *testing.T) {
89+
cloudAPIURL := getAzureAPIURL("")
90+
asserts.Equal(t, azureCloudURL, cloudAPIURL)
91+
}
92+
93+
func TestUpdateScmTokenForAzureOnPrem_whenUserNameIsSet_ShouldUpdateToken(t *testing.T) {
94+
username := "username"
95+
expectedToken := username + ":" + token
96+
updatedToken := updateScmTokenForAzure(token, username)
97+
asserts.Equal(t, expectedToken, updatedToken)
98+
}
99+
100+
func TestUpdateScmTokenForAzureOnPrem_whenUserNameNotSet_ShouldNotUpdateToken(t *testing.T) {
101+
username := ""
102+
expectedToken := token
103+
updatedToken := updateScmTokenForAzure(token, username)
104+
asserts.Equal(t, expectedToken, updatedToken)
105+
}
106+
107+
func TestCreateAzureNameSpace_ShouldCreateNamespace(t *testing.T) {
108+
azureNamespace := createAzureNameSpace("organization", "project")
109+
asserts.Equal(t, "organization/project", azureNamespace)
110+
}
111+
112+
func TestValidateAzureOnPremParameters_WhenParametersAreValid_ShouldReturnNil(t *testing.T) {
113+
err := validateAzureOnPremParameters("https://azure.example.com", "username")
114+
asserts.Nil(t, err)
115+
}
116+
117+
func TestValidateAzureOnPremParameters_WhenParametersAreNotValid_ShouldReturnError(t *testing.T) {
118+
err := validateAzureOnPremParameters("", "username")
119+
asserts.NotNil(t, err)
120+
}

internal/params/binds.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var EnvVarsBinds = []struct {
2828
{BflPathKey, BflPathEnv, "api/bfl"},
2929
{PRDecorationGithubPathKey, PRDecorationGithubPathEnv, "api/flow-publisher/pr/github"},
3030
{PRDecorationGitlabPathKey, PRDecorationGitlabPathEnv, "api/flow-publisher/pr/gitlab"},
31+
{PRDecorationAzurePathKey, PRDecorationAzurePathEnv, "api/flow-publisher/pr/azure"},
3132
{DescriptionsPathKey, DescriptionsPathEnv, "api/queries/descriptions"},
3233
{TenantConfigurationPathKey, TenantConfigurationPathEnv, "api/configuration/tenant"},
3334
{UploadsPathKey, UploadsPathEnv, "api/uploads"},

internal/params/envs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const (
3030
BflPathEnv = "CX_BFL_PATH"
3131
PRDecorationGithubPathEnv = "CX_PR_DECORATION_GITHUB_PATH"
3232
PRDecorationGitlabPathEnv = "CX_PR_DECORATION_GITLAB_PATH"
33+
PRDecorationAzurePathEnv = "CX_PR_DECORATION_AZURE_PATH"
3334
SastRmPathEnv = "CX_SAST_RM_PATH"
3435
UploadsPathEnv = "CX_UPLOADS_PATH"
3536
TokenExpirySecondsEnv = "CX_TOKEN_EXPIRY_SECONDS"

0 commit comments

Comments
 (0)