Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SCS Vulnerabilities in json report when Agent is VSCode/AST-CLI (AST-63907) #850

Closed
wants to merge 9 commits into from
Closed
32 changes: 30 additions & 2 deletions internal/commands/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,32 @@ func setIsContainersEnabled(agent string, featureFlagsWrapper wrappers.FeatureFl
containerEngineCLIEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.ContainerEngineCLIEnabled)
wrappers.IsContainersEnabled = containerEngineCLIEnabled.Status && agentSupported
}

func filterResultsByAgent(results *wrappers.ScanResultsCollection, agent string) *wrappers.ScanResultsCollection {
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
if agent == commonParams.VSCodeAgent {
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
var filteredResults []*wrappers.ScanResult
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
for _, result := range results.Results {
if result.Type != commonParams.SCSScorecardType {
filteredResults = append(filteredResults, result)
} else {
results.TotalCount--
}
}
results.Results = filteredResults
} else if agent != commonParams.DefaultAgent {
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
var filteredResults []*wrappers.ScanResult
for _, result := range results.Results {
if result.Type != commonParams.SCSScorecardType && result.Type != commonParams.SCSSecretDetectionType {
filteredResults = append(filteredResults, result)
} else {
results.TotalCount--
}
}
results.Results = filteredResults
}
return results
}

func CreateScanReport(
resultsWrapper wrappers.ResultsWrapper,
risksOverviewWrapper wrappers.RisksOverviewWrapper,
Expand Down Expand Up @@ -1088,7 +1114,7 @@ func CreateScanReport(
}
for _, reportType := range reportList {
err = createReport(reportType, formatPdfToEmail, formatPdfOptions, formatSbomOptions, targetFile,
targetPath, results, summary, exportWrapper, resultsPdfReportsWrapper, featureFlagsWrapper)
targetPath, results, summary, exportWrapper, resultsPdfReportsWrapper, featureFlagsWrapper, agent)
if err != nil {
return err
}
Expand Down Expand Up @@ -1223,7 +1249,8 @@ func createReport(format,
summary *wrappers.ResultSummary,
exportWrapper wrappers.ExportWrapper,
resultsPdfReportsWrapper wrappers.ResultsPdfWrapper,
featureFlagsWrapper wrappers.FeatureFlagsWrapper) error {
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
agent string) error {
if printer.IsFormat(format, printer.FormatIndentedJSON) {
return nil
}
Expand All @@ -1236,6 +1263,7 @@ func createReport(format,
return exportSonarResults(sonarRpt, results)
}
if printer.IsFormat(format, printer.FormatJSON) && isValidScanStatus(summary.Status, printer.FormatJSON) {
results = filterResultsByAgent(results, agent)
jsonRpt := createTargetName(targetFile, targetPath, printer.FormatJSON)
return exportJSONResults(jsonRpt, results)
}
Expand Down
187 changes: 187 additions & 0 deletions internal/commands/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import (
"encoding/json"
"fmt"
"io"
"os"
"regexp"
"strings"
Expand Down Expand Up @@ -132,6 +133,192 @@
assert.Equal(t, results[0].Status, "Partial", "")
}

func TestRunScsResultsShow_ASTCLI_AgentShouldShowAllResults(t *testing.T) {
executeCommand := func(agent string) *wrappers.ScanResultsCollection {
clearFlags()
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.SCSEngineCLIEnabled, Status: true}

_, err := executeRedirectedOsStdoutTestCommand(createASTTestCommand(),
"results", "show", "--scan-id", "SCS", "--report-format", "json", "--agent", agent)
assert.NilError(t, err)

file, err := os.Open(fileName + ".json")
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
defer file.Close()

fileContents, err := io.ReadAll(file)
if err != nil {
t.Fatalf("failed to read file: %v", err)
}

var results wrappers.ScanResultsCollection
err = json.Unmarshal(fileContents, &results)
assert.NilError(t, err)
return &results
}

results := executeCommand(params.DefaultAgent)
scsSecretDetectionFound := false
scsScorecardFound := false
for _, result := range results.Results {
if result.Type == params.SCSSecretDetectionType {
scsSecretDetectionFound = true
}
if result.Type == params.SCSScorecardType {
scsScorecardFound = true
}
if scsSecretDetectionFound && scsScorecardFound {
break
}
}
assert.Assert(t, scsSecretDetectionFound && scsScorecardFound, "SCS results should be included for AST-CLI agent")
assert.Assert(t, results.TotalCount == 2, "SCS Scorecard results should be excluded for VS Code agent")

defer os.Remove(fileName + ".json")

Check failure on line 179 in internal/commands/result_test.go

View workflow job for this annotation

GitHub Actions / lint

unnecessaryDefer: defer os.Remove(fileName + ".json") is placed just before return (gocritic)
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
}

func TestRunScsResultsShow_VSCode_AgentShouldNotShowScorecardResults(t *testing.T) {
executeCommand := func(agent string) *wrappers.ScanResultsCollection {
clearFlags()
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.SCSEngineCLIEnabled, Status: true}

_, err := executeRedirectedOsStdoutTestCommand(createASTTestCommand(),
"results", "show", "--scan-id", "SCS", "--report-format", "json", "--agent", agent)
assert.NilError(t, err)

file, err := os.Open(fileName + ".json")
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
defer file.Close()

fileContents, err := io.ReadAll(file)
if err != nil {
t.Fatalf("failed to read file: %v", err)
}

var results wrappers.ScanResultsCollection
err = json.Unmarshal(fileContents, &results)
assert.NilError(t, err)
return &results
}

results := executeCommand(params.VSCodeAgent)
for _, result := range results.Results {
assert.Assert(t, result.Type != params.SCSScorecardType, "SCS Scorecard results should be excluded for VS Code agent")
}
assert.Assert(t, results.TotalCount == 1, "SCS Scorecard results should be excluded for VS Code agent")

defer os.Remove(fileName + ".json")

Check failure on line 214 in internal/commands/result_test.go

View workflow job for this annotation

GitHub Actions / lint

unnecessaryDefer: defer os.Remove(fileName + ".json") is placed just before return (gocritic)
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
}

