From b1495a06818277b4e74fad30402e5f6e92f3163a Mon Sep 17 00:00:00 2001 From: david kopiel Date: Mon, 28 Apr 2025 23:56:47 +0300 Subject: [PATCH] feat: Improve jf scan summary for unsupported file types Adds warning for unsupported files and displays specific summary when only unsupported files are scanned. Avoids misleading 'No vulnerable components' message in this case. --- commands/scan/scan.go | 19 +++++++++++++++++ utils/results/output/resultwriter.go | 32 ++++++++++++++++++++++++++-- utils/results/results.go | 2 ++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 533c41c30..cfca28920 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -205,6 +205,10 @@ func (scanCmd *ScanCommand) indexFile(filePath string) (*xrayUtils.BinaryGraphNo var e *exec.ExitError if errors.As(err, &e) { if e.ExitCode() == fileNotSupportedExitCode { + + // --- ADDED LINE --- + log.Warn(fmt.Sprintf("Skipping scan for file '%s': File type not supported by JFrog Xray.", filePath)) + // --- END ADDED LINE --- log.Debug(fmt.Sprintf("File %s is not supported by Xray indexer app.", filePath)) return &indexerResults, nil } @@ -317,6 +321,21 @@ func (scanCmd *ScanCommand) RunScan(cmdType utils.CommandType) (cmdResults *resu // while the consumer uses the indexer to index those files. scanCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer, cmdResults) scanCmd.performScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer) + + // Initialize the flag to false by default + cmdResults.HasScannableComponents = false + // Iterate through the collected target results + for _, target := range cmdResults.Targets { + // Check if a technology was identified for the target. This implies + // successful indexing and that an SCA scan was likely performed or attempted. + // Check if Technology was identified (meaning indexing likely succeeded and scan was attempted) + if target.Technology != "" { + + cmdResults.HasScannableComponents = true + // Found at least one scannable component, no need to check further + break + } + } return } diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index ff1c3618f..05a432351 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -211,11 +211,39 @@ func (rw *ResultsWriter) printScaTablesIfNeeded(tableContent formats.ResultsTabl return } } + // --- START MODIFIED BLOCK --- if rw.commandResults.IncludesVulnerabilities() { - if err = PrintVulnerabilitiesTable(tableContent, rw.commandResults.CmdType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended); err != nil { - return + // Check if the results actually contain any vulnerabilities to display. + // We assume 'tableContent.SecurityVulnerabilitiesTable' holds the data prepared for the table. + // If this isn't the right way to check count, you might need to inspect 'tableContent' or 'rw.commandResults' further. + vulnerabilitiesExist := len(tableContent.SecurityVulnerabilitiesTable) > 0 + + if !vulnerabilitiesExist { + // CASE 1: No vulnerabilities were found. Now check *why*. + attemptedTargetCount := len(rw.commandResults.Targets) + hasScannable := rw.commandResults.HasScannableComponents // Use the flag you added + + if attemptedTargetCount > 0 && !hasScannable { + // Sub-case: Files were attempted, but none were scannable. Print specific message. + log.Output() // Add spacing for consistent formatting + fmt.Println("✨ Scan completed: No files of a supported type were found or scanned. ✨") + // Do not call PrintVulnerabilitiesTable + } else { + // Sub-case: No vulnerabilities found AND (either no files were attempted OR scannable files *were* found and clean). + // Let PrintVulnerabilitiesTable handle printing the standard "No vulnerable components" message. + if err = PrintVulnerabilitiesTable(tableContent, rw.commandResults.CmdType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended); err != nil { + return + } + } + } else { + // CASE 2: Vulnerabilities *were* found. Print the table as usual. + if err = PrintVulnerabilitiesTable(tableContent, rw.commandResults.CmdType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended); err != nil { + return + } } } + // --- END MODIFIED BLOCK --- + if rw.commandResults.IncludesLicenses() { if err = PrintLicensesTable(tableContent, rw.printExtended, rw.commandResults.CmdType); err != nil { return diff --git a/utils/results/results.go b/utils/results/results.go index 99965ba35..6c77d4487 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -30,6 +30,8 @@ type SecurityCommandResults struct { // MultiScanId is a unique identifier that is used to group multiple scans together. MultiScanId string `json:"multi_scan_id,omitempty"` // Results for each target in the command + HasScannableComponents bool `json:"has_scannable_components,omitempty"` + Targets []*TargetResults `json:"targets"` targetsMutex sync.Mutex `json:"-"` // GeneralError that occurred during the command execution