scanoss 1.25.0__tar.gz → 1.25.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. {scanoss-1.25.0/src/scanoss.egg-info → scanoss-1.25.2}/PKG-INFO +1 -1
  2. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/__init__.py +1 -1
  3. scanoss-1.25.2/src/scanoss/data/build_date.txt +1 -0
  4. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/inspection/copyleft.py +23 -2
  5. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/inspection/policy_check.py +101 -54
  6. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/inspection/undeclared_component.py +46 -15
  7. {scanoss-1.25.0 → scanoss-1.25.2/src/scanoss.egg-info}/PKG-INFO +1 -1
  8. {scanoss-1.25.0 → scanoss-1.25.2}/tests/test_policy_inspect.py +16 -53
  9. scanoss-1.25.0/src/scanoss/data/build_date.txt +0 -1
  10. {scanoss-1.25.0 → scanoss-1.25.2}/LICENSE +0 -0
  11. {scanoss-1.25.0 → scanoss-1.25.2}/PACKAGE.md +0 -0
  12. {scanoss-1.25.0 → scanoss-1.25.2}/README.md +0 -0
  13. {scanoss-1.25.0 → scanoss-1.25.2}/pyproject.toml +0 -0
  14. {scanoss-1.25.0 → scanoss-1.25.2}/setup.cfg +0 -0
  15. {scanoss-1.25.0 → scanoss-1.25.2}/src/protoc_gen_swagger/__init__.py +0 -0
  16. {scanoss-1.25.0 → scanoss-1.25.2}/src/protoc_gen_swagger/options/__init__.py +0 -0
  17. {scanoss-1.25.0 → scanoss-1.25.2}/src/protoc_gen_swagger/options/annotations_pb2.py +0 -0
  18. {scanoss-1.25.0 → scanoss-1.25.2}/src/protoc_gen_swagger/options/annotations_pb2_grpc.py +0 -0
  19. {scanoss-1.25.0 → scanoss-1.25.2}/src/protoc_gen_swagger/options/openapiv2_pb2.py +0 -0
  20. {scanoss-1.25.0 → scanoss-1.25.2}/src/protoc_gen_swagger/options/openapiv2_pb2_grpc.py +0 -0
  21. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/__init__.py +0 -0
  22. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/common/__init__.py +0 -0
  23. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/common/v2/__init__.py +0 -0
  24. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/common/v2/scanoss_common_pb2.py +0 -0
  25. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/common/v2/scanoss_common_pb2_grpc.py +0 -0
  26. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/components/__init__.py +0 -0
  27. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/components/v2/__init__.py +0 -0
  28. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/components/v2/scanoss_components_pb2.py +0 -0
  29. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/components/v2/scanoss_components_pb2_grpc.py +0 -0
  30. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +0 -0
  31. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +0 -0
  32. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/dependencies/__init__.py +0 -0
  33. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/dependencies/v2/__init__.py +0 -0
  34. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +0 -0
  35. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +0 -0
  36. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/geoprovenance/__init__.py +0 -0
  37. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/geoprovenance/v2/__init__.py +0 -0
  38. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +0 -0
  39. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +0 -0
  40. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/scanning/__init__.py +0 -0
  41. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/scanning/v2/__init__.py +0 -0
  42. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2.py +0 -0
  43. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +0 -0
  44. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/semgrep/__init__.py +0 -0
  45. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/semgrep/v2/__init__.py +0 -0
  46. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +0 -0
  47. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +0 -0
  48. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/vulnerabilities/__init__.py +0 -0
  49. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/vulnerabilities/v2/__init__.py +0 -0
  50. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +0 -0
  51. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +0 -0
  52. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/cli.py +0 -0
  53. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/components.py +0 -0
  54. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/constants.py +0 -0
  55. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/cryptography.py +0 -0
  56. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/csvoutput.py +0 -0
  57. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/cyclonedx.py +0 -0
  58. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/data/scanoss-settings-schema.json +0 -0
  59. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/data/spdx-exceptions.json +0 -0
  60. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/data/spdx-licenses.json +0 -0
  61. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/file_filters.py +0 -0
  62. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/filecount.py +0 -0
  63. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/inspection/__init__.py +0 -0
  64. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/inspection/utils/license_utils.py +0 -0
  65. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/results.py +0 -0
  66. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scancodedeps.py +0 -0
  67. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanner.py +0 -0
  68. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanners/__init__.py +0 -0
  69. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanners/container_scanner.py +0 -0
  70. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanners/folder_hasher.py +0 -0
  71. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanners/scanner_config.py +0 -0
  72. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanners/scanner_hfh.py +0 -0
  73. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanoss_settings.py +0 -0
  74. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanossapi.py +0 -0
  75. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanossbase.py +0 -0
  76. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanossgrpc.py +0 -0
  77. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scanpostprocessor.py +0 -0
  78. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/scantype.py +0 -0
  79. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/spdxlite.py +0 -0
  80. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/threadeddependencies.py +0 -0
  81. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/threadedscanning.py +0 -0
  82. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/utils/__init__.py +0 -0
  83. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/utils/abstract_presenter.py +0 -0
  84. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/utils/crc64.py +0 -0
  85. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/utils/file.py +0 -0
  86. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/utils/simhash.py +0 -0
  87. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss/winnowing.py +0 -0
  88. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss.egg-info/SOURCES.txt +0 -0
  89. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss.egg-info/dependency_links.txt +0 -0
  90. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss.egg-info/entry_points.txt +0 -0
  91. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss.egg-info/requires.txt +0 -0
  92. {scanoss-1.25.0 → scanoss-1.25.2}/src/scanoss.egg-info/top_level.txt +0 -0
  93. {scanoss-1.25.0 → scanoss-1.25.2}/tests/test_csv_output.py +0 -0
  94. {scanoss-1.25.0 → scanoss-1.25.2}/tests/test_file_filters.py +0 -0
  95. {scanoss-1.25.0 → scanoss-1.25.2}/tests/test_scan_post_processor.py +0 -0
  96. {scanoss-1.25.0 → scanoss-1.25.2}/tests/test_spdxlite.py +0 -0
  97. {scanoss-1.25.0 → scanoss-1.25.2}/tests/test_winnowing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scanoss