func TestRunScsResultsShow_Other_AgentsShouldNotShowScsResults(t *testing.T) {
executeCommand := func(agent string) *wrappers.ScanResultsCollection {
clearFlags()
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.SCSEngineCLIEnabled, Status: true}

_, err := executeRedirectedOsStdoutTestCommand(createASTTestCommand(),
"results", "show", "--scan-id", "SCS", "--report-format", "json", "--agent", agent)
assert.NilError(t, err)

file, err := os.Open(fileName + ".json")
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
defer file.Close()

fileContents, err := io.ReadAll(file)
if err != nil {
t.Fatalf("failed to read file: %v", err)
}

var results wrappers.ScanResultsCollection
err = json.Unmarshal(fileContents, &results)
assert.NilError(t, err)
return &results
}

results := executeCommand("Jetbrains")
for _, result := range results.Results {
assert.Assert(t, result.Type != params.SCSScorecardType && result.Type != params.SCSSecretDetectionType, "SCS results should be excluded for other agents")
}
assert.Assert(t, results.TotalCount == 0, "SCS Scorecard results should be excluded")

defer os.Remove(fileName + ".json")

Check failure on line 249 in internal/commands/result_test.go

View workflow job for this annotation

GitHub Actions / lint

unnecessaryDefer: defer os.Remove(fileName + ".json") is placed just before return (gocritic)
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
}

func TestRunWithoutScsResults_Other_AgentsShouldNotShowScsResults(t *testing.T) {
executeCommand := func(agent string) *wrappers.ScanResultsCollection {
clearFlags()
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.SCSEngineCLIEnabled, Status: true}
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.ContainerEngineCLIEnabled, Status: true}

_, err := executeRedirectedOsStdoutTestCommand(createASTTestCommand(),
"results", "show", "--scan-id", "MOCK", "--report-format", "json", "--agent", agent)
assert.NilError(t, err)

file, err := os.Open(fileName + ".json")
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
defer file.Close()

fileContents, err := io.ReadAll(file)
if err != nil {
t.Fatalf("failed to read file: %v", err)
}

var results wrappers.ScanResultsCollection
err = json.Unmarshal(fileContents, &results)
assert.NilError(t, err)
return &results
}

results := executeCommand("Jetbrains")
for _, result := range results.Results {
assert.Assert(t, result.Type != params.SCSScorecardType && result.Type != params.SCSSecretDetectionType, "SCS results should be excluded for other agents")
}
assert.Assert(t, results.TotalCount == 7, "SCS Scorecard results should be excluded")

defer os.Remove(fileName + ".json")
}

func TestRunNilResults_Other_AgentsShouldNotShowAnyResults(t *testing.T) {
executeCommand := func(agent string) *wrappers.ScanResultsCollection {
sarahCx marked this conversation as resolved.
Show resolved Hide resolved
clearFlags()
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.SCSEngineCLIEnabled, Status: true}
mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.ContainerEngineCLIEnabled, Status: true}

_, err := executeRedirectedOsStdoutTestCommand(createASTTestCommand(),
"results", "show", "--scan-id", "NIL_RESULTS", "--report-format", "json", "--agent", agent)
assert.NilError(t, err)

file, err := os.Open(fileName + ".json")
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
defer file.Close()

fileContents, err := io.ReadAll(file)
if err != nil {
t.Fatalf("failed to read file: %v", err)
}

