Skip to content

Commit 89dbaef

Browse files
Merge branch 'main' into feature/alex-containers-default-cloud
2 parents 62a25d7 + 45c4db1 commit 89dbaef

File tree

10 files changed

+208
-5
lines changed

10 files changed

+208
-5
lines changed

internal/commands/predicates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func triageShowSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWra
8181
Long: "The show command provides a list of all the predicates in the issue.",
8282
Example: heredoc.Doc(
8383
`
84-
$ cx triage show --similarity-id <SimilarityID> --project-id <ProjectID> --scan-type <SAST||IAC-SECURITY>
84+
$ cx triage show --similarity-id <SimilarityID> --project-id <ProjectID> --scan-type <SAST||IAC-SECURITY||SCS>
8585
`,
8686
),
8787

internal/commands/util/configuration_test.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import (
1010
"gotest.tools/assert"
1111
)
1212

13-
const cxAscaPort = "cx_asca_port"
13+
const (
14+
cxAscaPort = "cx_asca_port"
15+
cxScsScanOverviewPath = "cx_scs_scan_overview_path"
16+
defaultScsScanOverviewPath = "api/micro-engines/read/scans/%s/scan-overview"
17+
)
1418

1519
func TestNewConfigCommand(t *testing.T) {
1620
cmd := NewConfigCommand()
@@ -94,3 +98,56 @@ func TestChangedOnlyAscaPortInConfigFile_ConfigFileExistsWithDefaultValues_OnlyA
9498
}
9599
}
96100
}
101+
102+
func TestWriteSingleConfigKeyStringToExistingFile_UpdateScsScanOverviewPath_Success(t *testing.T) {
103+
configuration.LoadConfiguration()
104+
configFilePath, _ := configuration.GetConfigFilePath()
105+
err := configuration.SafeWriteSingleConfigKeyString(configFilePath, cxScsScanOverviewPath, defaultScsScanOverviewPath)
106+
assert.NilError(t, err)
107+
108+
config, err := configuration.LoadConfig(configFilePath)
109+
assert.NilError(t, err)
110+
asserts.Equal(t, defaultScsScanOverviewPath, config[cxScsScanOverviewPath])
111+
}
112+
113+
func TestWriteSingleConfigKeyStringNonExistingFile_CreatingTheFileAndWritesTheKey_Success(t *testing.T) {
114+
configFilePath := "non-existing-file"
115+
116+
file, err := os.Open(configFilePath)
117+
asserts.NotNil(t, err)
118+
asserts.Nil(t, file)
119+
120+
err = configuration.SafeWriteSingleConfigKeyString(configFilePath, cxScsScanOverviewPath, defaultScsScanOverviewPath)
121+
assert.NilError(t, err)
122+
123+
file, err = os.Open(configFilePath)
124+
assert.NilError(t, err)
125+
defer func(file *os.File) {
126+
_ = file.Close()
127+
_ = os.Remove(configFilePath)
128+
_ = os.Remove(configFilePath + ".lock")
129+
}(file)
130+
asserts.NotNil(t, file)
131+
}
132+
133+
func TestChangedOnlyScsScanOverviewPathInConfigFile_ConfigFileExistsWithDefaultValues_OnlyScsScanOverviewPathChangedSuccess(t *testing.T) {
134+
configuration.LoadConfiguration()
135+
configFilePath, _ := configuration.GetConfigFilePath()
136+
137+
oldConfig, err := configuration.LoadConfig(configFilePath)
138+
assert.NilError(t, err)
139+
140+
err = configuration.SafeWriteSingleConfigKeyString(configFilePath, cxScsScanOverviewPath, defaultScsScanOverviewPath)
141+
assert.NilError(t, err)
142+
143+
config, err := configuration.LoadConfig(configFilePath)
144+
assert.NilError(t, err)
145+
asserts.Equal(t, defaultScsScanOverviewPath, config[cxScsScanOverviewPath])
146+
147+
// Assert all the other properties are the same
148+
for key, value := range oldConfig {
149+
if key != cxScsScanOverviewPath {
150+
asserts.Equal(t, value, config[key])
151+
}
152+
}
153+
}

