scanoss 1.31.1__tar.gz → 1.31.3__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 (104) hide show
  1. {scanoss-1.31.1/src/scanoss.egg-info → scanoss-1.31.3}/PKG-INFO +1 -1
  2. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/__init__.py +1 -1
  3. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/csvoutput.py +13 -7
  4. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/cyclonedx.py +8 -3
  5. scanoss-1.31.3/src/scanoss/data/build_date.txt +1 -0
  6. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/export/dependency_track.py +6 -1
  7. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/dependency_track/project_violation.py +26 -4
  8. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/raw/license_summary.py +0 -1
  9. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/services/dependency_track_service.py +1 -0
  10. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/spdxlite.py +7 -2
  11. {scanoss-1.31.1 → scanoss-1.31.3/src/scanoss.egg-info}/PKG-INFO +1 -1
  12. scanoss-1.31.1/src/scanoss/data/build_date.txt +0 -1
  13. {scanoss-1.31.1 → scanoss-1.31.3}/LICENSE +0 -0
  14. {scanoss-1.31.1 → scanoss-1.31.3}/PACKAGE.md +0 -0
  15. {scanoss-1.31.1 → scanoss-1.31.3}/README.md +0 -0
  16. {scanoss-1.31.1 → scanoss-1.31.3}/pyproject.toml +0 -0
  17. {scanoss-1.31.1 → scanoss-1.31.3}/setup.cfg +0 -0
  18. {scanoss-1.31.1 → scanoss-1.31.3}/src/protoc_gen_swagger/__init__.py +0 -0
  19. {scanoss-1.31.1 → scanoss-1.31.3}/src/protoc_gen_swagger/options/__init__.py +0 -0
  20. {scanoss-1.31.1 → scanoss-1.31.3}/src/protoc_gen_swagger/options/annotations_pb2.py +0 -0
  21. {scanoss-1.31.1 → scanoss-1.31.3}/src/protoc_gen_swagger/options/annotations_pb2_grpc.py +0 -0
  22. {scanoss-1.31.1 → scanoss-1.31.3}/src/protoc_gen_swagger/options/openapiv2_pb2.py +0 -0
  23. {scanoss-1.31.1 → scanoss-1.31.3}/src/protoc_gen_swagger/options/openapiv2_pb2_grpc.py +0 -0
  24. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/__init__.py +0 -0
  25. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/common/__init__.py +0 -0
  26. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/common/v2/__init__.py +0 -0
  27. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/common/v2/scanoss_common_pb2.py +0 -0
  28. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/common/v2/scanoss_common_pb2_grpc.py +0 -0
  29. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/components/__init__.py +0 -0
  30. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/components/v2/__init__.py +0 -0
  31. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/components/v2/scanoss_components_pb2.py +0 -0
  32. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/components/v2/scanoss_components_pb2_grpc.py +0 -0
  33. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +0 -0
  34. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +0 -0
  35. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/dependencies/__init__.py +0 -0
  36. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/dependencies/v2/__init__.py +0 -0
  37. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +0 -0
  38. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +0 -0
  39. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/geoprovenance/__init__.py +0 -0
  40. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/geoprovenance/v2/__init__.py +0 -0
  41. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +0 -0
  42. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +0 -0
  43. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/scanning/__init__.py +0 -0
  44. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/scanning/v2/__init__.py +0 -0
  45. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2.py +0 -0
  46. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +0 -0
  47. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/semgrep/__init__.py +0 -0
  48. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/semgrep/v2/__init__.py +0 -0
  49. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +0 -0
  50. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +0 -0
  51. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/vulnerabilities/__init__.py +0 -0
  52. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/vulnerabilities/v2/__init__.py +0 -0
  53. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +0 -0
  54. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +0 -0
  55. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/cli.py +0 -0
  56. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/components.py +0 -0
  57. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/constants.py +0 -0
  58. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/cryptography.py +0 -0
  59. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/data/scanoss-settings-schema.json +0 -0
  60. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/data/spdx-exceptions.json +0 -0
  61. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/data/spdx-licenses.json +0 -0
  62. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/export/__init__.py +0 -0
  63. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/file_filters.py +0 -0
  64. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/filecount.py +0 -0
  65. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/__init__.py +0 -0
  66. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/policy_check.py +0 -0
  67. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/raw/component_summary.py +0 -0
  68. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/raw/copyleft.py +0 -0
  69. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/raw/raw_base.py +0 -0
  70. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/raw/undeclared_component.py +0 -0
  71. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/inspection/utils/license_utils.py +0 -0
  72. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/results.py +0 -0
  73. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scancodedeps.py +0 -0
  74. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanner.py +0 -0
  75. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanners/__init__.py +0 -0
  76. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanners/container_scanner.py +0 -0
  77. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanners/folder_hasher.py +0 -0
  78. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanners/scanner_config.py +0 -0
  79. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanners/scanner_hfh.py +0 -0
  80. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanoss_settings.py +0 -0
  81. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanossapi.py +0 -0
  82. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanossbase.py +0 -0
  83. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanossgrpc.py +0 -0
  84. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scanpostprocessor.py +0 -0
  85. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/scantype.py +0 -0
  86. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/threadeddependencies.py +0 -0
  87. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/threadedscanning.py +0 -0
  88. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/utils/__init__.py +0 -0
  89. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/utils/abstract_presenter.py +0 -0
  90. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/utils/crc64.py +0 -0
  91. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/utils/file.py +0 -0
  92. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/utils/simhash.py +0 -0
  93. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss/winnowing.py +0 -0
  94. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss.egg-info/SOURCES.txt +0 -0
  95. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss.egg-info/dependency_links.txt +0 -0
  96. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss.egg-info/entry_points.txt +0 -0
  97. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss.egg-info/requires.txt +0 -0
  98. {scanoss-1.31.1 → scanoss-1.31.3}/src/scanoss.egg-info/top_level.txt +0 -0
  99. {scanoss-1.31.1 → scanoss-1.31.3}/tests/test_csv_output.py +0 -0
  100. {scanoss-1.31.1 → scanoss-1.31.3}/tests/test_file_filters.py +0 -0
  101. {scanoss-1.31.1 → scanoss-1.31.3}/tests/test_policy_inspect.py +0 -0
  102. {scanoss-1.31.1 → scanoss-1.31.3}/tests/test_scan_post_processor.py +0 -0
  103. {scanoss-1.31.1 → scanoss-1.31.3}/tests/test_spdxlite.py +0 -0
  104. {scanoss-1.31.1 → scanoss-1.31.3}/tests/test_winnowing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scanoss
