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