3434from packageurl import PackageURL
3535
3636from . import __version__
37+ from .scanoss_settings import find_best_match
3738
3839
3940class SpdxLite :
@@ -42,12 +43,13 @@ class SpdxLite:
4243 Handle all interaction with SPDX Lite formatting
4344 """
4445
45- def __init__ (self , debug : bool = False , output_file : str = None ):
46+ def __init__ (self , debug : bool = False , output_file : str = None , scanoss_settings = None ):
4647 """
4748 Initialise the SpdxLite class
4849 """
4950 self .output_file = output_file
5051 self .debug = debug
52+ self .scanoss_settings = scanoss_settings
5153 self ._spdx_licenses = {} # Used to lookup for valid SPDX license identifiers
5254 self ._spdx_lic_names = {} # Used to look for SPDX license identifiers by name
5355
@@ -136,7 +138,9 @@ def _process_dependency_entry(self, file_path: str, entry: dict, summary: dict):
136138 if not self ._is_valid_purl (file_path , dep , purl , summary ):
137139 continue
138140 # Modifying the summary dictionary directly as it's passed by reference
139- summary [purl ] = self ._create_dependency_summary (dep )
141+ dep_summary = self ._create_dependency_summary (dep )
142+ dep_summary ['_file_path' ] = file_path
143+ summary [purl ] = dep_summary
140144
141145 def _process_file_entry (self , file_path : str , entry : dict , summary : dict ):
142146 """
@@ -156,7 +160,9 @@ def _process_file_entry(self, file_path: str, entry: dict, summary: dict):
156160 if not self ._is_valid_purl (file_path , entry , purl , summary ):
157161 return
158162
159- summary [purl ] = self ._create_file_summary (entry )
163+ file_summary = self ._create_file_summary (entry )
164+ file_summary ['_file_path' ] = file_path
165+ summary [purl ] = file_summary
160166
161167 def _is_valid_purl (self , file_path : str , entry : dict , purl : str , summary : dict ) -> bool :
162168 """
@@ -199,7 +205,6 @@ def _create_dependency_summary(self, dep: dict) -> dict:
199205 for field in ['component' , 'version' , 'url' ]:
200206 summary [field ] = dep .get (field , '' )
201207 summary ['licenses' ] = self ._process_licenses (dep .get ('licenses' ))
202- summary ['acknowledgement' ] = dep .get ('acknowledgement' )
203208 return summary
204209
205210 def _create_file_summary (self , entry : dict ) -> dict :
@@ -220,7 +225,6 @@ def _create_file_summary(self, entry: dict) -> dict:
220225 for field in fields :
221226 summary [field ] = entry .get (field )
222227 summary ['licenses' ] = self ._process_licenses (entry .get ('licenses' ))
223- summary ['acknowledgement' ] = entry .get ('acknowledgement' )
224228 return summary
225229
226230 def _process_licenses (self , licenses : list ) -> list :
@@ -293,6 +297,7 @@ def produce_from_json(self, data: json, output_file: str = None) -> bool:
293297 self .load_license_data ()
294298 spdx_document = self ._create_base_document (raw_data )
295299 self ._process_packages (raw_data , spdx_document )
300+ self ._build_annotations (raw_data , spdx_document )
296301 return self ._write_output (spdx_document , output_file )
297302
298303 def _create_base_document (self , raw_data : dict ) -> dict :
@@ -392,6 +397,36 @@ def _process_packages(self, raw_data: dict, spdx_document: dict):
392397
393398 self ._process_license_refs (lic_refs , spdx_document )
394399
400+ def _build_annotations (self , raw_data : dict , spdx_document : dict ):
401+ """Build SPDX annotations from BOM rules via ScanossSettings."""
402+ if not self .scanoss_settings :
403+ return
404+ all_entries = (self .scanoss_settings .get_bom_include ()
405+ + self .scanoss_settings .get_bom_replace ())
406+ entries_with_ack = [e for e in all_entries if e .acknowledgement ]
407+ if not entries_with_ack :
408+ return
409+ annotations = []
410+ org = self .scanoss_settings .get_organization ()
411+ for purl , comp in raw_data .items ():
412+ file_path = comp .get ('_file_path' , '' )
413+ match = find_best_match (file_path , [purl ], entries_with_ack )
414+ if match :
415+ ts = match .timestamp
416+ if not ts :
417+ self .print_stderr (
418+ f'Warning: No timestamp for annotation on { purl } , using current time'
419+ )
420+ ts = spdx_document ['creationInfo' ]['created' ]
421+ annotations .append ({
422+ 'annotationDate' : ts ,
423+ 'annotationType' : 'REVIEW' ,
424+ 'annotator' : f'Organization: { org } ' ,
425+ 'comment' : match .acknowledgement ,
426+ })
427+ if annotations :
428+ spdx_document ['annotations' ] = annotations
429+
395430 def _create_package_info (self , purl : str , comp : dict , lic_refs : set ) -> dict :
396431 """
397432 Create package information for SPDX document.
@@ -453,9 +488,6 @@ def _create_package_info(self, purl: str, comp: dict, lic_refs: set) -> dict:
453488 }
454489 ],
455490 }
456- acknowledgement = comp .get ('acknowledgement' )
457- if acknowledgement :
458- package_info ['comment' ] = acknowledgement
459491 return package_info
460492
461493 def _process_package_licenses (self , licenses : list , lic_refs : set ) -> str :
0 commit comments