scanoss 1.20.6__py3-none-any.whl → 1.23.0__py3-none-any.whl

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 (50) hide show
  1. protoc_gen_swagger/options/annotations_pb2.py +9 -12
  2. protoc_gen_swagger/options/annotations_pb2_grpc.py +1 -1
  3. protoc_gen_swagger/options/openapiv2_pb2.py +96 -98
  4. protoc_gen_swagger/options/openapiv2_pb2_grpc.py +1 -1
  5. scanoss/__init__.py +1 -1
  6. scanoss/api/common/v2/scanoss_common_pb2.py +20 -18
  7. scanoss/api/common/v2/scanoss_common_pb2_grpc.py +1 -1
  8. scanoss/api/components/v2/scanoss_components_pb2.py +38 -48
  9. scanoss/api/components/v2/scanoss_components_pb2_grpc.py +96 -142
  10. scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +42 -22
  11. scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +185 -75
  12. scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +32 -30
  13. scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +83 -75
  14. scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +49 -0
  15. scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +142 -0
  16. scanoss/api/scanning/v2/scanoss_scanning_pb2.py +20 -10
  17. scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +70 -40
  18. scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +18 -22
  19. scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +49 -71
  20. scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +27 -37
  21. scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +72 -109
  22. scanoss/cli.py +393 -84
  23. scanoss/components.py +21 -11
  24. scanoss/constants.py +12 -0
  25. scanoss/data/build_date.txt +1 -1
  26. scanoss/file_filters.py +272 -57
  27. scanoss/results.py +92 -109
  28. scanoss/scanners/__init__.py +23 -0
  29. scanoss/scanners/container_scanner.py +474 -0
  30. scanoss/scanners/folder_hasher.py +302 -0
  31. scanoss/scanners/scanner_config.py +73 -0
  32. scanoss/scanners/scanner_hfh.py +173 -0
  33. scanoss/scanoss_settings.py +9 -5
  34. scanoss/scanossbase.py +9 -3
  35. scanoss/scanossgrpc.py +143 -18
  36. scanoss/threadedscanning.py +6 -6
  37. scanoss/utils/abstract_presenter.py +103 -0
  38. scanoss/utils/crc64.py +96 -0
  39. scanoss/utils/simhash.py +198 -0
  40. {scanoss-1.20.6.dist-info → scanoss-1.23.0.dist-info}/METADATA +2 -1
  41. scanoss-1.23.0.dist-info/RECORD +83 -0
  42. {scanoss-1.20.6.dist-info → scanoss-1.23.0.dist-info}/WHEEL +1 -1
  43. scanoss/api/provenance/v2/scanoss_provenance_pb2.py +0 -42
  44. scanoss/api/provenance/v2/scanoss_provenance_pb2_grpc.py +0 -108
  45. scanoss-1.20.6.dist-info/RECORD +0 -74
  46. /scanoss/api/{provenance → geoprovenance}/__init__.py +0 -0
  47. /scanoss/api/{provenance → geoprovenance}/v2/__init__.py +0 -0
  48. {scanoss-1.20.6.dist-info → scanoss-1.23.0.dist-info}/entry_points.txt +0 -0
  49. {scanoss-1.20.6.dist-info → scanoss-1.23.0.dist-info}/licenses/LICENSE +0 -0
  50. {scanoss-1.20.6.dist-info → scanoss-1.23.0.dist-info}/top_level.txt +0 -0
scanoss/results.py CHANGED
@@ -25,6 +25,8 @@ SPDX-License-Identifier: MIT
25
25
  import json
26
26
  from typing import Any, Dict, List
27
27
 
28
+ from scanoss.utils.abstract_presenter import AbstractPresenter
29
+
28
30
  from .scanossbase import ScanossBase
29
31
 
30
32
  MATCH_TYPES = ['file', 'snippet']
@@ -47,16 +49,89 @@ PENDING_IDENTIFICATION_FILTERS = {
47
49
  'status': ['pending'],
48
50
  }
49
51
 
50
- AVAILABLE_OUTPUT_FORMATS = ['json', 'plain']
51
52
 
