@@ -212,6 +212,10 @@ def _append_component(
212
212
else :
213
213
purl = new_component ['purl' ]
214
214
215
+ if not purl :
216
+ self .print_debug (f'WARNING: _append_component: No purl found for new component: { new_component } ' )
217
+ return components
218
+
215
219
component_key = f'{ purl } @{ new_component ["version" ]} '
216
220
components [component_key ] = {
217
221
'purl' : purl ,
@@ -222,14 +226,21 @@ def _append_component(
222
226
if not new_component .get ('licenses' ):
223
227
self .print_debug (f'WARNING: Results missing licenses. Skipping: { new_component } ' )
224
228
return components
229
+
230
+
231
+ licenses_order_by_source_priority = self ._get_licenses_order_by_source_priority (new_component ['licenses' ])
225
232
# Process licenses for this component
226
- for license_item in new_component [ 'licenses' ] :
233
+ for license_item in licenses_order_by_source_priority :
227
234
if license_item .get ('name' ):
228
235
spdxid = license_item ['name' ]
236
+ source = license_item .get ('source' )
237
+ if not source :
238
+ source = 'unknown'
229
239
components [component_key ]['licenses' ][spdxid ] = {
230
240
'spdxid' : spdxid ,
231
241
'copyleft' : self .license_util .is_copyleft (spdxid ),
232
242
'url' : self .license_util .get_spdx_url (spdxid ),
243
+ 'source' : source ,
233
244
}
234
245
return components
235
246
@@ -261,10 +272,12 @@ def _get_components_data(self, results: Dict[str, Any], components: Dict[str, An
261
272
if len (c .get ('purl' )) <= 0 :
262
273
self .print_debug (f'WARNING: Result missing purls. Skipping: { c } ' )
263
274
continue
264
- if not c .get ('version' ):
265
- self .print_msg (f'WARNING: Result missing version. Skipping: { c } ' )
266
- continue
267
- component_key = f'{ c ["purl" ][0 ]} @{ c ["version" ]} '
275
+ version = c .get ('version' )
276
+ if not version :
277
+ self .print_debug (f'WARNING: Result missing version. Setting it to unknown: { c } ' )
278
+ version = 'unknown'
279
+ c ['version' ] = version #If no version exists. Set 'unknown' version to current component
280
+ component_key = f'{ c ["purl" ][0 ]} @{ version } '
268
281
if component_key not in components :
269
282
components = self ._append_component (components , c , component_id , status )
270
283
# End component loop
@@ -296,10 +309,12 @@ def _get_dependencies_data(self, results: Dict[str, Any], components: Dict[str,
296
309
if not dependency .get ('purl' ):
297
310
self .print_debug (f'WARNING: Dependency result missing purl. Skipping: { dependency } ' )
298
311
continue
299
- if not dependency .get ('version' ):
300
- self .print_msg (f'WARNING: Dependency result missing version. Skipping: { dependency } ' )
301
- continue
302
- component_key = f'{ dependency ["purl" ]} @{ dependency ["version" ]} '
312
+ version = c .get ('version' )
313
+ if not version :
314
+ self .print_debug (f'WARNING: Result missing version. Setting it to unknown: { c } ' )
315
+ version = 'unknown'
316
+ c ['version' ] = version # If no version exists. Set 'unknown' version to current component
317
+ component_key = f'{ dependency ["purl" ]} @{ version } '
303
318
if component_key not in components :
304
319
components = self ._append_component (components , dependency , component_id , status )
305
320
# End dependency loop
@@ -411,6 +426,61 @@ def _load_input_file(self):
411
426
self .print_stderr (f'ERROR: Problem parsing input JSON: { e } ' )
412
427
return None
413
428
429
+ def _convert_components_to_list (self , components : dict ):
430
+ if components is None :
431
+ self .print_debug (f'WARNING: Components is empty { self .results } ' )
432
+ return None
433
+ results_list = list (components .values ())
434
+ for component in results_list :
435
+ licenses = component .get ('licenses' )
436
+ if licenses is not None :
437
+ component ['licenses' ] = list (licenses .values ())
438
+ else :
439
+ self .print_debug (f'WARNING: Licenses missing for: { component } ' )
440
+ component ['licenses' ] = []
441
+ return results_list
442
+
443
+ def _get_licenses_order_by_source_priority (self ,licenses_data ):
444
+ """
445
+ Select licenses based on source priority:
446
+ 1. component_declared (highest priority)
447
+ 2. license_file
448
+ 3. file_header
449
+ 4. scancode (lowest priority)
450
+
451
+ If any high-priority source is found, return only licenses from that source.
452
+ If none found, return all licenses.
453
+
454
+ Returns: list with ordered licenses by source.
455
+ """
456
+ # Define priority order (highest to lowest)
457
+ priority_sources = ['component_declared' , 'license_file' , 'file_header' , 'scancode' ]
458
+
459
+ # Group licenses by source
460
+ licenses_by_source = {}
461
+ for license_item in licenses_data :
462
+
463
+ source = license_item .get ('source' , 'unknown' )
464
+ if source not in licenses_by_source :
465
+ licenses_by_source [source ] = {}
466
+
467
+ license_name = license_item .get ('name' )
468
+ if license_name :
469
+ # Use license name as key, store full license object as value
470
+ # If duplicate license names exist in same source, the last one wins
471
+ licenses_by_source [source ][license_name ] = license_item
472
+
473
+ # Find the highest priority source that has licenses
474
+ for priority_source in priority_sources :
475
+ if priority_source in licenses_by_source :
476
+ self .print_trace (f'Choosing { priority_source } as source' )
477
+ return list (licenses_by_source [priority_source ].values ())
478
+
479
+ # If no priority sources found, combine all licenses into a single list
480
+ self .print_debug ("No priority sources found, returning all licenses as list" )
481
+ return licenses_data
482
+
483
+
414
484
#
415
485
# End of PolicyCheck Class
416
486
#
0 commit comments