scanoss 1.20.5__py3-none-any.whl → 1.22.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.
- protoc_gen_swagger/options/annotations_pb2.py +9 -12
- protoc_gen_swagger/options/annotations_pb2_grpc.py +1 -1
- protoc_gen_swagger/options/openapiv2_pb2.py +96 -98
- protoc_gen_swagger/options/openapiv2_pb2_grpc.py +1 -1
- scanoss/__init__.py +1 -1
- scanoss/api/common/v2/scanoss_common_pb2.py +20 -18
- scanoss/api/common/v2/scanoss_common_pb2_grpc.py +1 -1
- scanoss/api/components/v2/scanoss_components_pb2.py +38 -48
- scanoss/api/components/v2/scanoss_components_pb2_grpc.py +96 -142
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +42 -22
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +185 -75
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +32 -30
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +83 -75
- scanoss/api/provenance/v2/scanoss_provenance_pb2.py +20 -21
- scanoss/api/provenance/v2/scanoss_provenance_pb2_grpc.py +1 -1
- scanoss/api/scanning/v2/scanoss_scanning_pb2.py +20 -10
- scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +70 -40
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +18 -22
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +49 -71
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +27 -37
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +72 -109
- scanoss/cli.py +417 -74
- scanoss/components.py +5 -3
- scanoss/constants.py +12 -0
- scanoss/data/build_date.txt +1 -1
- scanoss/file_filters.py +272 -57
- scanoss/results.py +92 -109
- scanoss/scanner.py +25 -20
- scanoss/scanners/__init__.py +23 -0
- scanoss/scanners/container_scanner.py +474 -0
- scanoss/scanners/folder_hasher.py +302 -0
- scanoss/scanners/scanner_config.py +73 -0
- scanoss/scanners/scanner_hfh.py +172 -0
- scanoss/scanoss_settings.py +9 -5
- scanoss/scanossapi.py +29 -7
- scanoss/scanossbase.py +9 -3
- scanoss/scanossgrpc.py +145 -13
- scanoss/threadedscanning.py +6 -6
- scanoss/utils/abstract_presenter.py +103 -0
- scanoss/utils/crc64.py +96 -0
- scanoss/utils/simhash.py +198 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info}/METADATA +4 -2
- scanoss-1.22.0.dist-info/RECORD +83 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info}/WHEEL +1 -1
- scanoss-1.20.5.dist-info/RECORD +0 -74
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info}/entry_points.txt +0 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info/licenses}/LICENSE +0 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.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
|
-
|
|
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
|
-
|
|
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.
|
|
87
|
-
|
|
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
|
|
178
|
-
f"ERROR: Invalid filter value '{filter_value}' for filter '{filter_key
|
|
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
|
-
"""
|
|
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)
|
scanoss/scanner.py
CHANGED
|
@@ -69,7 +69,7 @@ class Scanner(ScanossBase):
|
|
|
69
69
|
Handle the scanning of files, snippets and dependencies
|
|
70
70
|
"""
|
|
71
71
|
|
|
72
|
-
def __init__(
|
|
72
|
+
def __init__( # noqa: PLR0913, PLR0915
|
|
73
73
|
self,
|
|
74
74
|
wfp: str = None,
|
|
75
75
|
scan_output: str = None,
|
|
@@ -106,6 +106,7 @@ class Scanner(ScanossBase):
|
|
|
106
106
|
strip_snippet_ids=None,
|
|
107
107
|
skip_md5_ids=None,
|
|
108
108
|
scan_settings: 'ScanossSettings | None' = None,
|
|
109
|
+
req_headers: dict = None,
|
|
109
110
|
):
|
|
110
111
|
"""
|
|
111
112
|
Initialise scanning class, including Winnowing, ScanossApi, ThreadedScanning
|
|
@@ -129,6 +130,7 @@ class Scanner(ScanossBase):
|
|
|
129
130
|
self.skip_folders = skip_folders
|
|
130
131
|
self.skip_size = skip_size
|
|
131
132
|
self.skip_extensions = skip_extensions
|
|
133
|
+
self.req_headers = req_headers
|
|
132
134
|
ver_details = Scanner.version_details()
|
|
133
135
|
|
|
134
136
|
self.winnowing = Winnowing(
|
|
@@ -156,6 +158,7 @@ class Scanner(ScanossBase):
|
|
|
156
158
|
ca_cert=ca_cert,
|
|
157
159
|
pac=pac,
|
|
158
160
|
retry=retry,
|
|
161
|
+
req_headers= self.req_headers,
|
|
159
162
|
)
|
|
160
163
|
sc_deps = ScancodeDeps(debug=debug, quiet=quiet, trace=trace, timeout=sc_timeout, sc_command=sc_command)
|
|
161
164
|
grpc_api = ScanossGrpc(
|
|
@@ -169,6 +172,7 @@ class Scanner(ScanossBase):
|
|
|
169
172
|
proxy=proxy,
|
|
170
173
|
pac=pac,
|
|
171
174
|
grpc_proxy=grpc_proxy,
|
|
175
|
+
req_headers=self.req_headers,
|
|
172
176
|
)
|
|
173
177
|
self.threaded_deps = ThreadedDependencies(sc_deps, grpc_api, debug=debug, quiet=quiet, trace=trace)
|
|
174
178
|
self.nb_threads = nb_threads
|
|
@@ -302,7 +306,7 @@ class Scanner(ScanossBase):
|
|
|
302
306
|
|
|
303
307
|
success = True
|
|
304
308
|
if not scan_dir:
|
|
305
|
-
raise Exception(
|
|
309
|
+
raise Exception('ERROR: Please specify a folder to scan')
|
|
306
310
|
if not os.path.exists(scan_dir) or not os.path.isdir(scan_dir):
|
|
307
311
|
raise Exception(f'ERROR: Specified folder does not exist or is not a folder: {scan_dir}')
|
|
308
312
|
if not self.is_file_or_snippet_scan() and not self.is_dependency_scan():
|
|
@@ -386,7 +390,8 @@ class Scanner(ScanossBase):
|
|
|
386
390
|
file_count += 1
|
|
387
391
|
if self.threaded_scan:
|
|
388
392
|
wfp_size = len(wfp.encode('utf-8'))
|
|
389
|
-
# If the WFP is bigger than the max post size and we already have something stored in the scan block,
|
|
393
|
+
# If the WFP is bigger than the max post size and we already have something stored in the scan block,
|
|
394
|
+
# add it to the queue
|
|
390
395
|
if scan_block != '' and (wfp_size + scan_size) >= self.max_post_size:
|
|
391
396
|
self.threaded_scan.queue_add(scan_block)
|
|
392
397
|
queue_size += 1
|
|
@@ -436,7 +441,7 @@ class Scanner(ScanossBase):
|
|
|
436
441
|
self.threaded_scan.update_bar(create=True, file_count=file_count)
|
|
437
442
|
if not scan_started:
|
|
438
443
|
if not self.threaded_scan.run(wait=False): # Run the scan but do not wait for it to complete
|
|
439
|
-
self.print_stderr(
|
|
444
|
+
self.print_stderr('Warning: Some errors encounted while scanning. Results might be incomplete.')
|
|
440
445
|
success = False
|
|
441
446
|
return success
|
|
442
447
|
|
|
@@ -457,14 +462,14 @@ class Scanner(ScanossBase):
|
|
|
457
462
|
dep_responses = None
|
|
458
463
|
if self.is_file_or_snippet_scan():
|
|
459
464
|
if not self.threaded_scan.complete(): # Wait for the scans to complete
|
|
460
|
-
self.print_stderr(
|
|
465
|
+
self.print_stderr('Warning: Scanning analysis ran into some trouble.')
|
|
461
466
|
success = False
|
|
462
467
|
self.threaded_scan.complete_bar()
|
|
463
468
|
scan_responses = self.threaded_scan.responses
|
|
464
469
|
if self.is_dependency_scan():
|
|
465
470
|
self.print_msg('Retrieving dependency data...')
|
|
466
471
|
if not self.threaded_deps.complete():
|
|
467
|
-
self.print_stderr(
|
|
472
|
+
self.print_stderr('Warning: Dependency analysis ran into some trouble.')
|
|
468
473
|
success = False
|
|
469
474
|
dep_responses = self.threaded_deps.responses
|
|
470
475
|
|
|
@@ -546,7 +551,7 @@ class Scanner(ScanossBase):
|
|
|
546
551
|
"""
|
|
547
552
|
success = True
|
|
548
553
|
if not file:
|
|
549
|
-
raise Exception(
|
|
554
|
+
raise Exception('ERROR: Please specify a file to scan')
|
|
550
555
|
if not os.path.exists(file) or not os.path.isfile(file):
|
|
551
556
|
raise Exception(f'ERROR: Specified file does not exist or is not a file: {file}')
|
|
552
557
|
if not self.is_file_or_snippet_scan() and not self.is_dependency_scan():
|
|
@@ -583,7 +588,7 @@ class Scanner(ScanossBase):
|
|
|
583
588
|
"""
|
|
584
589
|
success = True
|
|
585
590
|
if not file:
|
|
586
|
-
raise Exception(
|
|
591
|
+
raise Exception('ERROR: Please specify a file to scan')
|
|
587
592
|
if not os.path.exists(file) or not os.path.isfile(file):
|
|
588
593
|
raise Exception(f'ERROR: Specified files does not exist or is not a file: {file}')
|
|
589
594
|
self.print_debug(f'Fingerprinting {file}...')
|
|
@@ -608,7 +613,7 @@ class Scanner(ScanossBase):
|
|
|
608
613
|
"""
|
|
609
614
|
success = True
|
|
610
615
|
if not files:
|
|
611
|
-
raise Exception(
|
|
616
|
+
raise Exception('ERROR: Please provide a non-empty list of filenames to scan')
|
|
612
617
|
|
|
613
618
|
file_filters = FileFilters(
|
|
614
619
|
debug=self.debug,
|
|
@@ -671,7 +676,7 @@ class Scanner(ScanossBase):
|
|
|
671
676
|
scan_started = True
|
|
672
677
|
if not self.threaded_scan.run(wait=False):
|
|
673
678
|
self.print_stderr(
|
|
674
|
-
|
|
679
|
+
'Warning: Some errors encounted while scanning. Results might be incomplete.'
|
|
675
680
|
)
|
|
676
681
|
success = False
|
|
677
682
|
|
|
@@ -704,12 +709,12 @@ class Scanner(ScanossBase):
|
|
|
704
709
|
"""
|
|
705
710
|
success = True
|
|
706
711
|
if not files:
|
|
707
|
-
raise Exception(
|
|
712
|
+
raise Exception('ERROR: Please specify a list of files to scan')
|
|
708
713
|
if not self.is_file_or_snippet_scan():
|
|
709
714
|
raise Exception(f'ERROR: file or snippet scan options have to be set to scan files: {files}')
|
|
710
715
|
if self.is_dependency_scan() or deps_file:
|
|
711
716
|
raise Exception(
|
|
712
|
-
|
|
717
|
+
'ERROR: The dependency scan option is currently not supported when scanning a list of files'
|
|
713
718
|
)
|
|
714
719
|
if self.scan_output:
|
|
715
720
|
self.print_msg(f'Writing results to {self.scan_output}...')
|
|
@@ -731,9 +736,9 @@ class Scanner(ScanossBase):
|
|
|
731
736
|
"""
|
|
732
737
|
success = True
|
|
733
738
|
if not filename:
|
|
734
|
-
raise Exception(
|
|
739
|
+
raise Exception('ERROR: Please specify a filename to scan')
|
|
735
740
|
if not contents:
|
|
736
|
-
raise Exception(
|
|
741
|
+
raise Exception('ERROR: Please specify a file contents to scan')
|
|
737
742
|
|
|
738
743
|
self.print_debug(f'Fingerprinting {filename}...')
|
|
739
744
|
wfp = self.winnowing.wfp_for_contents(filename, False, contents)
|
|
@@ -924,7 +929,7 @@ class Scanner(ScanossBase):
|
|
|
924
929
|
scan_started = True
|
|
925
930
|
if not self.threaded_scan.run(wait=False):
|
|
926
931
|
self.print_stderr(
|
|
927
|
-
|
|
932
|
+
'Warning: Some errors uncounted while scanning. Results might be incomplete.'
|
|
928
933
|
)
|
|
929
934
|
success = False
|
|
930
935
|
# End for loop
|
|
@@ -948,7 +953,7 @@ class Scanner(ScanossBase):
|
|
|
948
953
|
"""
|
|
949
954
|
success = True
|
|
950
955
|
if not wfp:
|
|
951
|
-
raise Exception(
|
|
956
|
+
raise Exception('ERROR: Please specify a WFP to scan')
|
|
952
957
|
raw_output = '{\n'
|
|
953
958
|
scan_resp = self.scanoss_api.scan(wfp)
|
|
954
959
|
if scan_resp is not None:
|
|
@@ -984,9 +989,9 @@ class Scanner(ScanossBase):
|
|
|
984
989
|
:return:
|
|
985
990
|
"""
|
|
986
991
|
if not filename:
|
|
987
|
-
raise Exception(
|
|
992
|
+
raise Exception('ERROR: Please specify a filename to scan')
|
|
988
993
|
if not contents:
|
|
989
|
-
raise Exception(
|
|
994
|
+
raise Exception('ERROR: Please specify a file contents to scan')
|
|
990
995
|
|
|
991
996
|
self.print_debug(f'Fingerprinting {filename}...')
|
|
992
997
|
wfp = self.winnowing.wfp_for_contents(filename, False, contents)
|
|
@@ -1005,7 +1010,7 @@ class Scanner(ScanossBase):
|
|
|
1005
1010
|
Fingerprint the specified file
|
|
1006
1011
|
"""
|
|
1007
1012
|
if not scan_file:
|
|
1008
|
-
raise Exception(
|
|
1013
|
+
raise Exception('ERROR: Please specify a file to fingerprint')
|
|
1009
1014
|
if not os.path.exists(scan_file) or not os.path.isfile(scan_file):
|
|
1010
1015
|
raise Exception(f'ERROR: Specified file does not exist or is not a file: {scan_file}')
|
|
1011
1016
|
|
|
@@ -1026,7 +1031,7 @@ class Scanner(ScanossBase):
|
|
|
1026
1031
|
Fingerprint the specified folder producing fingerprints
|
|
1027
1032
|
"""
|
|
1028
1033
|
if not scan_dir:
|
|
1029
|
-
raise Exception(
|
|
1034
|
+
raise Exception('ERROR: Please specify a folder to fingerprint')
|
|
1030
1035
|
if not os.path.exists(scan_dir) or not os.path.isdir(scan_dir):
|
|
1031
1036
|
raise Exception(f'ERROR: Specified folder does not exist or is not a folder: {scan_dir}')
|
|
1032
1037
|
file_filters = FileFilters(
|
|
@@ -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
|
+
"""
|