Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cli/gitcommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"strings"

"github.com/jfrog/froggit-go/vcsutils"
outputFormat "github.com/jfrog/jfrog-cli-core/v2/common/format"
"github.com/jfrog/jfrog-cli-core/v2/common/progressbar"
pluginsCommon "github.com/jfrog/jfrog-cli-core/v2/plugins/common"
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
Expand All @@ -14,6 +13,7 @@ import (
gitContributorsDocs "github.com/jfrog/jfrog-cli-security/cli/docs/git/contributors"
"github.com/jfrog/jfrog-cli-security/commands/git/audit"
"github.com/jfrog/jfrog-cli-security/commands/git/contributors"
"github.com/jfrog/jfrog-cli-security/utils/formats"
"github.com/jfrog/jfrog-cli-security/utils/xsc"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
Expand Down Expand Up @@ -56,7 +56,7 @@ func GitAuditCmd(c *components.Context) error {
}
gitAuditCmd.SetServerDetails(serverDetails).SetXrayVersion(xrayVersion).SetXscVersion(xscVersion)
// Set violations params
format, err := outputFormat.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
format, err := formats.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
if err != nil {
return err
}
Expand Down
44 changes: 26 additions & 18 deletions cli/scancommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/jfrog/jfrog-cli-security/commands/sast_server"
"github.com/jfrog/jfrog-cli-security/commands/source_mcp"
"github.com/jfrog/jfrog-cli-security/sca/bom/indexer"
"github.com/jfrog/jfrog-cli-security/utils/formats"
"github.com/jfrog/jfrog-cli-security/utils/xray"

"github.com/jfrog/jfrog-cli-security/commands/audit"
Expand All @@ -56,8 +57,10 @@ import (
"github.com/jfrog/jfrog-cli-security/utils/xsc"
)

const DockerScanCmdHiddenName = "dockerscan"
const SkipCurationAfterFailureEnv = "JFROG_CLI_SKIP_CURATION_AFTER_FAILURE"
const (
DockerScanCmdHiddenName = "dockerscan"
SkipCurationAfterFailureEnv = "JFROG_CLI_SKIP_CURATION_AFTER_FAILURE"
)

func getAuditAndScansCommands() []components.Command {
return []components.Command{
Expand All @@ -71,13 +74,14 @@ func getAuditAndScansCommands() []components.Command {
Action: ScanCmd,
},
{
Name: "sbom-enrich",
Aliases: []string{"se"},
Flags: flags.GetCommandFlags(flags.Enrich),
Description: enrichDocs.GetDescription(),
Arguments: enrichDocs.GetArguments(),
Category: securityCategory,
Action: EnrichCmd,
Name: "sbom-enrich",
Aliases: []string{"se"},
Flags: flags.GetCommandFlags(flags.Enrich),
Description: enrichDocs.GetDescription(),
Arguments: enrichDocs.GetArguments(),
Category: securityCategory,
SupportedFormats: []outputFormat.OutputFormat{outputFormat.Json, outputFormat.Table},
Action: EnrichCmd,
},
{
Name: "malicious-scan",
Expand Down Expand Up @@ -211,7 +215,6 @@ func getAuditAndScansCommands() []components.Command {
}

func SourceMcpCmd(c *components.Context) error {

serverDetails, err := CreateServerDetailsFromFlags(c)
if err != nil {
return err
Expand Down Expand Up @@ -266,11 +269,16 @@ func EnrichCmd(c *components.Context) error {
if err != nil {
return err
}
EnrichCmd := enrich.NewEnrichCommand().
format, err := c.GetOutputFormat()
if err != nil {
return err
}
enrichCmd := enrich.NewEnrichCommand().
SetServerDetails(serverDetails).
SetThreads(threads).
SetSpec(specFile)
return commandsCommon.Exec(EnrichCmd)
SetSpec(specFile).
SetOutputFormat(format)
return commandsCommon.Exec(enrichCmd)
}

func MaliciousScanCmd(c *components.Context) error {
Expand All @@ -281,7 +289,7 @@ func MaliciousScanCmd(c *components.Context) error {
if err = validateConnectionInputs(serverDetails); err != nil {
return err
}
format, err := outputFormat.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
format, err := formats.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
if err != nil {
return err
}
Expand Down Expand Up @@ -318,7 +326,7 @@ func ScanCmd(c *components.Context) error {
if err != nil {
return err
}
format, err := outputFormat.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
format, err := formats.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
if err != nil {
return err
}
Expand Down Expand Up @@ -437,7 +445,7 @@ func BuildScan(c *components.Context) error {
if err != nil {
return err
}
format, err := outputFormat.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
format, err := formats.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
if err != nil {
return err
}
Expand Down Expand Up @@ -526,7 +534,7 @@ func CreateAuditCmd(c *components.Context) (string, string, *coreConfig.ServerDe
if err != nil {
return "", "", nil, nil, err
}
format, err := outputFormat.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
format, err := formats.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
if err != nil {
return "", "", nil, nil, err
}
Expand Down Expand Up @@ -789,7 +797,7 @@ func DockerScan(c *components.Context, image string) error {
if err != nil {
return err
}
format, err := outputFormat.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
format, err := formats.GetOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
if err != nil {
return err
}
Expand Down
44 changes: 41 additions & 3 deletions commands/enrich/enrich.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import (
"encoding/xml"
"errors"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"text/tabwriter"

coreformat "github.com/jfrog/jfrog-cli-core/v2/common/format"
"github.com/jfrog/jfrog-cli-security/utils/results/output"
"github.com/jfrog/jfrog-client-go/utils/errorutils"

Expand All @@ -31,14 +34,22 @@ import (
orderedJson "github.com/virtuald/go-ordered-json"
)

type FileContext func(string) parallel.TaskFunc
type indexFileHandlerFunc func(file string)
type (
FileContext func(string) parallel.TaskFunc
indexFileHandlerFunc func(file string)
)

type EnrichCommand struct {
serverDetails *config.ServerDetails
spec *spec.SpecFiles
threads int
progress ioUtils.ProgressMgr
outputFormat coreformat.OutputFormat
}

func (enrichCmd *EnrichCommand) SetOutputFormat(format coreformat.OutputFormat) *EnrichCommand {
enrichCmd.outputFormat = format
return enrichCmd
}

func (enrichCmd *EnrichCommand) SetProgress(progress ioUtils.ProgressMgr) {
Expand Down Expand Up @@ -180,7 +191,6 @@ func (enrichCmd *EnrichCommand) Run() (err error) {
if err = enrichCmd.progress.Quit(); err != nil {
return err
}

}

fileCollectingErr := fileCollectingErrorsQueue.GetError()
Expand All @@ -192,6 +202,13 @@ func (enrichCmd *EnrichCommand) Run() (err error) {
return errorutils.CheckError(scanResults.GetErrors())
}

if enrichCmd.outputFormat == coreformat.Table {
if err = enrichCmd.printVulnerabilitiesTable(scanResults, os.Stdout); err != nil {
return
}
log.Info("Enrich process completed successfully.")
return
}
isXml, err := isXML(scanResults.Targets)
if err != nil {
return
Expand All @@ -217,6 +234,27 @@ func (enrichCmd *EnrichCommand) CommandName() string {
return "xr_enrich"
}

func (enrichCmd *EnrichCommand) printVulnerabilitiesTable(cmdResults *results.SecurityCommandResults, w io.Writer) error {
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
if _, err := fmt.Fprintln(tw, "COMPONENT\tCVE-ID"); err != nil {
return err
}
for _, xrayResult := range cmdResults.GetScaScansXrayResults() {
for _, vuln := range xrayResult.Vulnerabilities {
cveID := ""
if len(vuln.Cves) > 0 {
cveID = vuln.Cves[0].Id
}
for component := range vuln.Components {
if _, err := fmt.Fprintf(tw, "%s\t%s\n", component, cveID); err != nil {
return err
}
}
}
}
return tw.Flush()
}

func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) {
go func() {
defer fileProducer.Done()
Expand Down
82 changes: 82 additions & 0 deletions commands/enrich/enrich_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package enrich

import (
"bytes"
"strings"
"testing"

coreformat "github.com/jfrog/jfrog-cli-core/v2/common/format"
"github.com/jfrog/jfrog-cli-security/utils"
"github.com/jfrog/jfrog-cli-security/utils/results"
"github.com/jfrog/jfrog-client-go/xray/services"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func makeCmdResultsWithVulns(vulns []services.Vulnerability) *results.SecurityCommandResults {
cmdResults := results.NewCommandResults(utils.SBOM)
target := cmdResults.NewScanResults(results.ScanTarget{Target: "test.json", Name: "test.json"})
target.ScaScanResults(0, services.ScanResponse{Vulnerabilities: vulns})
return cmdResults
}

func TestPrintVulnerabilitiesTable_WithFindings(t *testing.T) {
cmdResults := makeCmdResultsWithVulns([]services.Vulnerability{
{
Cves: []services.Cve{{Id: "CVE-2021-1234"}},
Components: map[string]services.Component{"pkg:npm/lodash@4.17.11": {}},
},
{
Cves: []services.Cve{{Id: "CVE-2020-9999"}},
Components: map[string]services.Component{"pkg:npm/minimist@1.2.5": {}},
},
})

cmd := &EnrichCommand{outputFormat: coreformat.Table}
var buf bytes.Buffer
err := cmd.printVulnerabilitiesTable(cmdResults, &buf)
require.NoError(t, err)

out := buf.String()
assert.Contains(t, out, "COMPONENT")
assert.Contains(t, out, "CVE-ID")
assert.Contains(t, out, "pkg:npm/lodash@4.17.11")
assert.Contains(t, out, "CVE-2021-1234")
assert.Contains(t, out, "pkg:npm/minimist@1.2.5")
assert.Contains(t, out, "CVE-2020-9999")
}

func TestPrintVulnerabilitiesTable_Empty(t *testing.T) {
cmdResults := makeCmdResultsWithVulns(nil)

cmd := &EnrichCommand{outputFormat: coreformat.Table}
var buf bytes.Buffer
err := cmd.printVulnerabilitiesTable(cmdResults, &buf)
require.NoError(t, err)

out := buf.String()
assert.Contains(t, out, "COMPONENT")
assert.Contains(t, out, "CVE-ID")
// no data rows
lines := strings.Split(strings.TrimSpace(out), "\n")
assert.Len(t, lines, 1)
}

func TestPrintVulnerabilitiesTable_NoCves(t *testing.T) {
cmdResults := makeCmdResultsWithVulns([]services.Vulnerability{
{
Cves: nil,
Components: map[string]services.Component{"pkg:go/golang.org/x/net@v0.0.0-20210226": {}},
},
})

cmd := &EnrichCommand{outputFormat: coreformat.Table}
var buf bytes.Buffer
err := cmd.printVulnerabilitiesTable(cmdResults, &buf)
require.NoError(t, err)

out := buf.String()
assert.Contains(t, out, "pkg:go/golang.org/x/net@v0.0.0-20210226")
// CVE-ID column is blank but row is present
assert.True(t, strings.Count(out, "\n") >= 2)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/jfrog/gofrog v1.7.6
github.com/jfrog/jfrog-apps-config v1.0.1
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260423195010-d7aa2c437305
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260427010241-873f53d940b3
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260428135824-dbef60cb4319
github.com/jfrog/jfrog-client-go v1.55.1-0.20260428070955-750b933dc5c7
github.com/magiconair/properties v1.8.10
github.com/owenrumney/go-sarif/v3 v3.2.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260423195010-d7aa2c437305 h1:w
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260423195010-d7aa2c437305/go.mod h1:6QJFQvde/CLnFeIIFOvm/6QuQr8OT1QWiTJAkQ+1Mnc=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260427010241-873f53d940b3 h1:LdLQQmhOMUfU+3x7wbtB7kY/Dd2LXKHz7CCUpHWn7uM=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260427010241-873f53d940b3/go.mod h1:qpD7einonjqskDTEyqeG3NzAbZO6se0s0Pet0ObBQ3I=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260428135824-dbef60cb4319 h1:3q0lNklwvW7icWAKR4cmEmwi3RNZEWtXRTuXOTFva64=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260428135824-dbef60cb4319/go.mod h1:qpD7einonjqskDTEyqeG3NzAbZO6se0s0Pet0ObBQ3I=
github.com/jfrog/jfrog-client-go v1.55.1-0.20260428070955-750b933dc5c7 h1:MvHnFczVntYB/USj7/RRANvdWbTUcwEvXcIGr7lOyTc=
github.com/jfrog/jfrog-client-go v1.55.1-0.20260428070955-750b933dc5c7/go.mod h1:sCE06+GngPoyrGO0c+vmhgMoVSP83UMNiZnIuNPzU8U=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
Expand Down
13 changes: 13 additions & 0 deletions utils/formats/output_format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package formats

import (
outputFormat "github.com/jfrog/jfrog-cli-core/v2/common/format"
)

func GetOutputFormat(format string) (f outputFormat.OutputFormat, err error) {
f = outputFormat.Table
if format != "" {
f, err = outputFormat.ParseOutputFormat(format, outputFormat.All)
}
return
}
Loading