var results wrappers.ScanResultsCollection
err = json.Unmarshal(fileContents, &results)
assert.NilError(t, err)
return &results
}

results := executeCommand("Jetbrains")

assert.Assert(t, results.TotalCount == 0, "SCS Scorecard results should be excluded")

defer os.Remove(fileName + ".json")
}

func TestResultsExitCode_OnCanceledScan_PrintOnlyScanIDAndStatusCanceledToConsole(t *testing.T) {
model := wrappers.ScanResponseModel{
ID: "fake-scan-id-kics-fail-sast-canceled-id",
Expand Down
31 changes: 17 additions & 14 deletions internal/params/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const (
AgentFlagUsage = "Scan origin name"
ApplicationName = "application-name"
DefaultAgent = "ASTCLI"
VSCodeAgent = "VS Code"
DebugFlag = "debug"
DebugUsage = "Debug mode with detailed logs"
RetryFlag = "retry"
Expand Down Expand Up @@ -230,20 +231,22 @@ const (

// Results
const (
SastType = "sast"
KicsType = "kics"
APISecurityType = "api-security"
AIProtectionType = "AI Protection"
ContainersType = "containers"
APIDocumentationFlag = "apisec-swagger-filter"
IacType = "iac-security"
IacLabel = "IaC Security"
APISecurityLabel = "API Security"
ScaType = "sca"
APISecType = "apisec"
ScsType = "scs"
MicroEnginesType = "microengines" // the scs scan type for scans API
Success = "success"
SastType = "sast"
KicsType = "kics"
APISecurityType = "api-security"
AIProtectionType = "AI Protection"
ContainersType = "containers"
APIDocumentationFlag = "apisec-swagger-filter"
IacType = "iac-security"
IacLabel = "IaC Security"
APISecurityLabel = "API Security"
ScaType = "sca"
APISecType = "apisec"
ScsType = "scs"
MicroEnginesType = "microengines" // the scs scan type for scans API
Success = "success"
SCSScorecardType = "sscs-Scorecard"
SCSSecretDetectionType = "sscs-Secret Detection"
)

// ScaAgent AST Role
Expand Down
43 changes: 43 additions & 0 deletions internal/wrappers/mock/results-mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,40 @@ var containersResults = &wrappers.ScanResult{
CweID: "CWE-1234",
},
}
var scsResults = &wrappers.ScanResultsCollection{
TotalCount: 2,
Results: []*wrappers.ScanResult{
{
Type: "sscs-Secret Detection",
ID: "bhXbZjjoQZdGAwUhj6MLo9sh4fA=",
SimilarityID: "6deb156f325544aaefecee846b49a948571cecd4445d2b2b391a490641be5845",
Status: "NEW",
State: "TO_VERIFY",
Severity: "HIGH",
Created: "2024-07-30T12:49:56Z",
FirstFoundAt: "2023-07-06T10:28:49Z",
FoundAt: "2024-07-30T12:49:56Z",
FirstScanID: "3d922bcd-00fe-4774-b182-d51e739dff81",
Description: "Generic API Key has detected secret for file application.properties.",
VulnerabilityDetails: wrappers.VulnerabilityDetails{},
},
{
Type: "sscs-Scorecard",
ID: "n2a8iCzrIgbCe+dGKYk+cAApO0U=",
SimilarityID: "65323789a325544aaefecee846b49a948571cecd4445d2b2b391a490641be5845",
Status: "NEW",
State: "TO_VERIFY",
Severity: "HIGH",
Created: "2024-07-30T12:49:56Z",
FirstFoundAt: "2023-07-06T10:28:49Z",
FoundAt: "2024-07-30T12:49:56Z",
FirstScanID: "3d922bcd-00fe-4774-b182-d51e739dff81",
Description: "score is 0: branch protection not enabled on development/release branches:\\nWarn: branch protection not enabled for branch 'main'",

VulnerabilityDetails: wrappers.VulnerabilityDetails{},
},
},
}

func (r ResultsMockWrapper) GetAllResultsByScanID(params map[string]string) (
*wrappers.ScanResultsCollection,
Expand All @@ -49,6 +83,15 @@ func (r ResultsMockWrapper) GetAllResultsByScanID(params map[string]string) (
},
}, nil, nil
}
if params["scan-id"] == "SCS" {
return scsResults, nil, nil
}
if params["scan-id"] == "NIL_RESULTS" {
return &wrappers.ScanResultsCollection{
TotalCount: 0,
Results: nil,
}, nil, nil
}
const mock = "mock"
var dependencyPath = wrappers.DependencyPath{ID: mock, Name: mock, Version: mock, IsResolved: true, IsDevelopment: false, Locations: nil}
var dependencyArray = [][]wrappers.DependencyPath{{dependencyPath}}
Expand Down
Loading