3
- Version: 1.25.0
3
+ Version: 1.25.2
4
4
  Summary: Simple Python library to leverage the SCANOSS APIs
5
5
  Home-page: https://scanoss.com
6
6
  Author: SCANOSS
@@ -22,4 +22,4 @@ SPDX-License-Identifier: MIT
22
22
  THE SOFTWARE.
23
23
  """
24
24
 
25
- __version__ = '1.25.0'
25
+ __version__ = '1.25.2'
@@ -0,0 +1 @@
1
+ date: 20250618150502, utime: 1750259102
@@ -23,7 +23,8 @@ SPDX-License-Identifier: MIT
23
23
  """
24
24
 
25
25
  import json
26
- from typing import Dict, Any
26
+ from typing import Any, Dict
27
+
27
28
  from .policy_check import PolicyCheck, PolicyStatus
28
29
 
29
30
 
@@ -33,7 +34,7 @@ class Copyleft(PolicyCheck):
33
34
  Inspects components for copyleft licenses
34
35
  """
35
36
 
36
- def __init__(
37
+ def __init__( # noqa: PLR0913
37
38
  self,
38
39
  debug: bool = False,
39
40
  trace: bool = True,
@@ -158,6 +159,26 @@ class Copyleft(PolicyCheck):
158
159
  self.print_debug(f'Copyleft components: {filtered_components}')
159
160
  return filtered_components
160
161
 
162
+ def _get_components(self):
163
+ """
164
+ Extract and process components from results and their dependencies.
165
+
166
+ This method performs the following steps:
167
+ 1. Validates that `self.results` is loaded. Returns `None` if not.
168
+ 2. Extracts file, snippet, and dependency components into a dictionary.
169
+ 3. Converts components to a list and processes their licenses.
170
+
171
+ :return: A list of processed components with license data, or `None` if `self.results` is not set.
172
+ """
173
+ if self.results is None:
174
+ return None
175
+
176
+ components: dict = {}
177
+ # Extract component and license data from file and dependency results. Both helpers mutate `components`
178
+ self._get_components_data(self.results, components)
179
+ self._get_dependencies_data(self.results, components)
180
+ return self._convert_components_to_list(components)
181
+
161
182
  def run(self):
162
183
  """