53
+ class ResultsPresenter(AbstractPresenter):
54
+ """
55
+ SCANOSS Results presenter class
56
+ Handles the presentation of the scan results
57
+ """
58
+
59
+ def __init__(self, results_instance, **kwargs):
60
+ super().__init__(**kwargs)
61
+ self.results = results_instance
62
+
63
+ def _format_json_output(self) -> str:
64
+ """
65
+ Format the output data into a JSON object
66
+ """
67
+
68
+ formatted_data = []
69
+ for item in self.results.data:
70
+ formatted_data.append(
71
+ {
72
+ 'file': item.get('filename'),
73
+ 'status': item.get('status', 'N/A'),
74
+ 'match_type': item['id'],
75
+ 'matched': item.get('matched', 'N/A'),
76
+ 'purl': (item.get('purl')[0] if item.get('purl') else 'N/A'),
77
+ 'license': (item.get('licenses')[0].get('name', 'N/A') if item.get('licenses') else 'N/A'),
78
+ }
79
+ )
80
+ try:
81
+ return json.dumps({'results': formatted_data, 'total': len(formatted_data)}, indent=2)
82
+ except Exception as e:
83
+ self.base.print_stderr(f'ERROR: Problem formatting JSON output: {e}')
84
+ return ''
85
+
86
+ def _format_cyclonedx_output(self) -> str:
87
+ raise NotImplementedError('CycloneDX output is not implemented')
88
+
89
+ def _format_spdxlite_output(self) -> str:
90
+ raise NotImplementedError('SPDXlite output is not implemented')
91
+
92
+ def _format_csv_output(self) -> str:
93
+ raise NotImplementedError('CSV output is not implemented')
94
+
95
+ def _format_raw_output(self) -> str:
96
+ raise NotImplementedError('Raw output is not implemented')
97
+
98
+ def _format_plain_output(self) -> str:
99
+ """Format the output data into a plain text string
100
+
101
+ Returns:
102
+ str: The formatted output data
103
+ """
104
+ if not self.results.data:
105
+ msg = 'No results to present'
106
+ return msg
52
107
 
53
- class Results(ScanossBase):
108
+ formatted = ''
109
+ for item in self.results.data:
110
+ formatted += f'{self._format_plain_output_item(item)}\n'
111
+ return formatted
112
+
113
+ @staticmethod
114
+ def _format_plain_output_item(item):
115
+ purls = item.get('purl', [])
116
+ licenses = item.get('licenses', [])
117
+
118
+ return (
119
+ f'File: {item.get("filename")}\n'
120
+ f'Match type: {item.get("id")}\n'
121
+ f'Status: {item.get("status", "N/A")}\n'
122
+ f'Matched: {item.get("matched", "N/A")}\n'
123
+ f'Purl: {purls[0] if purls else "N/A"}\n'
124
+ f'License: {licenses[0].get("name", "N/A") if licenses else "N/A"}\n'
125
+ )
126
+
127
+
128
+ class Results:
54
129
  """
55
130
  SCANOSS Results class \n
56
131
  Handles the parsing and filtering of the scan results
57
132
  """
58
133
 
