Skip to content

Commit a88f68c

Browse files
committed
JGC-480 - Add --format flag to sbom-enrich
1 parent b3269a8 commit a88f68c

5 files changed

Lines changed: 134 additions & 11 deletions

File tree

cli/scancommands.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,14 @@ func getAuditAndScansCommands() []components.Command {
7171
Action: ScanCmd,
7272
},
7373
{
74-
Name: "sbom-enrich",
75-
Aliases: []string{"se"},
76-
Flags: flags.GetCommandFlags(flags.Enrich),
77-
Description: enrichDocs.GetDescription(),
78-
Arguments: enrichDocs.GetArguments(),
79-
Category: securityCategory,
80-
Action: EnrichCmd,
74+
Name: "sbom-enrich",
75+
Aliases: []string{"se"},
76+
Flags: flags.GetCommandFlags(flags.Enrich),
77+
Description: enrichDocs.GetDescription(),
78+
Arguments: enrichDocs.GetArguments(),
79+
Category: securityCategory,
80+
SupportedFormats: []outputFormat.OutputFormat{outputFormat.Json, outputFormat.Table},
81+
Action: EnrichCmd,
8182
},
8283
{
8384
Name: "malicious-scan",
@@ -266,11 +267,16 @@ func EnrichCmd(c *components.Context) error {
266267
if err != nil {
267268
return err
268269
}
269-
EnrichCmd := enrich.NewEnrichCommand().
270+
format, err := c.GetOutputFormat()
271+
if err != nil {
272+
return err
273+
}
274+
enrichCmd := enrich.NewEnrichCommand().
270275
SetServerDetails(serverDetails).
271276
SetThreads(threads).
272-
SetSpec(specFile)
273-
return commandsCommon.Exec(EnrichCmd)
277+
SetSpec(specFile).
278+
SetOutputFormat(format)
279+
return commandsCommon.Exec(enrichCmd)
274280
}
275281

276282
func MaliciousScanCmd(c *components.Context) error {

commands/enrich/enrich.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import (
44
"encoding/xml"
55
"errors"
66
"fmt"
7+
"io"
78
"os"
89
"os/exec"
910
"path/filepath"
11+
"text/tabwriter"
1012

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

@@ -39,6 +42,12 @@ type EnrichCommand struct {
3942
spec *spec.SpecFiles
4043
threads int
4144
progress ioUtils.ProgressMgr
45+
outputFormat coreformat.OutputFormat
46+
}
47+
48+
func (enrichCmd *EnrichCommand) SetOutputFormat(format coreformat.OutputFormat) *EnrichCommand {
49+
enrichCmd.outputFormat = format
50+
return enrichCmd
4251
}
4352

4453
func (enrichCmd *EnrichCommand) SetProgress(progress ioUtils.ProgressMgr) {
@@ -192,6 +201,13 @@ func (enrichCmd *EnrichCommand) Run() (err error) {
192201
return errorutils.CheckError(scanResults.GetErrors())
193202
}
194203

204+
if enrichCmd.outputFormat == coreformat.Table {
205+
if err = enrichCmd.printVulnerabilitiesTable(scanResults, os.Stdout); err != nil {
206+
return
207+
}
208+
log.Info("Enrich process completed successfully.")
209+
return
210+
}
195211
isXml, err := isXML(scanResults.Targets)
196212
if err != nil {
197213
return
@@ -217,6 +233,23 @@ func (enrichCmd *EnrichCommand) CommandName() string {
217233
return "xr_enrich"
218234
}
219235

236+
func (enrichCmd *EnrichCommand) printVulnerabilitiesTable(cmdResults *results.SecurityCommandResults, w io.Writer) error {
237+
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
238+
fmt.Fprintln(tw, "COMPONENT\tCVE-ID")
239+
for _, xrayResult := range cmdResults.GetScaScansXrayResults() {
240+
for _, vuln := range xrayResult.Vulnerabilities {
241+
cveID := ""
242+
if len(vuln.Cves) > 0 {
243+
cveID = vuln.Cves[0].Id
244+
}
245+
for component := range vuln.Components {
246+
fmt.Fprintf(tw, "%s\t%s\n", component, cveID)
247+
}
248+
}
249+
}
250+
return tw.Flush()
251+
}
252+
220253
func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) {
221254
go func() {
222255
defer fileProducer.Done()

commands/enrich/enrich_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package enrich
2+
3+
import (
4+
"bytes"
5+
"strings"
6+
"testing"
7+
8+
coreformat "github.com/jfrog/jfrog-cli-core/v2/common/format"
9+
"github.com/jfrog/jfrog-cli-security/utils"
10+
"github.com/jfrog/jfrog-cli-security/utils/results"
11+
"github.com/jfrog/jfrog-client-go/xray/services"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func makeCmdResultsWithVulns(vulns []services.Vulnerability) *results.SecurityCommandResults {
17+
cmdResults := results.NewCommandResults(utils.SBOM)
18+
target := cmdResults.NewScanResults(results.ScanTarget{Target: "test.json", Name: "test.json"})
19+
target.ScaScanResults(0, services.ScanResponse{Vulnerabilities: vulns})
20+
return cmdResults
21+
}
22+
23+
func TestPrintVulnerabilitiesTable_WithFindings(t *testing.T) {
24+
cmdResults := makeCmdResultsWithVulns([]services.Vulnerability{
25+
{
26+
Cves: []services.Cve{{Id: "CVE-2021-1234"}},
27+
Components: map[string]services.Component{"pkg:npm/lodash@4.17.11": {}},
28+
},
29+
{
30+
Cves: []services.Cve{{Id: "CVE-2020-9999"}},
31+
Components: map[string]services.Component{"pkg:npm/minimist@1.2.5": {}},
32+
},
33+
})
34+
35+
cmd := &EnrichCommand{outputFormat: coreformat.Table}
36+
var buf bytes.Buffer
37+
err := cmd.printVulnerabilitiesTable(cmdResults, &buf)
38+
require.NoError(t, err)
39+
40+
out := buf.String()
41+
assert.Contains(t, out, "COMPONENT")
42+
assert.Contains(t, out, "CVE-ID")
43+
assert.Contains(t, out, "pkg:npm/lodash@4.17.11")
44+
assert.Contains(t, out, "CVE-2021-1234")
45+
assert.Contains(t, out, "pkg:npm/minimist@1.2.5")
46+
assert.Contains(t, out, "CVE-2020-9999")
47+
}
48+
49+
func TestPrintVulnerabilitiesTable_Empty(t *testing.T) {
50+
cmdResults := makeCmdResultsWithVulns(nil)
51+
52+
cmd := &EnrichCommand{outputFormat: coreformat.Table}
53+
var buf bytes.Buffer
54+
err := cmd.printVulnerabilitiesTable(cmdResults, &buf)
55+
require.NoError(t, err)
56+
57+
out := buf.String()
58+
assert.Contains(t, out, "COMPONENT")
59+
assert.Contains(t, out, "CVE-ID")
60+
// no data rows
61+
lines := strings.Split(strings.TrimSpace(out), "\n")
62+
assert.Len(t, lines, 1)
63+
}
64+
65+
func TestPrintVulnerabilitiesTable_NoCves(t *testing.T) {
66+
cmdResults := makeCmdResultsWithVulns([]services.Vulnerability{
67+
{
68+
Cves: nil,
69+
Components: map[string]services.Component{"pkg:go/golang.org/x/net@v0.0.0-20210226": {}},
70+
},
71+
})
72+
73+
cmd := &EnrichCommand{outputFormat: coreformat.Table}
74+
var buf bytes.Buffer
75+
err := cmd.printVulnerabilitiesTable(cmdResults, &buf)
76+
require.NoError(t, err)
77+
78+
out := buf.String()
79+
assert.Contains(t, out, "pkg:go/golang.org/x/net@v0.0.0-20210226")
80+
// CVE-ID column is blank but row is present
81+
assert.True(t, strings.Count(out, "\n") >= 2)
82+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/jfrog/gofrog v1.7.6
1717
github.com/jfrog/jfrog-apps-config v1.0.1
1818
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260423195010-d7aa2c437305
19-
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260427010241-873f53d940b3
19+
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260428135824-dbef60cb4319
2020
github.com/jfrog/jfrog-client-go v1.55.1-0.20260428070955-750b933dc5c7
2121
github.com/magiconair/properties v1.8.10
2222
github.com/owenrumney/go-sarif/v3 v3.2.3

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260423195010-d7aa2c437305 h1:w
173173
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260423195010-d7aa2c437305/go.mod h1:6QJFQvde/CLnFeIIFOvm/6QuQr8OT1QWiTJAkQ+1Mnc=
174174
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260427010241-873f53d940b3 h1:LdLQQmhOMUfU+3x7wbtB7kY/Dd2LXKHz7CCUpHWn7uM=
175175
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260427010241-873f53d940b3/go.mod h1:qpD7einonjqskDTEyqeG3NzAbZO6se0s0Pet0ObBQ3I=
176+
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260428135824-dbef60cb4319 h1:3q0lNklwvW7icWAKR4cmEmwi3RNZEWtXRTuXOTFva64=
177+
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260428135824-dbef60cb4319/go.mod h1:qpD7einonjqskDTEyqeG3NzAbZO6se0s0Pet0ObBQ3I=
176178
github.com/jfrog/jfrog-client-go v1.55.1-0.20260428070955-750b933dc5c7 h1:MvHnFczVntYB/USj7/RRANvdWbTUcwEvXcIGr7lOyTc=
177179
github.com/jfrog/jfrog-client-go v1.55.1-0.20260428070955-750b933dc5c7/go.mod h1:sCE06+GngPoyrGO0c+vmhgMoVSP83UMNiZnIuNPzU8U=
178180
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=

0 commit comments

Comments
 (0)