Skip to content

Commit 4eb8091

Browse files
committed
fix: skip the dependency scan when no SCA pattern is enabled
1 parent e44147e commit 4eb8091

2 files changed

Lines changed: 97 additions & 17 deletions

File tree

internal/tool/tool.go

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,32 +81,43 @@ func (t codacyTrivy) Run(ctx context.Context, toolExecution codacy.ToolExecution
8181
// This is the only way to suppress Trivy logs.
8282
log.InitLogger(false, true)
8383

84-
report, err := t.runBaseScan(ctx, toolExecution.SourceDir)
85-
if err != nil {
86-
return nil, err
87-
}
84+
allIssues := []codacy.Result{}
8885

89-
sbom, err := t.getSBOM(ctx, report)
90-
if err != nil {
91-
return nil, err
92-
}
86+
// The dependency scan covers the whole source directory regardless of the requested files, and the SBOM is derived
87+
// from it, so both are wasted work when the execution has no SCA pattern to report them under.
88+
if scaScanningEnabled(*toolExecution.Patterns) {
89+
report, err := t.runBaseScan(ctx, toolExecution.SourceDir)
90+
if err != nil {
91+
return nil, err
92+
}
9393

94-
vulnerabilityScanningIssues, err := t.getVulnerabilities(ctx, report, toolExecution)
95-
if err != nil {
96-
return nil, err
97-
}
94+
sbom, err := t.getSBOM(ctx, report)
95+
if err != nil {
96+
return nil, err
97+
}
9898

99-
secretScanningIssues := t.runSecretScanning(toolExecution)
99+
vulnerabilityScanningIssues, err := t.getVulnerabilities(ctx, report, toolExecution)
100+
if err != nil {
101+
return nil, err
102+
}
100103

101-
maliciousPackagesIssues := t.maliciousPackagesScanner.Scan(report, toolExecution)
104+
allIssues = append(allIssues, vulnerabilityScanningIssues...)
105+
allIssues = append(allIssues, t.maliciousPackagesScanner.Scan(report, toolExecution)...)
106+
allIssues = append(allIssues, sbom)
107+
}
102108

103-
allIssues := append(vulnerabilityScanningIssues, secretScanningIssues...)
104-
allIssues = append(allIssues, maliciousPackagesIssues...)
105-
allIssues = append(allIssues, sbom)
109+
allIssues = append(allIssues, t.runSecretScanning(toolExecution)...)
106110

107111
return allIssues, nil
108112
}
109113

114+
// scaScanningEnabled returns whether any of the given patterns needs the dependency scan.
115+
func scaScanningEnabled(patterns []codacy.Pattern) bool {
116+
return lo.SomeBy(patterns, func(p codacy.Pattern) bool {
117+
return p.ID == ruleIDMaliciousPackages || lo.Contains(ruleIDsVulnerability, p.ID)
118+
})
119+
}
120+
110121
// runBaseScan will run a vulnerability scan that produces a report to be used for SBOM generation or for vulnerability issues.
111122
func (t codacyTrivy) runBaseScan(ctx context.Context, sourceDir string) (ptypes.Report, error) {
112123
config := flag.Options{

internal/tool/tool_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,75 @@ func TestRunVulnerabilityScanningNotEnabled(t *testing.T) {
627627
assert.Empty(t, results)
628628
}
629629

630+
func TestRunSkipsDependencyScanWhenScaNotEnabled(t *testing.T) {
631+
// Arrange
632+
srcDir, err := os.MkdirTemp("", "")
633+
if err != nil {
634+
assert.FailNow(t, "Failed to create tmp directory", err.Error())
635+
}
636+
defer os.RemoveAll(srcDir)
637+
638+
f, err := os.CreateTemp(srcDir, "file-")
639+
if err != nil {
640+
assert.FailNow(t, "Failed to create tmp file", err.Error())
641+
}
642+
defer f.Close()
643+
644+
if _, err := f.Write([]byte("AWS_ACCESS_KEY_ID=AKIA0123456789ABCDEF")); err != nil {
645+
assert.FailNow(t, "Failed to write to tmp file", err.Error())
646+
}
647+
648+
toolExecution := codacy.ToolExecution{
649+
Patterns: &[]codacy.Pattern{{ID: ruleIDSecret}},
650+
Files: &[]string{filepath.Base(f.Name())},
651+
SourceDir: srcDir,
652+
}
653+
654+
// A factory that only fails: reaching it at all would surface as an error from Run.
655+
underTest := codacyTrivy{runnerFactory: errorRunnerFactory{err: assert.AnError}}
656+
657+
// Act
658+
results, err := underTest.Run(context.Background(), toolExecution)
659+
660+
// Assert
661+
assert.NoError(t, err)
662+
assert.NotEmpty(t, results, "secret scanning still reports")
663+
664+
sboms := lo.Filter(results, func(result codacy.Result, _ int) bool {
665+
_, isSBOM := result.(codacy.SBOM)
666+
return isSBOM
667+
})
668+
assert.Empty(t, sboms, "the SBOM is derived from the dependency scan, so there is none")
669+
}
670+
671+
func TestScaScanningEnabled(t *testing.T) {
672+
// Arrange
673+
type testData struct {
674+
name string
675+
patterns []codacy.Pattern
676+
expected bool
677+
}
678+
679+
tests := []testData{
680+
{name: "no patterns", patterns: []codacy.Pattern{}, expected: false},
681+
{name: "only secret", patterns: []codacy.Pattern{{ID: ruleIDSecret}}, expected: false},
682+
{name: "only unknown", patterns: []codacy.Pattern{{ID: "unknown"}}, expected: false},
683+
{name: "a vulnerability severity", patterns: []codacy.Pattern{{ID: ruleIDVulnerabilityMinor}}, expected: true},
684+
{name: "malicious packages", patterns: []codacy.Pattern{{ID: ruleIDMaliciousPackages}}, expected: true},
685+
{
686+
name: "secret alongside a vulnerability severity",
687+
patterns: []codacy.Pattern{{ID: ruleIDSecret}, {ID: ruleIDVulnerabilityCritical}},
688+
expected: true,
689+
},
690+
}
691+
692+
for _, testData := range tests {
693+
t.Run(testData.name, func(t *testing.T) {
694+
assert.Equal(t, testData.expected, scaScanningEnabled(testData.patterns))
695+
})
696+
}
697+
}
698+
630699
func TestRunSecretScanningNotEnabled(t *testing.T) {
631700
toolExecution := codacy.ToolExecution{
632701
Patterns: &[]codacy.Pattern{{ID: ruleIDVulnerabilityMedium}},

0 commit comments

Comments
 (0)