3
- Version: 1.31.1
3
+ Version: 1.31.3
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.31.1'
25
+ __version__ = '1.31.3'
@@ -21,11 +21,10 @@ SPDX-License-Identifier: MIT
21
21
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
22
  THE SOFTWARE.
23
23
  """
24
-
24
+ import csv
25
25
  import json
26
26
  import os.path
27
27
  import sys
28
- import csv
29
28
 
30
29
  from .scanossbase import ScanossBase
31
30
 
@@ -44,16 +43,20 @@ class CsvOutput(ScanossBase):
44
43
  self.output_file = output_file
45
44
  self.debug = debug
46
45
 
47
- def parse(self, data: json):
46
+ # TODO Refactor (fails linter)
47
+ def parse(self, data: json): #noqa PLR0912, PLR0915
48
48
  """
49
49
  Parse the given input (raw/plain) JSON string and return CSV summary
50
50
  :param data: json - JSON object
51
51
  :return: CSV dictionary
52
52
  """
53
- if not data:
53
+ if data is None:
54
54
  self.print_stderr('ERROR: No JSON data provided to parse.')
55
55
  return None
56
- self.print_debug(f'Processing raw results into CSV format...')
56
+ if len(data) == 0:
57
+ self.print_msg('Warning: Empty scan results provided. Returning empty CSV list.')
58
+ return []
59
+ self.print_debug('Processing raw results into CSV format...')
57
60
  csv_dict = []
58
61
  row_id = 1
59
62
  for f in data:
@@ -92,7 +95,8 @@ class CsvOutput(ScanossBase):
92
95
  detected['licenses'] = ''
93
96
  else:
94
97
  detected['licenses'] = ';'.join(dc)
95
- # inventory_id,path,usage,detected_component,detected_license,detected_version,detected_latest,purl
98
+ # inventory_id,path,usage,detected_component,detected_license,
99
+ # detected_version,detected_latest,purl
96
100
  csv_dict.append(
97
101
  {
98
102
  'inventory_id': row_id,
@@ -183,9 +187,11 @@ class CsvOutput(ScanossBase):
183
187
  :return: True if successful, False otherwise
184
188
  """