internal/params/binds.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ var EnvVarsBinds = []struct {
2121
{ResultsPathKey, ResultsPathEnv, "api/results"},
2222
{ScanSummaryPathKey, ScanSummaryPathEnv, "api/scan-summary"},
2323
{RisksOverviewPathKey, RisksOverviewPathEnv, "api/apisec/static/api/scan/%s/risks-overview"},
24-
{ScsScanOverviewPathKey, ScsScanOverviewPathEnv, "api/micro-engines/scans/%s/scan-overview"},
24+
{ScsScanOverviewPathKey, ScsScanOverviewPathEnv, "api/micro-engines/read/scans/%s/scan-overview"},
2525
{SastResultsPathKey, SastResultsPathEnv, "api/sast-results"},
2626
{SastResultsPredicatesPathKey, SastResultsPredicatesPathEnv, "api/sast-results-predicates"},
2727
{KicsResultsPathKey, KicsResultsPathEnv, "api/kics-results"},
2828
{KicsResultsPredicatesPathKey, KicsResultsPredicatesPathEnv, "api/kics-results-predicates"},
29+
{ScsResultsReadPredicatesPathKey, ScsResultsReadPredicatesPathEnv, "api/micro-engines/read/predicates"},
30+
{ScsResultsWritePredicatesPathKey, ScsResultsWritePredicatesPathEnv, "api/micro-engines/write/predicates"},
2931
{BflPathKey, BflPathEnv, "api/bfl"},
3032
{PRDecorationGithubPathKey, PRDecorationGithubPathEnv, "api/flow-publisher/pr/github"},
3133
{PRDecorationGitlabPathKey, PRDecorationGitlabPathEnv, "api/flow-publisher/pr/gitlab"},

internal/params/envs.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const (
2828
SastResultsPredicatesPathEnv = "CX_SAST_RESULTS_PREDICATES_PATH"
2929
KicsResultsPathEnv = "CX_KICS_RESULTS_PATH"
3030
KicsResultsPredicatesPathEnv = "CX_KICS_RESULTS_PREDICATES_PATH"
31+
ScsResultsReadPredicatesPathEnv = "CX_SCS_RESULTS_PREDICATES_READ_PATH"
32+
ScsResultsWritePredicatesPathEnv = "CX_SCS_RESULTS_PREDICATES_WRITE_PATH"
3133
BflPathEnv = "CX_BFL_PATH"
3234
PRDecorationGithubPathEnv = "CX_PR_DECORATION_GITHUB_PATH"
3335
PRDecorationGitlabPathEnv = "CX_PR_DECORATION_GITLAB_PATH"

internal/params/keys.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ var (
5757
LogsEngineLogPathKey = strings.ToLower(LogsEngineLogPathEnv)
5858
SastResultsPredicatesPathKey = strings.ToLower(SastResultsPredicatesPathEnv)
5959
KicsResultsPredicatesPathKey = strings.ToLower(KicsResultsPredicatesPathEnv)
60+
ScsResultsReadPredicatesPathKey = strings.ToLower(ScsResultsReadPredicatesPathEnv)
61+
ScsResultsWritePredicatesPathKey = strings.ToLower(ScsResultsWritePredicatesPathEnv)
6062
DescriptionsPathKey = strings.ToLower(DescriptionsPathEnv)
6163
TenantConfigurationPathKey = strings.ToLower(TenantConfigurationPathEnv)
6264
ResultsPdfReportPathKey = strings.ToLower(ResultsPdfReportPathEnv)

internal/wrappers/client.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,14 @@ func getCredentialsPayload(accessKeyID, accessKeySecret string) string {
555555

556556
func getAPIKeyPayload(astToken string) string {
557557
logger.PrintIfVerbose("Using API key credentials.")
558-
return fmt.Sprintf("grant_type=refresh_token&client_id=ast-app&refresh_token=%s", astToken)
558+
559+
clientID, err := extractAZPFromToken(astToken)
560+
if err != nil {
561+
logger.PrintIfVerbose("Failed to extract azp from token, using default client_id")
562+
clientID = "ast-app"
563+
}
564+
565+
return fmt.Sprintf("grant_type=refresh_token&client_id=%s&refresh_token=%s", clientID, astToken)
559566
}
560567

561568
func getPasswordCredentialsPayload(username, password, adminClientID, adminClientSecret string) string {
@@ -782,3 +789,12 @@ func AppendIfNotExists(domainsMap map[string]struct{}, newDomain string) map[str
782789
}
783790
return domainsMap
784791
}
792+
793+
func extractAZPFromToken(astToken string) (string, error) {
794+
const azpClaim = "azp"
795+
azp, err := ExtractFromTokenClaims(astToken, azpClaim)
796+
if err != nil {
797+
return "ast-app", nil // default value in case of error
798+
}
799+
return azp, nil
800+
}

internal/wrappers/client_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,73 @@ func TestConcurrentWriteCredentialsToCache(t *testing.T) {
113113
assert.True(t, testTokenNumber >= 0 && testTokenNumber < 1000,
114114
"The token number should be within the expected range")
115115
}
116+
117+
func TestExtractAZPFromToken(t *testing.T) {
118+
// Test cases
119+
tests := []struct {
120+
name string
121+
token string
122+
expected string
123+
hasError bool
124+
}{
125+
{
126+
name: "Valid token with azp claim",
127+
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhenAiOiJ0ZXN0LWFwcCJ9.YqenXXXX", // token with azp: "test-app"
128+
expected: "test-app",
129+
hasError: false,
130+
},
131+
{
132+
name: "Invalid token format",
133+
token: "invalid-token",
134+
expected: "ast-app", // Should return default value
135+
hasError: false,
136+
},
137+
{
138+
name: "Valid token without azp claim",
139+
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.XXXXX",
140+
expected: "ast-app", // Should return default value
141+
hasError: false,
142+
},
143+
}
144+
145+
// Run tests
146+
for _, tt := range tests {
147+
t.Run(tt.name, func(t *testing.T) {
148+
result, err := extractAZPFromToken(tt.token)
149+
150+
if tt.hasError {
151+
assert.Error(t, err)
152+
} else {
153+
assert.NoError(t, err)
154+
}
155+
156+
assert.Equal(t, tt.expected, result)
157+
})
158+
}
159+
}
160+
161+
func TestGetAPIKeyPayload(t *testing.T) {
162+
tests := []struct {
163+
name string
164+
token string
165+
expected string
166+
}{
167+
{
168+
name: "Valid token with azp claim",
169+
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhenAiOiJ0ZXN0LWFwcCJ9.YqenXXXX",
170+
expected: "grant_type=refresh_token&client_id=test-app&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhenAiOiJ0ZXN0LWFwcCJ9.YqenXXXX",
171+
},
172+
{
173+
name: "Invalid token",
174+
token: "invalid-token",
175+
expected: "grant_type=refresh_token&client_id=ast-app&refresh_token=invalid-token",
176+
},
177+
}
178+
179+
for _, tt := range tests {
180+
t.Run(tt.name, func(t *testing.T) {
181+
result := getAPIKeyPayload(tt.token)
182+
assert.Equal(t, tt.expected, result)
183+
})
184+
}
185+
}

internal/wrappers/configuration/configuration.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,36 @@ func SafeWriteSingleConfigKey(configFilePath, key string, value int) error {
161161
return nil
162162
}
163163

164+
func SafeWriteSingleConfigKeyString(configFilePath, key string, value string) error {
165+
// Create a file lock
166+
lock := flock.New(configFilePath + ".lock")
167+
locked, err := lock.TryLock()
168+
if err != nil {
169+
return errors.Errorf("error acquiring lock: %s", err.Error())
170+
}
171+
if !locked {
172+
return errors.Errorf("could not acquire lock")
173+
}
174+
defer func() {
175+
_ = lock.Unlock()
176+
}()
177+
178+
// Load existing configuration or initialize a new one
179+
config, err := LoadConfig(configFilePath)
180+
if err != nil {
181+
return errors.Errorf("error loading config: %s", err.Error())
182+
}
183+
184+
// Update the configuration key
185+
config[key] = value
186+
187+
// Save the updated configuration back to the file
188+
if err = SaveConfig(configFilePath, config); err != nil {
189+
return errors.Errorf("error saving config: %s", err.Error())
190+
}
191+
return nil
192+
}
193+
164194
// LoadConfig loads the configuration from a file. If the file does not exist, it returns an empty map.
165195
func LoadConfig(path string) (map[string]interface{}, error) {
166196
config := make(map[string]interface{})

internal/wrappers/predicates-http.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ func (r *ResultsPredicatesHTTPWrapper) GetAllPredicatesForSimilarityID(similarit
3636
triageAPIPath = viper.GetString(params.KicsResultsPredicatesPathKey)
3737
} else if strings.EqualFold(strings.TrimSpace(scannerType), params.SastType) {
3838
triageAPIPath = viper.GetString(params.SastResultsPredicatesPathKey)
39+
} else if strings.EqualFold(strings.TrimSpace(scannerType), params.ScsType) {
40+
triageAPIPath = viper.GetString(params.ScsResultsReadPredicatesPathKey)
3941
} else if strings.EqualFold(strings.TrimSpace(scannerType), params.ScaType) {
4042
return &PredicatesCollectionResponseModel{}, nil, nil
4143
} else {
@@ -78,6 +80,8 @@ func (r ResultsPredicatesHTTPWrapper) PredicateSeverityAndState(predicate *Predi
7880
triageAPIPath = viper.GetString(params.SastResultsPredicatesPathKey)
7981
} else if strings.EqualFold(strings.TrimSpace(scanType), params.KicsType) || strings.EqualFold(strings.TrimSpace(scanType), params.IacType) {
8082
triageAPIPath = viper.GetString(params.KicsResultsPredicatesPathKey)
83+
} else if strings.EqualFold(strings.TrimSpace(scanType), params.ScsType) {
84+
triageAPIPath = viper.GetString(params.ScsResultsWritePredicatesPathKey)
8185
} else {
8286
return nil, errors.Errorf(invalidScanType, scanType)
8387
}

internal/wrappers/scan-overview-http.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,25 @@ package wrappers
33
import (
44
"encoding/json"
55
"fmt"
6+
"github.com/checkmarx/ast-cli/internal/logger"
7+
"github.com/checkmarx/ast-cli/internal/wrappers/configuration"
68
"net/http"
79

810
commonParams "github.com/checkmarx/ast-cli/internal/params"
911
"github.com/pkg/errors"
1012
"github.com/spf13/viper"
1113
)
1214

15+
const defaultPath = "api/micro-engines/read/scans/%s/scan-overview"
16+
1317
type ScanOverviewHTTPWrapper struct {
1418
path string
1519
}
1620

1721
func NewHTTPScanOverviewWrapper(path string) ScanOverviewWrapper {
22+
validPath := setDefaultPath(path)
1823
return &ScanOverviewHTTPWrapper{
19-
path: path,
24+
path: validPath,
2025
}
2126
}
2227

@@ -58,3 +63,18 @@ func (r *ScanOverviewHTTPWrapper) GetSCSOverviewByScanID(scanID string) (
5863
return nil, nil, errors.Errorf("response status code %d", resp.StatusCode)
5964
}
6065
}
66+
67+
// setDefaultPath checks if the path is the default path, if not it writes the default path to the config file
68+
func setDefaultPath(path string) string {
69+
if path != defaultPath {
70+
configFilePath, err := configuration.GetConfigFilePath()
71+
if err != nil {
72+
logger.PrintfIfVerbose("Error getting config file path: %v", err)
73+
}
74+
err = configuration.SafeWriteSingleConfigKeyString(configFilePath, commonParams.ScsScanOverviewPathKey, defaultPath)
75+
if err != nil {
76+
logger.PrintfIfVerbose("Error writing Scan Overview path to config file: %v", err)
77+
}
78+
}
79+
return defaultPath
80+
}

0 commit comments

Comments
 (0)