Skip to content

Commit 579b70a

Browse files
Fix: CLI failes when running analyze with non exsisting file (#150)
* fix: Add path param validation - Added a new function to validate the existence of provided paths before analysis. - Updated the analyze command's short and long descriptions for clarity. - Improved error logging when failing to retrieve the current working directory. - Enhanced SARIF output merging to handle empty files and invalid JSON more gracefully.
1 parent f97be27 commit 579b70a

File tree

6 files changed

+141
-38
lines changed

6 files changed

+141
-38
lines changed

cmd/analyze.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,15 +369,33 @@ func runTool(workDirectory string, toolName string, pathsToCheck []string, outpu
369369
return runToolByName(toolName, workDirectory, pathsToCheck, autoFix, outputFile, outputFormat, tool, runtime)
370370
}
371371

372+
// validatePaths checks if all provided paths exist and returns an error if any don't
373+
func validatePaths(paths []string) error {
374+
for _, path := range paths {
375+
if _, err := os.Stat(path); os.IsNotExist(err) {
376+
return fmt.Errorf("❌ Error: cannot find file or directory '%s'", path)
377+
}
378+
}
379+
return nil
380+
}
381+
372382
var analyzeCmd = &cobra.Command{
373383
Use: "analyze",
374-
Short: "Runs all configured linters.",
375-
Long: "Runs all configured tools for code analysis. Use --tool flag to run a specific tool.",
384+
Short: "Analyze code using configured tools",
385+
Long: `Analyze code using configured tools and output results in the specified format.`,
376386
Run: func(cmd *cobra.Command, args []string) {
387+
// Validate paths before proceeding
388+
if err := validatePaths(args); err != nil {
389+
fmt.Println(err)
390+
os.Exit(1)
391+
}
392+
393+
// Get current working directory
377394
workDirectory, err := os.Getwd()
378395
if err != nil {
379-
log.Fatal(err)
396+
log.Fatalf("Failed to get current working directory: %v", err)
380397
}
398+
381399
var toolsToRun map[string]*plugins.ToolInfo
382400

383401
if toolsToAnalyzeParam != "" {

cmd/analyze_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,44 @@ func TestEslintInstallationValidationLogic(t *testing.T) {
221221
})
222222
}
223223
}
224+
225+
func TestValidatePaths(t *testing.T) {
226+
tests := []struct {
227+
name string
228+
paths []string
229+
expectError bool
230+
}{
231+
{
232+
name: "valid path",
233+
paths: []string{"."},
234+
expectError: false,
235+
},
236+
{
237+
name: "non-existent file",
238+
paths: []string{"non-existent-file.txt"},
239+
expectError: true,
240+
},
241+
{
242+
name: "multiple paths with one invalid",
243+
paths: []string{".", "non-existent-file.txt"},
244+
expectError: true,
245+
},
246+
{
247+
name: "empty paths",
248+
paths: []string{},
249+
expectError: false,
250+
},
251+
}
252+
253+
for _, tt := range tests {
254+
t.Run(tt.name, func(t *testing.T) {
255+
err := validatePaths(tt.paths)
256+
if tt.expectError {
257+
assert.Error(t, err)
258+
assert.Contains(t, err.Error(), "❌ Error: cannot find file or directory")
259+
} else {
260+
assert.NoError(t, err)
261+
}
262+
})
263+
}
264+
}
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
patterns:
22
Lizard_ccn-minor:
33
category: Complexity
4-
description: Check the Cyclomatic Complexity value of a function or logic block. If the threshold is not met, raise a Minor issue. The default threshold is 5.
4+
description: Checks that the cyclomatic complexity of functions or logic blocks does not exceed a minor threshold, defaulting to 5.
55
explanation: |-
66
# Minor Cyclomatic Complexity control
77
@@ -11,10 +11,10 @@ patterns:
1111
severityLevel: Info
1212
threshold: 5
1313
timeToFix: 5
14-
title: Minor Cyclomatic Complexity control
14+
title: Enforce Minor Cyclomatic Complexity Threshold
1515
Lizard_nloc-critical:
1616
category: Complexity
17-
description: Check the number of lines of code (without comments) in a function or logic block. If the threshold is not met, raise a Critical issue. The default threshold is 100.
17+
description: Checks if functions or logic blocks exceed a set maximum number of lines of code (excluding comments), defaulting to 100 lines.
1818
explanation: |-
1919
# Critical NLOC control - Number of Lines of Code (without comments)
2020
@@ -23,11 +23,11 @@ patterns:
2323
level: Error
2424
severityLevel: Error
2525
threshold: 100
26-
timeToFix: 5
27-
title: Critical NLOC control - Number of Lines of Code (without comments)
26+
timeToFix: 15
27+
title: Enforce Maximum Number of Lines of Code in Functions
2828
Lizard_nloc-medium:
2929
category: Complexity
30-
description: Check the number of lines of code (without comments) in a function. If the threshold is not met, raise a Medium issue. The default threshold is 50.
30+
description: Checks if the number of lines of code (excluding comments) in a function exceeds a medium threshold (default 50 lines).
3131
explanation: |-
3232
# Medium NLOC control - Number of Lines of Code (without comments)
3333
@@ -36,5 +36,5 @@ patterns:
3636
level: Warning
3737
severityLevel: Warning
3838
threshold: 50
39-
timeToFix: 5
40-
title: Medium NLOC control - Number of Lines of Code (without comments)
39+
timeToFix: 10
40+
title: Enforce Medium Number of Lines of Code (NLOC) Limit

integration-tests/init-without-token/expected/tools-configs/lizard.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ patterns:
1010
level: Warning
1111
severityLevel: Warning
1212
threshold: 8
13-
timeToFix: 5
13+
timeToFix: 10
1414
title: Enforce Medium Cyclomatic Complexity Threshold
1515
Lizard_file-nloc-medium:
1616
category: Complexity
@@ -20,7 +20,7 @@ patterns:
2020
level: Warning
2121
severityLevel: Warning
2222
threshold: 500
23-
timeToFix: 5
23+
timeToFix: 10
2424
title: Enforce Medium File Length Limit Based on Number of Lines of Code
2525
Lizard_nloc-medium:
2626
category: Complexity
@@ -33,7 +33,7 @@ patterns:
3333
level: Warning
3434
severityLevel: Warning
3535
threshold: 50
36-
timeToFix: 5
36+
timeToFix: 10
3737
title: Enforce Medium Number of Lines of Code (NLOC) Limit
3838
Lizard_parameter-count-medium:
3939
category: Complexity
@@ -46,5 +46,5 @@ patterns:
4646
level: Warning
4747
severityLevel: Warning
4848
threshold: 8
49-
timeToFix: 5
49+
timeToFix: 10
5050
title: Enforce Medium Parameter Count Limit
Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,79 @@
11
{
2-
"version": "2.1.0",
32
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
43
"runs": [
54
{
6-
"tool": {
7-
"driver": {
8-
"fullName": "Trivy Vulnerability Scanner",
9-
"informationUri": "https://github.com/aquasecurity/trivy",
10-
"name": "Trivy",
11-
"rules": null,
12-
"version": "0.59.1"
5+
"columnKind": "utf16CodeUnits",
6+
"originalUriBaseIds": {
7+
"ROOTPATH": {
8+
"uri": "file:///plugins/tools/trivy/test/src/"
139
}
1410
},
1511
"results": [
1612
{
17-
"ruleId": "CVE-2024-21538",
18-
"ruleIndex": 0,
1913
"level": "error",
14+
"locations": [
15+
{
16+
"message": {
17+
"text": "package-lock.json: [email protected]"
18+
},
19+
"physicalLocation": {
20+
"artifactLocation": {
21+
"uri": "package-lock.json",
22+
"uriBaseId": "ROOTPATH"
23+
},
24+
"region": {
25+
"endColumn": 1,
26+
"endLine": 527,
27+
"startColumn": 1,
28+
"startLine": 515
29+
}
30+
}
31+
}
32+
],
2033
"message": {
2134
"text": "Package: cross-spawn\nInstalled Version: 7.0.3\nVulnerability CVE-2024-21538\nSeverity: HIGH\nFixed Version: 7.0.5, 6.0.6\nLink: [CVE-2024-21538](https://avd.aquasec.com/nvd/cve-2024-21538)"
2235
},
36+
"ruleId": "CVE-2024-21538",
37+
"ruleIndex": 1
38+
},
39+
{
40+
"level": "note",
2341
"locations": [
2442
{
43+
"message": {
44+
"text": "package-lock.json: [email protected]"
45+
},
2546
"physicalLocation": {
2647
"artifactLocation": {
2748
"uri": "package-lock.json",
2849
"uriBaseId": "ROOTPATH"
2950
},
3051
"region": {
31-
"startLine": 515,
52+
"endColumn": 1,
53+
"endLine": 357,
3254
"startColumn": 1,
33-
"endLine": 527,
34-
"endColumn": 1
55+
"startLine": 349
3556
}
36-
},
37-
"message": {
38-
"text": "package-lock.json: [email protected]"
3957
}
4058
}
41-
]
59+
],
60+
"message": {
61+
"text": "Package: brace-expansion\nInstalled Version: 1.1.11\nVulnerability CVE-2025-5889\nSeverity: LOW\nFixed Version: 2.0.2, 1.1.12, 3.0.1, 4.0.1\nLink: [CVE-2025-5889](https://avd.aquasec.com/nvd/cve-2025-5889)"
62+
},
63+
"ruleId": "CVE-2025-5889",
64+
"ruleIndex": 0
4265
}
4366
],
44-
"columnKind": "utf16CodeUnits",
45-
"originalUriBaseIds": {
46-
"ROOTPATH": {
47-
"uri": "file:///plugins/tools/trivy/test/src/"
67+
"tool": {
68+
"driver": {
69+
"fullName": "Trivy Vulnerability Scanner",
70+
"informationUri": "https://github.com/aquasecurity/trivy",
71+
"name": "Trivy",
72+
"rules": null,
73+
"version": "0.59.1"
4874
}
4975
}
5076
}
51-
]
77+
],
78+
"version": "2.1.0"
5279
}

utils/sarif.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,26 @@ func MergeSarifOutputs(inputFiles []string, outputFile string) error {
204204
return fmt.Errorf("failed to read SARIF file %s: %w", file, err)
205205
}
206206

207+
// Skip empty files
208+
if len(data) == 0 {
209+
continue
210+
}
211+
207212
var sarif SimpleSarifReport
208213
if err := json.Unmarshal(data, &sarif); err != nil {
209-
return fmt.Errorf("failed to parse SARIF file %s: %w", file, err)
214+
// If file is empty or invalid JSON, create an empty SARIF report - extra protection from invalid files
215+
emptySarif := SimpleSarifReport{
216+
Version: "2.1.0",
217+
Schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
218+
Runs: []json.RawMessage{},
219+
}
220+
emptyData, err := json.Marshal(emptySarif)
221+
if err != nil {
222+
return fmt.Errorf("failed to create empty SARIF report: %w", err)
223+
}
224+
if err := json.Unmarshal(emptyData, &sarif); err != nil {
225+
return fmt.Errorf("failed to parse empty SARIF report: %w", err)
226+
}
210227
}
211228

212229
mergedSarif.Runs = append(mergedSarif.Runs, sarif.Runs...)

0 commit comments

Comments
 (0)