@@ -22,7 +22,6 @@ import (
22
22
"encoding/csv"
23
23
"fmt"
24
24
"io"
25
- "reflect"
26
25
"sort"
27
26
"strings"
28
27
"text/tabwriter"
@@ -260,156 +259,14 @@ func loadDocumentVulnerabilities(document *schema.BOM, whereFilters []common.Whe
260
259
// Hash all components found in the (root).components[] (+ "nested" components)
261
260
pVulnerabilities := document .GetCdxVulnerabilities ()
262
261
if pVulnerabilities != nil && len (* pVulnerabilities ) > 0 {
263
- if err = hashVulnerabilities ( document , * pVulnerabilities , whereFilters ); err != nil {
262
+ if err = document . HashVulnerabilities ( * pVulnerabilities , whereFilters ); err != nil {
264
263
return
265
264
}
266
265
}
267
266
268
267
return
269
268
}
270
269
271
- // We need to hash our own informational structure around the CDX data in order
272
- // to simplify --where queries to command line users
273
- func hashVulnerabilities (bom * schema.BOM , vulnerabilities []schema.CDXVulnerability , whereFilters []common.WhereFilter ) (err error ) {
274
- getLogger ().Enter ()
275
- defer getLogger ().Exit (err )
276
-
277
- for _ , cdxVulnerability := range vulnerabilities {
278
- _ , err = hashVulnerability (bom , cdxVulnerability , whereFilters )
279
- if err != nil {
280
- return
281
- }
282
- }
283
- return
284
- }
285
-
286
- // Hash a CDX Component and recursively those of any "nested" components
287
- // TODO we should WARN if version is not a valid semver (e.g., examples/cyclonedx/BOM/laravel-7.12.0/bom.1.3.json)
288
- func hashVulnerability (bom * schema.BOM , cdxVulnerability schema.CDXVulnerability , whereFilters []common.WhereFilter ) (vi * schema.VulnerabilityInfo , err error ) {
289
- getLogger ().Enter ()
290
- defer getLogger ().Exit (err )
291
- var vulnInfo schema.VulnerabilityInfo
292
- vi = & vulnInfo
293
-
294
- if reflect .DeepEqual (cdxVulnerability , schema.CDXVulnerability {}) {
295
- err = getLogger ().Errorf ("invalid vulnerability info: missing or empty : %v " , cdxVulnerability )
296
- return
297
- }
298
-
299
- if cdxVulnerability .Id == "" {
300
- getLogger ().Warningf ("vulnerability missing required value `id` : %v " , cdxVulnerability )
301
- }
302
-
303
- if cdxVulnerability .Published == "" {
304
- getLogger ().Warningf ("vulnerability (`%s`) missing `published` date" , cdxVulnerability .Id )
305
- }
306
-
307
- if cdxVulnerability .Created == "" {
308
- getLogger ().Warningf ("vulnerability (`%s`) missing `created` date" , cdxVulnerability .Id )
309
- }
310
-
311
- if len (cdxVulnerability .Ratings ) == 0 {
312
- getLogger ().Warningf ("vulnerability (`%s`) missing `ratings`" , cdxVulnerability .Id )
313
- }
314
-
315
- // hash any component w/o a license using special key name
316
- vulnInfo .Vulnerability = cdxVulnerability
317
- if cdxVulnerability .BOMRef != nil {
318
- vulnInfo .BOMRef = cdxVulnerability .BOMRef .String ()
319
- }
320
- vulnInfo .Id = cdxVulnerability .Id
321
-
322
- // Truncate dates from 2023-02-02T00:00:00.000Z to 2023-02-02
323
- // Note: if validation errors are found by the "truncate" function,
324
- // it will emit an error and return the original (failing) value
325
- dateTime , _ := utils .TruncateTimeStampISO8601Date (cdxVulnerability .Created )
326
- vulnInfo .Created = dateTime
327
-
328
- dateTime , _ = utils .TruncateTimeStampISO8601Date (cdxVulnerability .Published )
329
- vulnInfo .Published = dateTime
330
-
331
- dateTime , _ = utils .TruncateTimeStampISO8601Date (cdxVulnerability .Updated )
332
- vulnInfo .Updated = dateTime
333
-
334
- dateTime , _ = utils .TruncateTimeStampISO8601Date (cdxVulnerability .Rejected )
335
- vulnInfo .Rejected = dateTime
336
-
337
- vulnInfo .Description = cdxVulnerability .Description
338
-
339
- // Source object: retrieve report fields from nested objects
340
- if cdxVulnerability .Source != nil {
341
- source := * cdxVulnerability .Source
342
- vulnInfo .Source = source
343
- vulnInfo .SourceName = source .Name
344
- vulnInfo .SourceUrl = source .Url
345
- }
346
-
347
- // TODO: replace empty Analysis values with "UNDEFINED"
348
- vulnInfo .AnalysisState = cdxVulnerability .Analysis .State
349
- if vulnInfo .AnalysisState == "" {
350
- vulnInfo .AnalysisState = schema .VULN_ANALYSIS_STATE_EMPTY
351
- }
352
-
353
- vulnInfo .AnalysisJustification = cdxVulnerability .Analysis .Justification
354
- if vulnInfo .AnalysisJustification == "" {
355
- vulnInfo .AnalysisJustification = schema .VULN_ANALYSIS_STATE_EMPTY
356
- }
357
- vulnInfo .AnalysisResponse = cdxVulnerability .Analysis .Response
358
- if len (vulnInfo .AnalysisResponse ) == 0 {
359
- vulnInfo .AnalysisResponse = []string {schema .VULN_ANALYSIS_STATE_EMPTY }
360
- }
361
-
362
- // Convert []int to []string for --where filter
363
- // TODO see if we can eliminate this conversion and handle while preparing report data
364
- // as this SHOULD appear there as []interface{}
365
- if len (cdxVulnerability .Cwes ) > 0 {
366
- vulnInfo .CweIds = strings .Fields (strings .Trim (fmt .Sprint (cdxVulnerability .Cwes ), "[]" ))
367
- }
368
-
369
- // CVSS Score Qualitative Rating
370
- // 0.0 None
371
- // 0.1 – 3.9 Low
372
- // 4.0 – 6.9 Medium
373
- // 7.0 – 8.9 High
374
- // 9.0 – 10.0 Critical
375
-
376
- // TODO: if summary report, see if more than one severity can be shown without clogging up column data
377
- numRatings := len (cdxVulnerability .Ratings )
378
- if numRatings > 0 {
379
- //var sourceMatch int
380
- for _ , rating := range cdxVulnerability .Ratings {
381
- // defer to same source as the top-level vuln. declares
382
- fSeverity := fmt .Sprintf ("%s: %v (%s)" , rating .Method , rating .Score , rating .Severity )
383
- // give listing priority to ratings that matches top-level vuln. reporting source
384
- if rating .Source .Name == cdxVulnerability .Source .Name {
385
- // prepend to slice
386
- vulnInfo .CvssSeverity = append ([]string {fSeverity }, vulnInfo .CvssSeverity ... )
387
- continue
388
- }
389
- vulnInfo .CvssSeverity = append (vulnInfo .CvssSeverity , fSeverity )
390
- }
391
-
392
- } else {
393
- // Set first entry to empty value (i.e., "none")
394
- vulnInfo .CvssSeverity = append (vulnInfo .CvssSeverity , schema .VULN_RATING_EMPTY )
395
- }
396
-
397
- var match bool = true
398
- if len (whereFilters ) > 0 {
399
- mapVulnInfo , _ := utils .MarshalStructToJsonMap (vulnInfo )
400
- match , _ = whereFilterMatch (mapVulnInfo , whereFilters )
401
- }
402
-
403
- if match {
404
- bom .VulnerabilityMap .Put (vulnInfo .Id , vulnInfo )
405
-
406
- getLogger ().Tracef ("Put: %s (`%s`), `%s`)" ,
407
- vulnInfo .Id , vulnInfo .Description , vulnInfo .BOMRef )
408
- }
409
-
410
- return
411
- }
412
-
413
270
// NOTE: This list is NOT de-duplicated
414
271
// TODO: Add a --no-title flag to skip title output
415
272
func DisplayVulnListText (bom * schema.BOM , output io.Writer , flags utils.VulnerabilityCommandFlags ) {
0 commit comments