163
184
  Run the copyleft license inspection process.
@@ -166,6 +166,30 @@ class PolicyCheck(ScanossBase):
166
166
  """
167
167
  pass
168
168
 
169
+ @abstractmethod
170
+ def _get_components(self):
171
+ """
172
+ Retrieve and process components from the preloaded results.
173
+
174
+ This method performs the following steps:
175
+ 1. Checks if the results have been previously loaded (self.results).
176
+ 2. Extracts and processes components from the loaded results.
177
+
178
+ :return: A list of processed components, or None if an error occurred during any step.
179
+
180
+ Possible reasons for returning None include:
181
+ - Results not loaded (self.results is None)
182
+ - Failure to extract components from the results
183
+
184
+ Note:
185
+ - This method assumes that the results have been previously loaded and stored in self.results.
186
+ - Implementations must extract components (e.g. via `_get_components_data`,
187
+ `_get_dependencies_data`, or other helpers).
188
+ - If `self.results` is `None`, simply return `None`.
189
+ """
190
+ pass
191
+
192
+
169
193
  def _append_component(
170
194
  self, components: Dict[str, Any], new_component: Dict[str, Any], id: str, status: str
171
195
  ) -> Dict[str, Any]:
@@ -188,6 +212,10 @@ class PolicyCheck(ScanossBase):
188
212
  else:
189
213
  purl = new_component['purl']
190
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
+
191
219
  component_key = f'{purl}@{new_component["version"]}'
192
220
  components[component_key] = {
193
221
  'purl': purl,
@@ -198,14 +226,21 @@ class PolicyCheck(ScanossBase):
198
226
  if not new_component.get('licenses'):
199
227
  self.print_debug(f'WARNING: Results missing licenses. Skipping: {new_component}')
200
228
  return components
229
+
230
+
231
+ licenses_order_by_source_priority = self._get_licenses_order_by_source_priority(new_component['licenses'])
201
232
  # Process licenses for this component
202
- for license_item in new_component['licenses']:
233
+ for license_item in licenses_order_by_source_priority:
203
234
  if license_item.get('name'):
204
235
  spdxid = license_item['name']
236
+ source = license_item.get('source')
237
+ if not source:
238
+ source = 'unknown'
205
239
  components[component_key]['licenses'][spdxid] = {
206
240
  'spdxid': spdxid,
207
241
  'copyleft': self.license_util.is_copyleft(spdxid),
208
242
  'url': self.license_util.get_spdx_url(spdxid),
243
+ 'source': source,
209
244
  }
210
245
  return components
211
246
 
@@ -223,6 +258,9 @@ class PolicyCheck(ScanossBase):
223
258
  if not component_id:
224
259
  self.print_debug(f'WARNING: Result missing id. Skipping: {c}')
225
260
  continue
261
+ ## Skip dependency
262
+ if component_id == ComponentID.DEPENDENCY.value:
263
+ continue
226
264
  status = c.get('status')
227
265
  if not status:
228
266
  self.print_debug(f'WARNING: Result missing status. Skipping: {c}')
@@ -234,10 +272,12 @@ class PolicyCheck(ScanossBase):
234
272
  if len(c.get('purl')) <= 0:
235
273
  self.print_debug(f'WARNING: Result missing purls. Skipping: {c}')
236
274
  continue
237
- if not c.get('version'):
238
- self.print_msg(f'WARNING: Result missing version. Skipping: {c}')
239
- continue
240
- 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}'
241
281
  if component_key not in components:
242
282
  components = self._append_component(components, c, component_id, status)
243
283
  # End component loop
@@ -269,10 +309,12 @@ class PolicyCheck(ScanossBase):
269
309
  if not dependency.get('purl'):
270
310
  self.print_debug(f'WARNING: Dependency result missing purl. Skipping: {dependency}')
271
311
  continue
272
- if not dependency.get('version'):
273
- self.print_msg(f'WARNING: Dependency result missing version. Skipping: {dependency}')
274
- continue
275
- 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}'
276
318
  if component_key not in components:
277
319
  components = self._append_component(components, dependency, component_id, status)
278
320
  # End dependency loop
@@ -280,33 +322,6 @@ class PolicyCheck(ScanossBase):
280
322
  # End of result loop
281
323
  return components
282
324
 
283
- def _get_components_from_results(self, results: Dict[str, Any]) -> list or None:
284
- """
285
- Process the results dictionary to extract and format component information.
286
-
287
- This function iterates through the results dictionary, identifying components from
288
- different sources (files, snippets, and dependencies). It consolidates this information
289
- into a list of unique components, each with its associated licenses and other details.
290
-
291
- :param results: A dictionary containing the raw results of a component scan
292
- :return: A list of dictionaries, each representing a unique component with its details
293
- """
294
- if results is None:
295
- self.print_stderr('ERROR: Results cannot be empty')
296
- return None
297
-
298
- components = {}
299
- # Extract file and snippet components
300
- components = self._get_components_data(results, components)
301
- # Extract dependency components
302
- components = self._get_dependencies_data(results, components)
303
- # Convert to list and process licenses
304
- results_list = list(components.values())
305
- for component in results_list:
306
- component['licenses'] = list(component['licenses'].values())
307
-
308
- return results_list
309
-
310
325
  def generate_table(self, headers, rows, centered_columns=None):
311
326
  """