59
- def __init__(
134
+ def __init__( # noqa: PLR0913
60
135
  self,
61
136
  debug: bool = False,
62
137
  trace: bool = False,
@@ -80,11 +155,17 @@ class Results(ScanossBase):
80
155
  output_format (str, optional): Output format. Defaults to None.
81
156
  """
82
157
 
83
- super().__init__(debug, trace, quiet)
158
+ self.base = ScanossBase(debug, trace, quiet)
84
159
  self.data = self._load_and_transform(filepath)
85
160
  self.filters = self._load_filters(match_type=match_type, status=status)
86
- self.output_file = output_file
87
- self.output_format = output_format
161
+ self.presenter = ResultsPresenter(
162
+ self,
163
+ debug=debug,
164
+ trace=trace,
165
+ quiet=quiet,
166
+ output_file=output_file,
167
+ output_format=output_format,
168
+ )
88
169
 
89
170
  def load_file(self, file: str) -> Dict[str, Any]:
90
171
  """Load the JSON file
@@ -99,7 +180,7 @@ class Results(ScanossBase):
99
180
  try:
100
181
  return json.load(jsonfile)
101
182
  except Exception as e:
102
- self.print_stderr(f'ERROR: Problem parsing input JSON: {e}')
183
+ self.base.print_stderr(f'ERROR: Problem parsing input JSON: {e}')
103
184
 
104
185
  def _load_and_transform(self, file: str) -> List[Dict[str, Any]]:
105
186
  """
@@ -174,8 +255,8 @@ class Results(ScanossBase):
174
255
  def _validate_filter_values(filter_key: str, filter_value: List[str]):
175
256
  if any(value not in AVAILABLE_FILTER_VALUES.get(filter_key, []) for value in filter_value):
176
257
  valid_values = ', '.join(AVAILABLE_FILTER_VALUES.get(filter_key, []))
177
- raise Exception(
178
- f"ERROR: Invalid filter value '{filter_value}' for filter '{filter_key.value}'. "
258
+ raise ValueError(
259
+ f"ERROR: Invalid filter value '{filter_value}' for filter '{filter_key}'. "
179
260
  f'Valid values are: {valid_values}'
180
261
  )
181
262
 
@@ -190,103 +271,5 @@ class Results(ScanossBase):
190
271
  return bool(self.data)
191
272
 
192
273
  def present(self, output_format: str = None, output_file: str = None):
193
- """Format and present the results. If no output format is provided, the results will be printed to stdout
194
-
195
- Args:
196
- output_format (str, optional): Output format. Defaults to None.
197
- output_file (str, optional): Output file. Defaults to None.
198
-
199
- Raises:
200
- Exception: Invalid output format
201
-
202
- Returns:
203
- None
204
- """
205
- file_path = output_file or self.output_file
206
- fmt = output_format or self.output_format
207
-
208
- if fmt and fmt not in AVAILABLE_OUTPUT_FORMATS:
209
- raise Exception(
210
- f"ERROR: Invalid output format '{output_format}'. Valid values are: {', '.join(AVAILABLE_OUTPUT_FORMATS)}"
211
- )
212
-
213
- if fmt == 'json':
214
- return self._present_json(file_path)
215
- elif fmt == 'plain':
216
- return self._present_plain(file_path)
217
- else:
218
- return self._present_stdout()
219
-
220
- def _present_json(self, file: str = None):
221
- """Present the results in JSON format
222
-
223
- Args:
224
- file (str, optional): Output file. Defaults to None.
225
- """
226
- self.print_to_file_or_stdout(json.dumps(self._format_json_output(), indent=2), file)
227
-
228
- def _format_json_output(self):
229
- """
230
- Format the output data into a JSON object
231
- """
232
-
233
- formatted_data = []
234
- for item in self.data:
235
- formatted_data.append(
236
- {
237
- 'file': item.get('filename'),
238
- 'status': item.get('status', 'N/A'),
239
- 'match_type': item['id'],
240
- 'matched': item.get('matched', 'N/A'),
241
- 'purl': (item.get('purl')[0] if item.get('purl') else 'N/A'),
242
- 'license': (item.get('licenses')[0].get('name', 'N/A') if item.get('licenses') else 'N/A'),
243
- }
244
- )
245
- return {'results': formatted_data, 'total': len(formatted_data)}
246
-
247
- def _present_plain(self, file: str = None):
248
- """Present the results in plain text format
249
-
250
- Args:
251
- file (str, optional): Output file. Defaults to None.
252
-
253
- Returns:
254
- None
255
- """
256
- if not self.data:
257
- return self.print_stderr('No results to present')
258
- self.print_to_file_or_stdout(self._format_plain_output(), file)
259
-
260
- def _present_stdout(self):
261
- """Present the results to stdout
262
-
263
- Returns:
264
- None
265
- """
266
- if not self.data:
267
- return self.print_stderr('No results to present')
268
- self.print_to_file_or_stdout(self._format_plain_output())
269
-
270
- def _format_plain_output(self):
271
- """
272
- Format the output data into a plain text string
273
- """
274
-
275
- formatted = ''
276
- for item in self.data:
277
- formatted += f'{self._format_plain_output_item(item)} \n'
278
- return formatted
279
-
280
- @staticmethod
281
- def _format_plain_output_item(item):
282
- purls = item.get('purl', [])
283
- licenses = item.get('licenses', [])
284
-
285
- return (
286
- f'File: {item.get("filename")}\n'
287
- f'Match type: {item.get("id")}\n'
288
- f'Status: {item.get("status", "N/A")}\n'
289
- f'Matched: {item.get("matched", "N/A")}\n'
290
- f'Purl: {purls[0] if purls else "N/A"}\n'
291
- f'License: {licenses[0].get("name", "N/A") if licenses else "N/A"}\n'
292
- )
274
+ """Present the results in the selected format"""
275
+ self.presenter.present(output_format=output_format, output_file=output_file)
@@ -0,0 +1,23 @@
1
+ """
2
+ SPDX-License-Identifier: MIT
3
+
4
+ Copyright (c) 2025, SCANOSS
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+ """