Skip to content

Commit f892978

Browse files
authored
Support a component list report command with column (--where) filters and --summary options (#85)
* Support a Component list/report command with filters and summary options Signed-off-by: Matt Rutkowski <[email protected]> * Assure all component display methods use pointers to ComponentMap entries Signed-off-by: Matt Rutkowski <[email protected]> * Add component list tests; support copyright column Signed-off-by: Matt Rutkowski <[email protected]> * Add tests for component list command using existing test data Signed-off-by: Matt Rutkowski <[email protected]> * Support where clause with float64 values; add testcase Signed-off-by: Matt Rutkowski <[email protected]> * Add Manufacturer, Publisher, HasPedigree columns to component list Signed-off-by: Matt Rutkowski <[email protected]> * Remove uncalled isEmpty() method Signed-off-by: Matt Rutkowski <[email protected]> * Add v1.6 testcase that includes varying component fields Signed-off-by: Matt Rutkowski <[email protected]> * Add JSON test files from the v1.6 spec. repo. Signed-off-by: Matt Rutkowski <[email protected]> * Add JSON test files from the v1.6 spec. repo. Signed-off-by: Matt Rutkowski <[email protected]> * Add JSON test files from the v1.6 spec. repo. Signed-off-by: Matt Rutkowski <[email protected]> * Add JSON test files from the v1.6 spec. repo. Signed-off-by: Matt Rutkowski <[email protected]> * prepare for more columns in component list output Signed-off-by: Matt Rutkowski <[email protected]> * Support full set of column data for component list Signed-off-by: Matt Rutkowski <[email protected]> * Consolidate report/list formatting flags Signed-off-by: Matt Rutkowski <[email protected]> * Improve README top-level abstract Signed-off-by: Matt Rutkowski <[email protected]> * Improve README top-level abstract Signed-off-by: Matt Rutkowski <[email protected]> * Improve README top-level abstract Signed-off-by: Matt Rutkowski <[email protected]> --------- Signed-off-by: Matt Rutkowski <[email protected]>
1 parent edc06ac commit f892978

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2588
-325
lines changed

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"BOMREF",
1313
"BSDL",
1414
"callstack",
15+
"CBOM",
1516
"CDLA",
1617
"cdxschema",
1718
"CISA",

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
This utility was designed to be an API platform to validate, analyze and edit **Bills-of-Materials (BOMs)**. Initially, it was created to validate **CycloneDX** or **SPDX-formatted** BOMs against versioned JSON schemas (as published by their respective standards communities) or customized schema variants designed by organizations that may have stricter compliance requirements.
66

7-
The utility now includes a rich set of commands, listed below, such as **trim**, **patch** (IETF RFC 6902) and **diff** as well as commands used to create filtered reports, in various formats, using the utility's powerful, SQL-like **query** command capability.
7+
Supported report commands can easily extract **component**, **service**, component **license**, **license policy**, **vulnerability** and other BOM information. These reports are designed to enable verification for most [BOM use cases](#cyclonedx-use-cases) as well as custom security and compliance requirements. Specifically, these commands can be used to create customized, filtered reports, in various formats *(e.g., CSV, markdown, JSON)*, using the utility's powerful, SQL-like **query** command capability to only include information *where* (i.e., using the `--where` flag) data values match specified patterns.
88

9-
Supported report commands can easily extract **license**, **license policy**, **vulnerability**, **component**, **service** and other BOM information enabling verification for most [BOM use cases](#cyclonedx-use-cases) as well as custom security and compliance requirements.
9+
The utility now includes a rich set of commands, listed below, such as **trim**, **patch** (IETF RFC 6902) and **diff**.
1010

1111
*Please note that the utility supports all BOM variants such as **Software** (SBOM), **Hardware** (HBOM), **Manufacturing** (MBOM), **AI/ML** (MLBOM), etc. that adhere to their respective schemas.*
1212

cmd/component.go

+128-46
Original file line numberDiff line numberDiff line change
@@ -39,40 +39,105 @@ const (
3939

4040
var VALID_SUBCOMMANDS_COMPONENT = []string{SUBCOMMAND_COMPONENT_LIST}
4141

42-
var COMPONENT_LIST_ROW_DATA = []ColumnFormatData{
43-
*NewColumnFormatData(COMPONENT_FILTER_KEY_TYPE, DEFAULT_COLUMN_TRUNCATE_LENGTH, REPORT_SUMMARY_DATA_TRUE, false),
44-
*NewColumnFormatData(COMPONENT_FILTER_KEY_NAME, DEFAULT_COLUMN_TRUNCATE_LENGTH, REPORT_SUMMARY_DATA_TRUE, false),
45-
*NewColumnFormatData(COMPONENT_FILTER_KEY_VERSION, DEFAULT_COLUMN_TRUNCATE_LENGTH, REPORT_SUMMARY_DATA_TRUE, false),
46-
*NewColumnFormatData(COMPONENT_FILTER_KEY_BOMREF, DEFAULT_COLUMN_TRUNCATE_LENGTH, REPORT_SUMMARY_DATA_TRUE, REPORT_REPLACE_LINE_FEEDS_TRUE),
47-
}
48-
4942
// filter keys
5043
// Note: these string values MUST match annotations for the ComponentInfo struct fields
51-
// Type string `json:"type"`
52-
// Publisher string `json:"publisher,omitempty"`
5344
// Scope string `json:"scope,omitempty"`
54-
// Copyright string `json:"copyright,omitempty"`
55-
// Cpe string `json:"cpe,omitempty"` // See: https://nvd.nist.gov/products/cpe
56-
// Purl string `json:"purl,omitempty" scvs:"bom:resource:identifiers:purl"` // See: https://github.com/package-url/purl-spec
57-
// Swid *CDXSwid `json:"swid,omitempty"`
5845
const (
59-
COMPONENT_FILTER_KEY_TYPE = "type"
60-
COMPONENT_FILTER_KEY_NAME = "name"
61-
COMPONENT_FILTER_KEY_VERSION = "version"
62-
COMPONENT_FILTER_KEY_BOMREF = "bom-ref"
46+
COMPONENT_FILTER_KEY_BOMREF = "bom-ref"
47+
COMPONENT_FILTER_KEY_GROUP = "group"
48+
COMPONENT_FILTER_KEY_TYPE = "type"
49+
COMPONENT_FILTER_KEY_NAME = "name"
50+
COMPONENT_FILTER_KEY_DESCRIPTION = "description"
51+
COMPONENT_FILTER_KEY_VERSION = "version"
52+
COMPONENT_FILTER_KEY_COPYRIGHT = "copyright"
53+
COMPONENT_FILTER_KEY_PURL = "purl"
54+
COMPONENT_FILTER_KEY_SWID = "swid-tag-id"
55+
COMPONENT_FILTER_KEY_CPE = "cpe"
56+
COMPONENT_FILTER_KEY_SUPPLIER_NAME = "supplier-name"
57+
COMPONENT_FILTER_KEY_SUPPLIER_URL = "supplier-url"
58+
COMPONENT_FILTER_KEY_MANUFACTURER_NAME = "manufacturer-name"
59+
COMPONENT_FILTER_KEY_MANUFACTURER_URL = "manufacturer-url"
60+
COMPONENT_FILTER_KEY_PUBLISHER = "publisher"
61+
COMPONENT_FILTER_KEY_NUM_LICENSES = "number-licenses"
62+
COMPONENT_FILTER_KEY_NUM_HASHES = "number-hashes"
63+
COMPONENT_FILTER_KEY_HAS_PEDIGREE = "has-pedigree"
64+
COMPONENT_FILTER_KEY_HAS_EVIDENCE = "has-evidence"
65+
COMPONENT_FILTER_KEY_MIME_TYPE = "mime-type"
66+
COMPONENT_FILTER_KEY_HAS_SCOPE = "scope"
67+
COMPONENT_FILTER_KEY_HAS_COMPONENTS = "has-components"
68+
COMPONENT_FILTER_KEY_HAS_RELEASE_NOTES = "has-release-notes"
69+
COMPONENT_FILTER_KEY_HAS_MODEL_CARD = "has-model-card"
70+
COMPONENT_FILTER_KEY_HAS_DATA = "has-data"
71+
COMPONENT_FILTER_KEY_HAS_TAGS = "has-tags"
72+
COMPONENT_FILTER_KEY_HAS_SIGNATURE = "has-signature"
6373
)
6474

6575
var VALID_COMPONENT_FILTER_KEYS = []string{
76+
COMPONENT_FILTER_KEY_BOMREF,
77+
COMPONENT_FILTER_KEY_GROUP,
6678
COMPONENT_FILTER_KEY_TYPE,
6779
COMPONENT_FILTER_KEY_NAME,
80+
COMPONENT_FILTER_KEY_DESCRIPTION,
6881
COMPONENT_FILTER_KEY_VERSION,
69-
COMPONENT_FILTER_KEY_BOMREF,
82+
COMPONENT_FILTER_KEY_COPYRIGHT,
83+
COMPONENT_FILTER_KEY_PURL,
84+
COMPONENT_FILTER_KEY_CPE,
85+
COMPONENT_FILTER_KEY_SWID,
86+
COMPONENT_FILTER_KEY_SUPPLIER_NAME,
87+
COMPONENT_FILTER_KEY_SUPPLIER_URL,
88+
COMPONENT_FILTER_KEY_MANUFACTURER_NAME,
89+
COMPONENT_FILTER_KEY_MANUFACTURER_URL,
90+
COMPONENT_FILTER_KEY_PUBLISHER,
91+
COMPONENT_FILTER_KEY_NUM_LICENSES,
92+
COMPONENT_FILTER_KEY_NUM_HASHES,
93+
COMPONENT_FILTER_KEY_HAS_PEDIGREE,
94+
COMPONENT_FILTER_KEY_HAS_EVIDENCE,
95+
COMPONENT_FILTER_KEY_MIME_TYPE,
96+
COMPONENT_FILTER_KEY_HAS_SCOPE,
97+
COMPONENT_FILTER_KEY_HAS_COMPONENTS,
98+
COMPONENT_FILTER_KEY_HAS_RELEASE_NOTES,
99+
COMPONENT_FILTER_KEY_HAS_MODEL_CARD,
100+
COMPONENT_FILTER_KEY_HAS_DATA,
101+
COMPONENT_FILTER_KEY_HAS_TAGS,
102+
COMPONENT_FILTER_KEY_HAS_SIGNATURE,
103+
}
104+
105+
var COMPONENT_LIST_ROW_DATA = []ColumnFormatData{
106+
*NewColumnFormatData(COMPONENT_FILTER_KEY_BOMREF, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
107+
*NewColumnFormatData(COMPONENT_FILTER_KEY_GROUP, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
108+
*NewColumnFormatData(COMPONENT_FILTER_KEY_TYPE, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
109+
*NewColumnFormatData(COMPONENT_FILTER_KEY_NAME, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
110+
*NewColumnFormatData(COMPONENT_FILTER_KEY_VERSION, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
111+
*NewColumnFormatData(COMPONENT_FILTER_KEY_DESCRIPTION, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, REPORT_REPLACE_LINE_FEEDS_TRUE),
112+
*NewColumnFormatData(COMPONENT_FILTER_KEY_COPYRIGHT, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
113+
*NewColumnFormatData(COMPONENT_FILTER_KEY_SUPPLIER_NAME, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
114+
*NewColumnFormatData(COMPONENT_FILTER_KEY_SUPPLIER_URL, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
115+
*NewColumnFormatData(COMPONENT_FILTER_KEY_MANUFACTURER_NAME, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
116+
*NewColumnFormatData(COMPONENT_FILTER_KEY_MANUFACTURER_URL, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
117+
*NewColumnFormatData(COMPONENT_FILTER_KEY_PUBLISHER, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
118+
*NewColumnFormatData(COMPONENT_FILTER_KEY_PURL, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
119+
*NewColumnFormatData(COMPONENT_FILTER_KEY_SWID, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
120+
*NewColumnFormatData(COMPONENT_FILTER_KEY_CPE, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
121+
*NewColumnFormatData(COMPONENT_FILTER_KEY_MIME_TYPE, REPORT_DO_NOT_TRUNCATE, false, false),
122+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_SCOPE, REPORT_DO_NOT_TRUNCATE, false, false),
123+
*NewColumnFormatData(COMPONENT_FILTER_KEY_NUM_HASHES, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
124+
*NewColumnFormatData(COMPONENT_FILTER_KEY_NUM_LICENSES, REPORT_DO_NOT_TRUNCATE, REPORT_SUMMARY_DATA, false),
125+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_PEDIGREE, REPORT_DO_NOT_TRUNCATE, false, false),
126+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_EVIDENCE, REPORT_DO_NOT_TRUNCATE, false, false),
127+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_COMPONENTS, REPORT_DO_NOT_TRUNCATE, false, false),
128+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_RELEASE_NOTES, REPORT_DO_NOT_TRUNCATE, false, false),
129+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_MODEL_CARD, REPORT_DO_NOT_TRUNCATE, false, false),
130+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_DATA, REPORT_DO_NOT_TRUNCATE, false, false),
131+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_TAGS, REPORT_DO_NOT_TRUNCATE, false, false),
132+
*NewColumnFormatData(COMPONENT_FILTER_KEY_HAS_SIGNATURE, REPORT_DO_NOT_TRUNCATE, false, false),
70133
}
71134

72135
// Flags. Reuse query flag values where possible
73136
const (
74-
FLAG_COMPONENT_TYPE = "type"
75-
FLAG_COMPONENT_TYPE_HELP = "filter output by component type(s)"
137+
FLAG_COMPONENT_SUMMARY = "summary"
138+
FLAG_COMPONENT_TYPE = "type"
139+
// FLAG_COMPONENT_TYPE_HELP = "filter output by component type(s)"
140+
FLAG_COMPONENT_SUMMARY_HELP = "summarize component information when listing in supported formats"
76141
)
77142

78143
const (
@@ -94,7 +159,11 @@ func NewCommandComponent() *cobra.Command {
94159
command.Long = "Report on components found in the BOM input file"
95160
command.Flags().StringVarP(&utils.GlobalFlags.PersistentFlags.OutputFormat, FLAG_FILE_OUTPUT_FORMAT, "", FORMAT_TEXT,
96161
FLAG_COMPONENT_OUTPUT_FORMAT_HELP+COMPONENT_LIST_OUTPUT_SUPPORTED_FORMATS)
97-
command.Flags().StringP(FLAG_COMPONENT_TYPE, "", "", FLAG_COMPONENT_TYPE_HELP)
162+
//command.Flags().StringP(FLAG_COMPONENT_TYPE, "", "", FLAG_COMPONENT_TYPE_HELP)
163+
command.Flags().BoolVarP(
164+
&utils.GlobalFlags.ComponentFlags.Summary,
165+
FLAG_COMPONENT_SUMMARY, "", false,
166+
FLAG_COMPONENT_SUMMARY_HELP)
98167
command.Flags().StringP(FLAG_REPORT_WHERE, "", "", FLAG_REPORT_WHERE_HELP)
99168
command.RunE = componentCmdImpl
100169
command.ValidArgs = VALID_SUBCOMMANDS_COMPONENT
@@ -145,7 +214,7 @@ func componentCmdImpl(cmd *cobra.Command, args []string) (err error) {
145214
whereFilters, err := processWhereFlag(cmd)
146215

147216
if err == nil {
148-
err = ListComponents(writer, utils.GlobalFlags.PersistentFlags, whereFilters)
217+
err = ListComponents(writer, utils.GlobalFlags.PersistentFlags, utils.GlobalFlags.ComponentFlags, whereFilters)
149218
}
150219

151220
return
@@ -160,7 +229,7 @@ func processComponentListResults(err error) {
160229
}
161230

162231
// NOTE: resourceType has already been validated
163-
func ListComponents(writer io.Writer, persistentFlags utils.PersistentCommandFlags, whereFilters []common.WhereFilter) (err error) {
232+
func ListComponents(writer io.Writer, persistentFlags utils.PersistentCommandFlags, flags utils.ComponentCommandFlags, whereFilters []common.WhereFilter) (err error) {
164233
getLogger().Enter()
165234
defer getLogger().Exit()
166235

@@ -191,16 +260,16 @@ func ListComponents(writer io.Writer, persistentFlags utils.PersistentCommandFla
191260
getLogger().Infof("Outputting listing (`%s` format)...", format)
192261
switch format {
193262
case FORMAT_TEXT:
194-
err = DisplayComponentListText(document, writer)
263+
err = DisplayComponentListText(document, writer, flags)
195264
case FORMAT_CSV:
196-
err = DisplayComponentListCSV(document, writer)
265+
err = DisplayComponentListCSV(document, writer, flags)
197266
case FORMAT_MARKDOWN:
198-
err = DisplayComponentListMarkdown(document, writer)
267+
err = DisplayComponentListMarkdown(document, writer, flags)
199268
default:
200269
// Default to Text output for anything else (set as flag default)
201270
getLogger().Warningf("Listing not supported for `%s` format; defaulting to `%s` format...",
202271
format, FORMAT_TEXT)
203-
err = DisplayComponentListText(document, writer)
272+
err = DisplayComponentListText(document, writer, flags)
204273
}
205274
return
206275
}
@@ -232,21 +301,25 @@ func loadDocumentComponents(document *schema.BOM, whereFilters []common.WhereFil
232301
return
233302
}
234303

304+
// NOTE: component hashmap values are pointers to CDXComponentInfo structs
235305
func sortComponents(entries []multimap.Entry) {
236306
// Sort by Type then Name
237307
sort.Slice(entries, func(i, j int) bool {
238-
resource1 := (entries[i].Value).(schema.CDXComponentInfo)
239-
resource2 := (entries[j].Value).(schema.CDXComponentInfo)
240-
if resource1.ResourceType != resource2.ResourceType {
241-
return resource1.ResourceType < resource2.ResourceType
308+
resource1 := (entries[i].Value).(*schema.CDXComponentInfo)
309+
resource2 := (entries[j].Value).(*schema.CDXComponentInfo)
310+
if resource1.Group != resource2.Group {
311+
return resource1.Group < resource2.Group
312+
}
313+
if resource1.Type != resource2.Type {
314+
return resource1.Type < resource2.Type
242315
}
243316
return resource1.Name < resource2.Name
244317
})
245318
}
246319

247320
// NOTE: This list is NOT de-duplicated
248321
// TODO: Add a --no-title flag to skip title output
249-
func DisplayComponentListText(bom *schema.BOM, writer io.Writer) (err error) {
322+
func DisplayComponentListText(bom *schema.BOM, writer io.Writer, flags utils.ComponentCommandFlags) (err error) {
250323
getLogger().Enter()
251324
defer getLogger().Exit()
252325

@@ -258,7 +331,7 @@ func DisplayComponentListText(bom *schema.BOM, writer io.Writer) (err error) {
258331
w.Init(writer, 8, 2, 2, ' ', 0)
259332

260333
// create title row and underline row from slices of optional and compulsory titles
261-
titles, underlines := prepareReportTitleData(COMPONENT_LIST_ROW_DATA, true)
334+
titles, underlines := prepareReportTitleData(COMPONENT_LIST_ROW_DATA, flags.Summary)
262335

263336
// Add tabs between column titles for the tabWRiter
264337
fmt.Fprintf(w, "%s\n", strings.Join(titles, "\t"))
@@ -278,11 +351,14 @@ func DisplayComponentListText(bom *schema.BOM, writer io.Writer) (err error) {
278351

279352
// Emit row data
280353
var line []string
354+
var pComponentInfo *schema.CDXComponentInfo
281355
for _, entry := range entries {
356+
// NOTE: component hashmap values are pointers to CDXComponentInfo structs
357+
pComponentInfo = entry.Value.(*schema.CDXComponentInfo)
282358
line, err = prepareReportLineData(
283-
entry.Value.(schema.CDXComponentInfo),
359+
*pComponentInfo,
284360
COMPONENT_LIST_ROW_DATA,
285-
true,
361+
flags.Summary,
286362
)
287363
// Only emit line if no error
288364
if err != nil {
@@ -294,7 +370,7 @@ func DisplayComponentListText(bom *schema.BOM, writer io.Writer) (err error) {
294370
}
295371

296372
// TODO: Add a --no-title flag to skip title output
297-
func DisplayComponentListCSV(bom *schema.BOM, writer io.Writer) (err error) {
373+
func DisplayComponentListCSV(bom *schema.BOM, writer io.Writer, flags utils.ComponentCommandFlags) (err error) {
298374
getLogger().Enter()
299375
defer getLogger().Exit()
300376

@@ -303,14 +379,14 @@ func DisplayComponentListCSV(bom *schema.BOM, writer io.Writer) (err error) {
303379
defer w.Flush()
304380

305381
// Create title row data as []string
306-
titles, _ := prepareReportTitleData(COMPONENT_LIST_ROW_DATA, true)
382+
titles, _ := prepareReportTitleData(COMPONENT_LIST_ROW_DATA, flags.Summary)
307383

308384
if err = w.Write(titles); err != nil {
309385
return getLogger().Errorf("error writing to output (%v): %s", titles, err)
310386
}
311387

312388
// Display a warning "missing" in the actual output and return (short-circuit)
313-
entries := bom.ResourceMap.Entries()
389+
entries := bom.ComponentMap.Entries()
314390

315391
// Emit no resource found warning into output
316392
if len(entries) == 0 {
@@ -326,11 +402,14 @@ func DisplayComponentListCSV(bom *schema.BOM, writer io.Writer) (err error) {
326402
sortComponents(entries)
327403

328404
var line []string
405+
var pComponentInfo *schema.CDXComponentInfo
329406
for _, entry := range entries {
407+
// NOTE: component hashmap values are pointers to CDXComponentInfo structs
408+
pComponentInfo = entry.Value.(*schema.CDXComponentInfo)
330409
line, err = prepareReportLineData(
331-
entry.Value.(schema.CDXResourceInfo),
410+
*pComponentInfo,
332411
COMPONENT_LIST_ROW_DATA,
333-
true,
412+
flags.Summary,
334413
)
335414
// Only emit line if no error
336415
if err != nil {
@@ -344,22 +423,22 @@ func DisplayComponentListCSV(bom *schema.BOM, writer io.Writer) (err error) {
344423
}
345424

346425
// TODO: Add a --no-title flag to skip title output
347-
func DisplayComponentListMarkdown(bom *schema.BOM, writer io.Writer) (err error) {
426+
func DisplayComponentListMarkdown(bom *schema.BOM, writer io.Writer, flags utils.ComponentCommandFlags) (err error) {
348427
getLogger().Enter()
349428
defer getLogger().Exit()
350429

351430
// Create title row data as []string, include all columns that are flagged "summary" data
352-
titles, _ := prepareReportTitleData(COMPONENT_LIST_ROW_DATA, true)
431+
titles, _ := prepareReportTitleData(COMPONENT_LIST_ROW_DATA, flags.Summary)
353432
titleRow := createMarkdownRow(titles)
354433
fmt.Fprintf(writer, "%s\n", titleRow)
355434

356435
// create alignment row, include all columns that are flagged "summary" data
357-
alignments := createMarkdownColumnAlignmentRow(COMPONENT_LIST_ROW_DATA, true)
436+
alignments := createMarkdownColumnAlignmentRow(COMPONENT_LIST_ROW_DATA, flags.Summary)
358437
alignmentRow := createMarkdownRow(alignments)
359438
fmt.Fprintf(writer, "%s\n", alignmentRow)
360439

361440
// Display a warning "missing" in the actual output and return (short-circuit)
362-
entries := bom.ResourceMap.Entries()
441+
entries := bom.ComponentMap.Entries()
363442

364443
// Emit no components found warning into output
365444
if len(entries) == 0 {
@@ -372,11 +451,14 @@ func DisplayComponentListMarkdown(bom *schema.BOM, writer io.Writer) (err error)
372451

373452
var line []string
374453
var lineRow string
454+
var pComponentInfo *schema.CDXComponentInfo
375455
for _, entry := range entries {
456+
// NOTE: component hashmap values are pointers to CDXComponentInfo structs
457+
pComponentInfo = entry.Value.(*schema.CDXComponentInfo)
376458
line, err = prepareReportLineData(
377-
entry.Value.(schema.CDXResourceInfo),
459+
*pComponentInfo,
378460
COMPONENT_LIST_ROW_DATA,
379-
true,
461+
flags.Summary,
380462
)
381463
// Only emit line if no error
382464
if err != nil {

0 commit comments

Comments
 (0)