312
327
  Generate a Markdown table.
@@ -411,28 +426,60 @@ class PolicyCheck(ScanossBase):
411
426
  self.print_stderr(f'ERROR: Problem parsing input JSON: {e}')
412
427
  return None
413
428
 
414
- def _get_components(self):
415
- """
416
- Retrieve and process components from the preloaded results.
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
417
442
 
418
- This method performs the following steps:
419
- 1. Checks if the results have been previously loaded (self.results).
420
- 2. Extracts and processes components from the loaded results.
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)
421
450
 
422
- :return: A list of processed components, or None if an error occurred during any step.
423
- Possible reasons for returning None include:
424
- - Results not loaded (self.results is None)
425
- - Failure to extract components from the results
451
+ If any high-priority source is found, return only licenses from that source.
452
+ If none found, return all licenses.
426
453
 
427
- Note:
428
- - This method assumes that the results have been previously loaded and stored in self.results.
429
- - If results is None, the method returns None without performing any further operations.
430
- - The actual processing of components is delegated to the _get_components_from_results method.
454
+ Returns: list with ordered licenses by source.
431
455
  """
432
- if self.results is None:
433
- return None
434
- components = self._get_components_from_results(self.results)
435
- return components
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
+
436
483
 
437
484
  #
438
485
  # End of PolicyCheck Class
@@ -23,7 +23,8 @@ SPDX-License-Identifier: MIT
23
23
  """
24
24
 
25
25
  import json
26
- from typing import Dict, Any
26
+ from typing import Any, Dict
27
+
27
28
  from .policy_check import PolicyCheck, PolicyStatus
28
29
 
29
30
 
@@ -33,7 +34,7 @@ class UndeclaredComponent(PolicyCheck):
33
34
  Inspects for undeclared components
34
35
  """
35
36
 