185
189
  csv_data = self.parse(data)
186
- if not csv_data:
190
+ if csv_data is None:
187
191
  self.print_stderr('ERROR: No CSV data returned for the JSON string provided.')
188
192
  return False
193
+ if len(csv_data) == 0:
194
+ self.print_msg('Warning: Empty scan results - generating CSV with headers only.')
189
195
  # Header row/column details
190
196
  fields = [
191
197
  'inventory_id',
@@ -57,9 +57,12 @@ class CycloneDx(ScanossBase):
57
57
  :param data: dict - JSON object
58
58
  :return: CycloneDX dictionary, and vulnerability dictionary
59
59
  """
60
- if not data:
60
+ if data is None:
61
61
  self.print_stderr('ERROR: No JSON data provided to parse.')
62
62
  return None, None
63
+ if len(data) == 0:
64
+ self.print_msg('Warning: Empty scan results provided. Returning empty component dictionary.')
65
+ return {}, {}
63
66
  self.print_debug('Processing raw results into CycloneDX format...')
64
67
  cdx = {}
65
68
  vdx = {}
@@ -186,9 +189,11 @@ class CycloneDx(ScanossBase):
186
189
  json: The CycloneDX output
187
190
  """
188
191
  cdx, vdx = self.parse(data)
189
- if not cdx:
192
+ if cdx is None:
190
193
  self.print_stderr('ERROR: No CycloneDX data returned for the JSON string provided.')
191
- return False, None
194
+ return False, {}
195
+ if len(cdx) == 0:
196
+ self.print_msg('Warning: Empty scan results - generating minimal CycloneDX SBOM with no components.')
192
197
  self._spdx.load_license_data() # Load SPDX license name data for later reference
193
198
  #
194
199
  # Using CDX version 1.4: https://cyclonedx.org/docs/1.4/json/
@@ -0,0 +1 @@
1
+ date: 20250819171726, utime: 1755623846
@@ -118,7 +118,12 @@ class DependencyTrackExporter(ScanossBase):
118
118
  Base64 encoded string
119
119
  """
120
120
  if not sbom_content:
121
- self.print_stderr('Warning: Empty SBOM content')
121
+ self.print_stderr('Warning: Empty SBOM content provided')
122
+ return ''
123
+ # Check if SBOM has no components (empty scan results)
124
+ components = sbom_content.get('components', [])
125
+ if len(components) == 0:
126
+ self.print_msg('Notice: SBOM contains no components (empty scan results)')
122
127
  json_str = json.dumps(sbom_content, separators=(',', ':'))
123
128
  encoded = base64.b64encode(json_str.encode('utf-8')).decode('utf-8')
124
129
  return encoded
@@ -230,16 +230,34 @@ class DependencyTrackProjectViolationPolicyCheck(PolicyCheck[PolicyViolationDict
230
230
  if not dt_project:
231
231
  self.print_stderr('Warning: No project details supplied. Returning False.')
232
232
  return False
233
- last_import = dt_project.get('lastBomImport', 0)
234
- last_vulnerability_analysis = dt_project.get('lastVulnerabilityAnalysis', 0)
233
+
234
+ # Safely extract and normalise timestamp values to numeric types
235
+ def _safe_timestamp(field, value=None, default=0) -> float:
236
+ """Convert timestamp value to float, handling string/numeric types safely."""
237
+ if value is None:
238
+ return float(default)
239
+ try:
240
+ return float(value)
241
+ except (ValueError, TypeError):
242
+ self.print_stderr(f'Warning: Invalid timestamp for {field}, value: {value}, using default: {default}')
243
+ return float(default)
244
+
245
+ last_import = _safe_timestamp('lastBomImport', dt_project.get('lastBomImport'), 0)
246
+ last_vulnerability_analysis = _safe_timestamp('lastVulnerabilityAnalysis',
247
+ dt_project.get('lastVulnerabilityAnalysis'), 0
248
+ )
235
249
  metrics = dt_project.get('metrics', {})
236
- last_occurrence = metrics.get('lastOccurrence', 0) if isinstance(metrics, dict) else 0
250
+ last_occurrence = _safe_timestamp('lastOccurrence',
251
+ metrics.get('lastOccurrence', 0)
252
+ if isinstance(metrics, dict) else 0, 0
253
+ )
237
254
  if self.debug:
238
255
  self.print_msg(f'last_import: {last_import}')
239
256
  self.print_msg(f'last_vulnerability_analysis: {last_vulnerability_analysis}')
240
257
  self.print_msg(f'last_occurrence: {last_occurrence}')
241
258
  self.print_msg(f'last_vulnerability_analysis is updated: {last_vulnerability_analysis >= last_import}')
242
259
  self.print_msg(f'last_occurrence is updated: {last_occurrence >= last_import}')
260
+ # If all timestamps are zero, this indicates no processing has occurred
243
261
  if last_vulnerability_analysis == 0 or last_occurrence == 0 or last_import == 0:
244
262
  self.print_stderr(f'Warning: Some project data appears to be unset. Returning False: {dt_project}')
245
263
  return False
@@ -434,12 +452,16 @@ class DependencyTrackProjectViolationPolicyCheck(PolicyCheck[PolicyViolationDict
434
452
  return PolicyStatus.ERROR.value
435
453
  # Get project violations from Dependency Track
436
454
  dt_project_violations = self.dep_track_service.get_project_violations(self.project_id)
455
+ # Handle case where service returns None (API error) vs empty list (no violations)
456
+ if dt_project_violations is None:
457
+ self.print_stderr('Error: Failed to retrieve project violations from Dependency Track')
458
+ return PolicyStatus.ERROR.value
437
459
  # Sort violations by priority and format output
438
460
  formatter = self._get_formatter()
439
461
  if formatter is None:
440
462
  self.print_stderr('Error: Invalid format specified.')
441
463
  return PolicyStatus.ERROR.value
442
- # Format and output data
464
+ # Format and output data - handle empty results gracefully
443
465
  data = formatter(self._sort_project_violations(dt_project_violations))
444
466
  self.print_to_file_or_stdout(data['details'], self.output)
445
467
  self.print_to_file_or_stderr(data['summary'], self.status)
@@ -132,7 +132,6 @@ class LicenseSummary(RawBase):
132
132
  return self._convert_components_to_list(components)
133
133
 
134
134
  def run(self):
135
- print("Running LicenseSummary")
136
135
  components = self._get_components()
137
136
  license_summary = self._get_licenses_summary_from_components(components)
138
137
  self.print_to_file_or_stdout(json.dumps(license_summary, indent=2), self.output)
@@ -97,6 +97,7 @@ class DependencyTrackService(ScanossBase):
97
97
  if not project_id:
98
98
  self.print_stderr('Error: Missing project id. Cannot search for project violations.')
99
99
  return None
100
+ # Return the result as-is - None indicates API failure, empty list means no violations
100
101
  return self.get_dep_track_data(f'{self.url}/api/v1/violation/project/{project_id}')
101
102
 
102
103
  def get_project_by_id(self, project_id:str):
@@ -71,9 +71,12 @@ class SpdxLite:
71
71
  :param data: json - JSON object
72
72
  :return: summary dictionary
73
73
  """
74
- if not data:
74
+ if data is None:
75
75
  self.print_stderr('ERROR: No JSON data provided to parse.')
76
76
  return None
77
+ if len(data) == 0:
78
+ self.print_debug('Warning: Empty scan results provided. Returning empty summary.')
79
+ return {}
77
80
 
78
81
  self.print_debug('Processing raw results into summary format...')
79
82
  return self._process_files(data)
@@ -277,9 +280,11 @@ class SpdxLite:
277
280
  :return: True if successful, False otherwise
278
281
  """
279
282
  raw_data = self.parse(data)
280
- if not raw_data:
283
+ if raw_data is None:
281
284
  self.print_stderr('ERROR: No SPDX data returned for the JSON string provided.')
282
285
  return False
286
+ if len(raw_data) == 0:
287
+ self.print_debug('Warning: Empty scan results - generating minimal SPDX Lite document with no packages.')
283
288
 
284
289
  self.load_license_data()
285
290
  spdx_document = self._create_base_document(raw_data)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scanoss
3
- Version: 1.31.1
3
+ Version: 1.31.3
4
4
  Summary: Simple Python library to leverage the SCANOSS APIs
5
5
  Home-page: https://scanoss.com
6
6
  Author: SCANOSS
@@ -1 +0,0 @@
1
- date: 20250808142900, utime: 1754663340
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes