Skip to content

Commit 59c687a

Browse files
Add SSCS as scan type for the triage command (AST-72075) (#1022)
* Support scs triage capabilities * Divide sscs (REST) server in two (read and write) * feature(sscs-env-var): guarantee that env var has default string value * test(sscs-env-var): add new UTs * fix(sscs-env-var): fix typos --------- Co-authored-by: AlvoBen <[email protected]>
1 parent 12df086 commit 59c687a

File tree

8 files changed

+121
-4
lines changed

8 files changed

+121
-4
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/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)