36
- def __init__(
37
+ def __init__( # noqa: PLR0913
37
38
  self,
38
39
  debug: bool = False,
39
40
  trace: bool = True,
@@ -73,7 +74,7 @@ class UndeclaredComponent(PolicyCheck):
73
74
  :return: List of undeclared components
74
75
  """
75
76
  if components is None:
76
- self.print_debug(f'WARNING: No components provided!')
77
+ self.print_debug('WARNING: No components provided!')
77
78
  return None
78
79
  undeclared_components = []
79
80
  for component in components:
@@ -87,25 +88,35 @@ class UndeclaredComponent(PolicyCheck):
87
88
  """
88
89
  Get a summary of the undeclared components.
89
90
 
91
+ :param components: List of all components
92
+ :return: Component summary markdown
93
+ """
94
+
95
+ """
96
+ Get a summary of the undeclared components.
97
+
90
98
  :param components: List of all components
91
99
  :return: Component summary markdown
92
100
  """
93
101
  if len(components) > 0:
102
+ json_content = json.dumps(self._generate_scanoss_file(components), indent=2)
103
+
94
104
  if self.sbom_format == 'settings':
95
- json_str = (
96
- json.dumps(self._generate_scanoss_file(components), indent=2)
97
- .replace('\n', '\\n')
98
- .replace('"', '\\"')
105
+ return (
106
+ f'{len(components)} undeclared component(s) were found.\n'
107
+ f'Add the following snippet into your `scanoss.json` file\n'
108
+ f'{{code:json}}\n'
109
+ f'{json_content}\n'
110
+ f'{{code}}\n'
99
111
  )
100
- return f'{len(components)} undeclared component(s) were found.\nAdd the following snippet into your `scanoss.json` file\n{{code:json}}\n{json.dumps(self._generate_scanoss_file(components), indent=2)}\n{{code}}\n'
101
112
  else:
102
- json_str = (
103
- json.dumps(self._generate_scanoss_file(components), indent=2)
104
- .replace('\n', '\\n')
105
- .replace('"', '\\"')
113
+ return (
114
+ f'{len(components)} undeclared component(s) were found.\n'
115
+ f'Add the following snippet into your `sbom.json` file\n'
116
+ f'{{code:json}}\n'
117
+ f'{json_content}\n'
118
+ f'{{code}}\n'
106
119
  )
107
- return f'{len(components)} undeclared component(s) were found.\nAdd the following snippet into your `sbom.json` file\n{{code:json}}\n{json.dumps(self._generate_scanoss_file(components), indent=2)}\n{{code}}\n'
108
-
109
120
  return f'{len(components)} undeclared component(s) were found.\\n'
110
121
 
111
122
  def _get_summary(self, components: list) -> str:
@@ -190,7 +201,7 @@ class UndeclaredComponent(PolicyCheck):
190
201
  """
191
202
  unique_components = {}
192
203
  if components is None:
193
- self.print_stderr(f'WARNING: No components provided!')
204
+ self.print_stderr('WARNING: No components provided!')
194
205
  return []
195
206
 
196
207
  for component in components:
@@ -225,6 +236,26 @@ class UndeclaredComponent(PolicyCheck):
225
236
 
226
237
  return sbom
227
238
 
239
+ def _get_components(self):
240
+ """
241
+ Extract and process components from file results only.
242
+
243
+ This method performs the following steps:
244
+ 1. Validates if `self.results` is loaded. Returns `None` if not loaded.
245
+ 2. Extracts file and snippet components into a dictionary.
246
+ 3. Converts the components dictionary into a list of components.
247
+ 4. Processes the licenses for each component by converting them into a list.
248
+
249
+ :return: A list of processed components with their licenses, or `None` if `self.results` is not set.
250
+ """
251
+ if self.results is None:
252
+ return None
253
+ components: dict = {}
254
+ # Extract file and snippet components
255
+ components = self._get_components_data(self.results, components)
256
+ # Convert to list and process licenses
257
+ return self._convert_components_to_list(components)
258
+
228
259
  def run(self):
229
260
  """
230
261
  Run the undeclared component inspection process.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scanoss
3
- Version: 1.25.0
3
+ Version: 1.25.2
4
4
  Summary: Simple Python library to leverage the SCANOSS APIs
5
5
  Home-page: https://scanoss.com
6
6
  Author: SCANOSS
@@ -114,7 +114,7 @@ class MyTestCase(unittest.TestCase):
114
114
  copyleft = Copyleft(filepath=input_file_name, format_type='json', explicit='MIT')
115
115
  status, results = copyleft.run()
116
116
  details = json.loads(results['details'])
117
- self.assertEqual(len(details['components']), 3)
117
+ self.assertEqual(len(details['components']), 2)
118
118
  self.assertEqual(status, 0)
119
119
 
120
120
  """
@@ -144,11 +144,10 @@ class MyTestCase(unittest.TestCase):
144
144
  expected_detail_output = (
145
145
  '### Copyleft licenses \n | Component | Version | License | URL | Copyleft |\n'
146
146
  ' | - | :-: | - | - | :-: |\n'
147
- '| pkg:github/scanoss/engine | 4.0.4 | MIT | https://spdx.org/licenses/MIT.html | YES | \n'
148
147
  ' | pkg:npm/%40electron/rebuild | 3.7.0 | MIT | https://spdx.org/licenses/MIT.html | YES |\n'
149
148
  '| pkg:npm/%40emotion/react | 11.13.3 | MIT | https://spdx.org/licenses/MIT.html | YES | \n'
150
149
  )
151
- expected_summary_output = '3 component(s) with copyleft licenses were found.\n'
150
+ expected_summary_output = '2 component(s) with copyleft licenses were found.\n'
152
151
  self.assertEqual(
153
152
  re.sub(r'\s|\\(?!`)|\\(?=`)', '', results['details']),
154
153
  re.sub(r'\s|\\(?!`)|\\(?=`)', '', expected_detail_output),
@@ -179,7 +178,7 @@ class MyTestCase(unittest.TestCase):
179
178
  status, results = undeclared.run()
180
179
  details = json.loads(results['details'])
181
180
  summary = results['summary']
182
- expected_summary_output = """5 undeclared component(s) were found.
181
+ expected_summary_output = """3 undeclared component(s) were found.
183
182
  Add the following snippet into your `sbom.json` file
184
183
  ```json
185
184
  {
@@ -189,17 +188,11 @@ class MyTestCase(unittest.TestCase):
189
188
  },
190
189
  {
191
190
  "purl": "pkg:github/scanoss/wfp"
192
- },
193
- {
194
- "purl": "pkg:npm/%40electron/rebuild"
195
- },
196
- {
197
- "purl": "pkg:npm/%40emotion/react"
198
191
  }
199
192
  ]
200
193
  }```
201
194
  """
202
- self.assertEqual(len(details['components']), 5)
195
+ self.assertEqual(len(details['components']), 3)
203
196
  self.assertEqual(
204
197
  re.sub(r'\s|\\(?!`)|\\(?=`)', '', summary), re.sub(r'\s|\\(?!`)|\\(?=`)', '', expected_summary_output)
205
198
  )
@@ -220,13 +213,11 @@ class MyTestCase(unittest.TestCase):
220
213
  expected_details_output = """ ### Undeclared components
221
214
  | Component | Version | License |
222
215
  | - | - | - |
223
- | pkg:github/scanoss/scanner.c | 1.3.3 | BSD-2-Clause - GPL-2.0-only |
216
+ | pkg:github/scanoss/scanner.c | 1.3.3 | GPL-2.0-only |
224
217
  | pkg:github/scanoss/scanner.c | 1.1.4 | GPL-2.0-only |
225
- | pkg:github/scanoss/wfp | 6afc1f6 | Zlib - GPL-2.0-only |
226
- | pkg:npm/%40electron/rebuild | 3.7.0 | MIT |
227
- | pkg:npm/%40emotion/react | 11.13.3 | MIT | """
218
+ | pkg:github/scanoss/wfp | 6afc1f6 | GPL-2.0-only | """
228
219
 
229
- expected_summary_output = """5 undeclared component(s) were found.
220
+ expected_summary_output = """3 undeclared component(s) were found.
230
221
  Add the following snippet into your `sbom.json` file
231
222
  ```json
232
223
  {
@@ -236,13 +227,7 @@ class MyTestCase(unittest.TestCase):
236
227
  },
237
228
  {
238
229
  "purl": "pkg:github/scanoss/wfp"
239
- },
240
- {
241
- "purl": "pkg:npm/%40electron/rebuild"
242
- },
243
- {
244
- "purl": "pkg:npm/%40emotion/react"
245
- }
230
+ }
246
231
  ]
247
232
  }```
248
233
  """
@@ -271,13 +256,11 @@ class MyTestCase(unittest.TestCase):
271
256
  expected_details_output = """ ### Undeclared components
272
257
  | Component | Version | License |
273
258
  | - | - | - |
274
- | pkg:github/scanoss/scanner.c | 1.3.3 | BSD-2-Clause - GPL-2.0-only |
259
+ | pkg:github/scanoss/scanner.c | 1.3.3 | GPL-2.0-only |
275
260
  | pkg:github/scanoss/scanner.c | 1.1.4 | GPL-2.0-only |
276
- | pkg:github/scanoss/wfp | 6afc1f6 | Zlib - GPL-2.0-only |
277
- | pkg:npm/%40electron/rebuild | 3.7.0 | MIT |
278
- | pkg:npm/%40emotion/react | 11.13.3 | MIT | """
261
+ | pkg:github/scanoss/wfp | 6afc1f6 | GPL-2.0-only | """
279
262
 
280
- expected_summary_output = """5 undeclared component(s) were found.
263
+ expected_summary_output = """3 undeclared component(s) were found.
281
264
  Add the following snippet into your `scanoss.json` file
282
265
 
283
266
  ```json
@@ -289,12 +272,6 @@ class MyTestCase(unittest.TestCase):
289
272
  },
290
273
  {
291
274
  "purl": "pkg:github/scanoss/wfp"
292
- },
293
- {
294
- "purl": "pkg:npm/%40electron/rebuild"
295
- },
296
- {
297
- "purl": "pkg:npm/%40emotion/react"
298
275
  }
299
276
  ]
300
277
  }
@@ -322,7 +299,7 @@ class MyTestCase(unittest.TestCase):
322
299
  status, results = undeclared.run()
323
300
  details = json.loads(results['details'])
324
301
  summary = results['summary']
325
- expected_summary_output = """5 undeclared component(s) were found.
302
+ expected_summary_output = """3 undeclared component(s) were found.
326
303
  Add the following snippet into your `scanoss.json` file
327
304
 
328
305
  ```json
@@ -334,19 +311,13 @@ class MyTestCase(unittest.TestCase):
334
311
  },
335
312
  {
336
313
  "purl": "pkg:github/scanoss/wfp"
337
- },
338
- {
339
- "purl": "pkg:npm/%40electron/rebuild"
340
- },
341
- {
342
- "purl": "pkg:npm/%40emotion/react"
343
314
  }
344
315
  ]
345
316
  }
346
317
  }
347
318
  ```"""
348
319
  self.assertEqual(status, 0)
349
- self.assertEqual(len(details['components']), 5)
320
+ self.assertEqual(len(details['components']), 3)
350
321
  self.assertEqual(
351
322
  re.sub(r'\s|\\(?!`)|\\(?=`)', '', summary), re.sub(r'\s|\\(?!`)|\\(?=`)', '', expected_summary_output)
352
323
  )
@@ -360,13 +331,11 @@ class MyTestCase(unittest.TestCase):
360
331
  details = results['details']
361
332
  summary = results['summary']
362
333
  expected_details_output = """|*Component*|*Version*|*License*|
363
- |pkg:github/scanoss/scanner.c|1.3.3|BSD-2-Clause - GPL-2.0-only|
334
+ |pkg:github/scanoss/scanner.c|1.3.3|GPL-2.0-only|
364
335
  |pkg:github/scanoss/scanner.c|1.1.4|GPL-2.0-only|
365
- |pkg:github/scanoss/wfp|6afc1f6|Zlib - GPL-2.0-only|
366
- |pkg:npm/%40electron/rebuild|3.7.0|MIT|
367
- |pkg:npm/%40emotion/react|11.13.3|MIT|
336
+ |pkg:github/scanoss/wfp|6afc1f6|GPL-2.0-only|
368
337
  """
369
- expected_summary_output = """5 undeclared component(s) were found.
338
+ expected_summary_output = """3 undeclared component(s) were found.
370
339
  Add the following snippet into your `scanoss.json` file
371
340
  {code:json}
372
341
  {
@@ -377,12 +346,6 @@ Add the following snippet into your `scanoss.json` file
377
346
  },
378
347
  {
379
348
  "purl": "pkg:github/scanoss/wfp"
380
- },
381
- {
382
- "purl": "pkg:npm/%40electron/rebuild"
383
- },
384
- {
385
- "purl": "pkg:npm/%40emotion/react"
386
349
  }
387
350
  ]
388
351
  }
@@ -1 +0,0 @@
1
- date: 20250610161304, utime: 1749571984
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes