scanoss 1.32.0__py3-none-any.whl → 1.34.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 +18 -12
- protoc_gen_swagger/options/annotations_pb2.pyi +48 -0
- protoc_gen_swagger/options/annotations_pb2_grpc.py +20 -0
- protoc_gen_swagger/options/openapiv2_pb2.py +110 -99
- protoc_gen_swagger/options/openapiv2_pb2.pyi +1317 -0
- protoc_gen_swagger/options/openapiv2_pb2_grpc.py +20 -0
- scanoss/__init__.py +1 -1
- scanoss/api/common/v2/scanoss_common_pb2.py +8 -6
- scanoss/api/common/v2/scanoss_common_pb2_grpc.py +5 -1
- scanoss/api/components/v2/scanoss_components_pb2.py +46 -32
- scanoss/api/components/v2/scanoss_components_pb2_grpc.py +6 -6
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +107 -29
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +545 -9
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +29 -21
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +1 -0
- scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +51 -19
- scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +189 -1
- scanoss/api/licenses/v2/scanoss_licenses_pb2.py +27 -27
- scanoss/api/scanning/v2/scanoss_scanning_pb2.py +18 -18
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +29 -13
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +102 -8
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +21 -21
- scanoss/cli.py +193 -146
- scanoss/components.py +57 -46
- scanoss/cryptography.py +64 -44
- scanoss/cyclonedx.py +22 -0
- scanoss/data/build_date.txt +1 -1
- scanoss/scanossgrpc.py +433 -314
- {scanoss-1.32.0.dist-info → scanoss-1.34.0.dist-info}/METADATA +4 -3
- {scanoss-1.32.0.dist-info → scanoss-1.34.0.dist-info}/RECORD +34 -32
- {scanoss-1.32.0.dist-info → scanoss-1.34.0.dist-info}/WHEEL +0 -0
- {scanoss-1.32.0.dist-info → scanoss-1.34.0.dist-info}/entry_points.txt +0 -0
- {scanoss-1.32.0.dist-info → scanoss-1.34.0.dist-info}/licenses/LICENSE +0 -0
- {scanoss-1.32.0.dist-info → scanoss-1.34.0.dist-info}/top_level.txt +0 -0
scanoss/components.py
CHANGED
|
@@ -29,6 +29,9 @@ from typing import List, Optional, TextIO
|
|
|
29
29
|
|
|
30
30
|
from pypac.parser import PACFile
|
|
31
31
|
|
|
32
|
+
from scanoss.cyclonedx import CycloneDx
|
|
33
|
+
from scanoss.utils.file import validate_json_file
|
|
34
|
+
|
|
32
35
|
from .scanner import Scanner
|
|
33
36
|
from .scanossbase import ScanossBase
|
|
34
37
|
from .scanossgrpc import ScanossGrpc
|
|
@@ -74,6 +77,7 @@ class Components(ScanossBase):
|
|
|
74
77
|
"""
|
|
75
78
|
super().__init__(debug, trace, quiet)
|
|
76
79
|
ver_details = Scanner.version_details()
|
|
80
|
+
self.use_grpc = use_grpc
|
|
77
81
|
self.grpc_api = ScanossGrpc(
|
|
78
82
|
url=grpc_url,
|
|
79
83
|
debug=debug,
|
|
@@ -88,10 +92,10 @@ class Components(ScanossBase):
|
|
|
88
92
|
timeout=timeout,
|
|
89
93
|
req_headers=req_headers,
|
|
90
94
|
ignore_cert_errors=ignore_cert_errors,
|
|
91
|
-
use_grpc=use_grpc,
|
|
92
95
|
)
|
|
96
|
+
self.cdx = CycloneDx(debug=self.debug)
|
|
93
97
|
|
|
94
|
-
def load_comps(self, json_file: Optional[str] = None, purls: Optional[List[str]] = None)-> Optional[dict]:
|
|
98
|
+
def load_comps(self, json_file: Optional[str] = None, purls: Optional[List[str]] = None) -> Optional[dict]:
|
|
95
99
|
"""
|
|
96
100
|
Load the specified components and return a dictionary
|
|
97
101
|
|
|
@@ -101,8 +105,9 @@ class Components(ScanossBase):
|
|
|
101
105
|
"""
|
|
102
106
|
return self.load_purls(json_file, purls, 'components')
|
|
103
107
|
|
|
104
|
-
def load_purls(
|
|
105
|
-
|
|
108
|
+
def load_purls(
|
|
109
|
+
self, json_file: Optional[str] = None, purls: Optional[List[str]] = None, field: str = 'purls'
|
|
110
|
+
) -> Optional[dict]:
|
|
106
111
|
"""
|
|
107
112
|
Load the specified purls and return a dictionary
|
|
108
113
|
|
|
@@ -112,15 +117,15 @@ class Components(ScanossBase):
|
|
|
112
117
|
:return: PURL Request dictionary or None
|
|
113
118
|
"""
|
|
114
119
|
if json_file:
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
result = validate_json_file(json_file)
|
|
121
|
+
if not result.is_valid:
|
|
122
|
+
self.print_stderr(f'ERROR: Problem parsing input JSON: {result.error}')
|
|
117
123
|
return None
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return None
|
|
124
|
+
|
|
125
|
+
if self.cdx.is_cyclonedx_json(json.dumps(result.data)):
|
|
126
|
+
purl_request = self.cdx.get_purls_request_from_cdx(result.data, field)
|
|
127
|
+
else:
|
|
128
|
+
purl_request = result.data
|
|
124
129
|
elif purls:
|
|
125
130
|
if not all(isinstance(purl, str) for purl in purls):
|
|
126
131
|
self.print_stderr('ERROR: PURLs must be a list of strings.')
|
|
@@ -185,32 +190,6 @@ class Components(ScanossBase):
|
|
|
185
190
|
self.print_trace(f'Closing file: {filename}')
|
|
186
191
|
file.close()
|
|
187
192
|
|
|
188
|
-
def get_crypto_details(self, json_file: str = None, purls: [] = None, output_file: str = None) -> bool:
|
|
189
|
-
"""
|
|
190
|
-
Retrieve the cryptographic details for the supplied PURLs
|
|
191
|
-
|
|
192
|
-
:param json_file: PURL JSON request file (optional)
|
|
193
|
-
:param purls: PURL request array (optional)
|
|
194
|
-
:param output_file: output filename (optional). Default: STDOUT
|
|
195
|
-
:return: True on success, False otherwise
|
|
196
|
-
"""
|
|
197
|
-
success = False
|
|
198
|
-
purls_request = self.load_purls(json_file, purls)
|
|
199
|
-
if purls_request is None or len(purls_request) == 0:
|
|
200
|
-
return False
|
|
201
|
-
file = self._open_file_or_sdtout(output_file)
|
|
202
|
-
if file is None:
|
|
203
|
-
return False
|
|
204
|
-
self.print_msg('Sending PURLs to Crypto API for decoration...')
|
|
205
|
-
response = self.grpc_api.get_crypto_json(purls_request)
|
|
206
|
-
if response:
|
|
207
|
-
print(json.dumps(response, indent=2, sort_keys=True), file=file)
|
|
208
|
-
success = True
|
|
209
|
-
if output_file:
|
|
210
|
-
self.print_msg(f'Results written to: {output_file}')
|
|
211
|
-
self._close_file(output_file, file)
|
|
212
|
-
return success
|
|
213
|
-
|
|
214
193
|
def get_vulnerabilities(self, json_file: str = None, purls: [] = None, output_file: str = None) -> bool:
|
|
215
194
|
"""
|
|
216
195
|
Retrieve any vulnerabilities related to the given PURLs
|
|
@@ -228,7 +207,7 @@ class Components(ScanossBase):
|
|
|
228
207
|
if file is None:
|
|
229
208
|
return False
|
|
230
209
|
self.print_msg('Sending PURLs to Vulnerability API for decoration...')
|
|
231
|
-
response = self.grpc_api.get_vulnerabilities_json(purls_request)
|
|
210
|
+
response = self.grpc_api.get_vulnerabilities_json(purls_request, use_grpc=self.use_grpc)
|
|
232
211
|
if response:
|
|
233
212
|
print(json.dumps(response, indent=2, sort_keys=True), file=file)
|
|
234
213
|
success = True
|
|
@@ -247,14 +226,14 @@ class Components(ScanossBase):
|
|
|
247
226
|
:return: True on success, False otherwise
|
|
248
227
|
"""
|
|
249
228
|
success = False
|
|
250
|
-
purls_request = self.
|
|
229
|
+
purls_request = self.load_comps(json_file, purls)
|
|
251
230
|
if purls_request is None or len(purls_request) == 0:
|
|
252
231
|
return False
|
|
253
232
|
file = self._open_file_or_sdtout(output_file)
|
|
254
233
|
if file is None:
|
|
255
234
|
return False
|
|
256
235
|
self.print_msg('Sending PURLs to Semgrep API for decoration...')
|
|
257
|
-
response = self.grpc_api.get_semgrep_json(purls_request)
|
|
236
|
+
response = self.grpc_api.get_semgrep_json(purls_request, use_grpc=self.use_grpc)
|
|
258
237
|
if response:
|
|
259
238
|
print(json.dumps(response, indent=2, sort_keys=True), file=file)
|
|
260
239
|
success = True
|
|
@@ -304,7 +283,7 @@ class Components(ScanossBase):
|
|
|
304
283
|
if file is None:
|
|
305
284
|
return False
|
|
306
285
|
self.print_msg('Sending search data to Components API...')
|
|
307
|
-
response = self.grpc_api.search_components_json(request)
|
|
286
|
+
response = self.grpc_api.search_components_json(request, use_grpc=self.use_grpc)
|
|
308
287
|
if response:
|
|
309
288
|
print(json.dumps(response, indent=2, sort_keys=True), file=file)
|
|
310
289
|
success = True
|
|
@@ -340,7 +319,7 @@ class Components(ScanossBase):
|
|
|
340
319
|
if file is None:
|
|
341
320
|
return False
|
|
342
321
|
self.print_msg('Sending PURLs to Component Versions API...')
|
|
343
|
-
response = self.grpc_api.get_component_versions_json(request)
|
|
322
|
+
response = self.grpc_api.get_component_versions_json(request, use_grpc=self.use_grpc)
|
|
344
323
|
if response:
|
|
345
324
|
print(json.dumps(response, indent=2, sort_keys=True), file=file)
|
|
346
325
|
success = True
|
|
@@ -365,7 +344,7 @@ class Components(ScanossBase):
|
|
|
365
344
|
bool: True on success, False otherwise
|
|
366
345
|
"""
|
|
367
346
|
success = False
|
|
368
|
-
purls_request = self.
|
|
347
|
+
purls_request = self.load_comps(json_file, purls)
|
|
369
348
|
if purls_request is None or len(purls_request) == 0:
|
|
370
349
|
return False
|
|
371
350
|
file = self._open_file_or_sdtout(output_file)
|
|
@@ -373,10 +352,42 @@ class Components(ScanossBase):
|
|
|
373
352
|
return False
|
|
374
353
|
if origin:
|
|
375
354
|
self.print_msg('Sending PURLs to Geo Provenance Origin API for decoration...')
|
|
376
|
-
response = self.grpc_api.get_provenance_origin(purls_request)
|
|
355
|
+
response = self.grpc_api.get_provenance_origin(purls_request, use_grpc=self.use_grpc)
|
|
377
356
|
else:
|
|
378
357
|
self.print_msg('Sending PURLs to Geo Provenance Declared API for decoration...')
|
|
379
|
-
response = self.grpc_api.get_provenance_json(purls_request)
|
|
358
|
+
response = self.grpc_api.get_provenance_json(purls_request, use_grpc=self.use_grpc)
|
|
359
|
+
if response:
|
|
360
|
+
print(json.dumps(response, indent=2, sort_keys=True), file=file)
|
|
361
|
+
success = True
|
|
362
|
+
if output_file:
|
|
363
|
+
self.print_msg(f'Results written to: {output_file}')
|
|
364
|
+
self._close_file(output_file, file)
|
|
365
|
+
return success
|
|
366
|
+
|
|
367
|
+
def get_licenses(self, json_file: str = None, purls: [] = None, output_file: str = None) -> bool:
|
|
368
|
+
"""
|
|
369
|
+
Retrieve the license details for the supplied PURLs
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
json_file (str, optional): Input JSON file. Defaults to None.
|
|
373
|
+
purls (None, optional): PURLs to retrieve license details for. Defaults to None.
|
|
374
|
+
output_file (str, optional): Output file. Defaults to None.
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
bool: True on success, False otherwise
|
|
378
|
+
"""
|
|
379
|
+
success = False
|
|
380
|
+
|
|
381
|
+
purls_request = self.load_purls(json_file, purls)
|
|
382
|
+
if not purls_request:
|
|
383
|
+
return False
|
|
384
|
+
file = self._open_file_or_sdtout(output_file)
|
|
385
|
+
if file is None:
|
|
386
|
+
return False
|
|
387
|
+
|
|
388
|
+
# We'll use the new ComponentBatchRequest instead of deprecated PurlRequest for the license api
|
|
389
|
+
component_batch_request = {'components': purls_request.get('purls')}
|
|
390
|
+
response = self.grpc_api.get_licenses(component_batch_request, use_grpc=self.use_grpc)
|
|
380
391
|
if response:
|
|
381
392
|
print(json.dumps(response, indent=2, sort_keys=True), file=file)
|
|
382
393
|
success = True
|
scanoss/cryptography.py
CHANGED
|
@@ -2,6 +2,7 @@ import json
|
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from typing import Dict, List, Optional
|
|
4
4
|
|
|
5
|
+
from scanoss.cyclonedx import CycloneDx
|
|
5
6
|
from scanoss.scanossbase import ScanossBase
|
|
6
7
|
from scanoss.scanossgrpc import ScanossGrpc
|
|
7
8
|
from scanoss.utils.abstract_presenter import AbstractPresenter
|
|
@@ -18,14 +19,47 @@ MIN_SPLIT_PARTS = 2
|
|
|
18
19
|
@dataclass
|
|
19
20
|
class CryptographyConfig:
|
|
20
21
|
purl: List[str]
|
|
22
|
+
debug: bool = False
|
|
23
|
+
header: Optional[str] = None
|
|
21
24
|
input_file: Optional[str] = None
|
|
22
25
|
output_file: Optional[str] = None
|
|
23
|
-
header: Optional[str] = None
|
|
24
|
-
debug: bool = False
|
|
25
|
-
trace: bool = False
|
|
26
26
|
quiet: bool = False
|
|
27
|
+
trace: bool = False
|
|
28
|
+
use_grpc: bool = False
|
|
27
29
|
with_range: bool = False
|
|
28
30
|
|
|
31
|
+
def _process_input_file(self) -> dict:
|
|
32
|
+
"""
|
|
33
|
+
Process and validate the input file, returning the validated purl_request.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
dict: The validated purl_request dictionary
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
ScanossCryptographyError: If the input file is invalid
|
|
40
|
+
"""
|
|
41
|
+
result = validate_json_file(self.input_file)
|
|
42
|
+
if not result.is_valid:
|
|
43
|
+
raise ScanossCryptographyError(
|
|
44
|
+
f'There was a problem with the purl input file. {result.error}'
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
cdx = CycloneDx(debug=self.debug)
|
|
48
|
+
if cdx.is_cyclonedx_json(json.dumps(result.data)):
|
|
49
|
+
purl_request = cdx.get_purls_request_from_cdx(result.data)
|
|
50
|
+
else:
|
|
51
|
+
purl_request = result.data
|
|
52
|
+
|
|
53
|
+
if (
|
|
54
|
+
not isinstance(purl_request, dict)
|
|
55
|
+
or 'purls' not in purl_request
|
|
56
|
+
or not isinstance(purl_request['purls'], list)
|
|
57
|
+
or not all(isinstance(p, dict) and 'purl' in p for p in purl_request['purls'])
|
|
58
|
+
):
|
|
59
|
+
raise ScanossCryptographyError('The supplied input file is not in the correct PurlRequest format.')
|
|
60
|
+
|
|
61
|
+
return purl_request
|
|
62
|
+
|
|
29
63
|
def __post_init__(self):
|
|
30
64
|
"""
|
|
31
65
|
Validate that the configuration is valid.
|
|
@@ -36,22 +70,11 @@ class CryptographyConfig:
|
|
|
36
70
|
parts = purl.split('@')
|
|
37
71
|
if not (len(parts) >= MIN_SPLIT_PARTS and parts[1]):
|
|
38
72
|
raise ScanossCryptographyError(
|
|
39
|
-
f'Invalid PURL format: "{purl}".
|
|
73
|
+
f'Invalid PURL format: "{purl}".It must include a version (e.g., pkg:type/name@version)'
|
|
40
74
|
)
|
|
41
75
|
if self.input_file:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
raise ScanossCryptographyError(
|
|
45
|
-
f'There was a problem with the purl input file. {input_file_validation.error}'
|
|
46
|
-
)
|
|
47
|
-
if (
|
|
48
|
-
not isinstance(input_file_validation.data, dict)
|
|
49
|
-
or 'purls' not in input_file_validation.data
|
|
50
|
-
or not isinstance(input_file_validation.data['purls'], list)
|
|
51
|
-
or not all(isinstance(p, dict) and 'purl' in p for p in input_file_validation.data['purls'])
|
|
52
|
-
):
|
|
53
|
-
raise ScanossCryptographyError('The supplied input file is not in the correct PurlRequest format.')
|
|
54
|
-
purls = input_file_validation.data['purls']
|
|
76
|
+
purl_request = self._process_input_file()
|
|
77
|
+
purls = purl_request['purls']
|
|
55
78
|
purls_with_requirement = []
|
|
56
79
|
if self.with_range and any('requirement' not in p for p in purls):
|
|
57
80
|
raise ScanossCryptographyError(
|
|
@@ -69,13 +92,14 @@ class CryptographyConfig:
|
|
|
69
92
|
def create_cryptography_config_from_args(args) -> CryptographyConfig:
|
|
70
93
|
return CryptographyConfig(
|
|
71
94
|
debug=getattr(args, 'debug', False),
|
|
72
|
-
|
|
73
|
-
quiet=getattr(args, 'quiet', False),
|
|
74
|
-
with_range=getattr(args, 'with_range', False),
|
|
75
|
-
purl=getattr(args, 'purl', []),
|
|
95
|
+
header=getattr(args, 'header', None),
|
|
76
96
|
input_file=getattr(args, 'input', None),
|
|
77
97
|
output_file=getattr(args, 'output', None),
|
|
78
|
-
|
|
98
|
+
purl=getattr(args, 'purl', []),
|
|
99
|
+
quiet=getattr(args, 'quiet', False),
|
|
100
|
+
trace=getattr(args, 'trace', False),
|
|
101
|
+
use_grpc=getattr(args, 'grpc', False),
|
|
102
|
+
with_range=getattr(args, 'with_range', False),
|
|
79
103
|
)
|
|
80
104
|
|
|
81
105
|
|
|
@@ -112,7 +136,7 @@ class Cryptography:
|
|
|
112
136
|
|
|
113
137
|
self.client = client
|
|
114
138
|
self.config = config
|
|
115
|
-
self.
|
|
139
|
+
self.components_request = self._build_components_request()
|
|
116
140
|
self.results = None
|
|
117
141
|
|
|
118
142
|
def get_algorithms(self) -> Optional[Dict]:
|
|
@@ -123,15 +147,16 @@ class Cryptography:
|
|
|
123
147
|
Optional[Dict]: The folder hash response from the gRPC client, or None if an error occurs.
|
|
124
148
|
"""
|
|
125
149
|
|
|
126
|
-
if not self.
|
|
150
|
+
if not self.components_request or not self.components_request.get('components'):
|
|
127
151
|
raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
|
|
128
|
-
self.
|
|
129
|
-
|
|
130
|
-
)
|
|
152
|
+
components_str = ', '.join(p['purl'] for p in self.components_request['components'])
|
|
153
|
+
self.base.print_stderr(f'Getting cryptographic algorithms for {components_str}')
|
|
131
154
|
if self.config.with_range:
|
|
132
|
-
response = self.client.get_crypto_algorithms_in_range_for_purl(
|
|
155
|
+
response = self.client.get_crypto_algorithms_in_range_for_purl(
|
|
156
|
+
self.components_request, self.config.use_grpc
|
|
157
|
+
)
|
|
133
158
|
else:
|
|
134
|
-
response = self.client.get_crypto_algorithms_for_purl(self.
|
|
159
|
+
response = self.client.get_crypto_algorithms_for_purl(self.components_request, self.config.use_grpc)
|
|
135
160
|
if response:
|
|
136
161
|
self.results = response
|
|
137
162
|
|
|
@@ -145,17 +170,17 @@ class Cryptography:
|
|
|
145
170
|
Optional[Dict]: The encryption hints response from the gRPC client, or None if an error occurs.
|
|
146
171
|
"""
|
|
147
172
|
|
|
148
|
-
if not self.
|
|
173
|
+
if not self.components_request or not self.components_request.get('components'):
|
|
149
174
|
raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
|
|
150
175
|
self.base.print_stderr(
|
|
151
176
|
f'Getting encryption hints '
|
|
152
177
|
f'{"in range" if self.config.with_range else ""} '
|
|
153
|
-
f'for {", ".join([p["purl"] for p in self.
|
|
178
|
+
f'for {", ".join([p["purl"] for p in self.components_request["components"]])}'
|
|
154
179
|
)
|
|
155
180
|
if self.config.with_range:
|
|
156
|
-
response = self.client.get_encryption_hints_in_range_for_purl(self.
|
|
181
|
+
response = self.client.get_encryption_hints_in_range_for_purl(self.components_request, self.config.use_grpc)
|
|
157
182
|
else:
|
|
158
|
-
response = self.client.get_encryption_hints_for_purl(self.
|
|
183
|
+
response = self.client.get_encryption_hints_for_purl(self.components_request, self.config.use_grpc)
|
|
159
184
|
if response:
|
|
160
185
|
self.results = response
|
|
161
186
|
|
|
@@ -169,34 +194,29 @@ class Cryptography:
|
|
|
169
194
|
Optional[Dict]: The versions in range response from the gRPC client, or None if an error occurs.
|
|
170
195
|
"""
|
|
171
196
|
|
|
172
|
-
if not self.
|
|
197
|
+
if not self.components_request or not self.components_request.get('components'):
|
|
173
198
|
raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
|
|
174
199
|
|
|
175
|
-
self.
|
|
176
|
-
|
|
177
|
-
)
|
|
200
|
+
components_str = ', '.join(p['purl'] for p in self.components_request['components'])
|
|
201
|
+
self.base.print_stderr(f'Getting versions in range for {components_str}')
|
|
178
202
|
|
|
179
|
-
response = self.client.get_versions_in_range_for_purl(self.
|
|
203
|
+
response = self.client.get_versions_in_range_for_purl(self.components_request, self.config.use_grpc)
|
|
180
204
|
if response:
|
|
181
205
|
self.results = response
|
|
182
206
|
|
|
183
207
|
return self.results
|
|
184
208
|
|
|
185
|
-
def
|
|
209
|
+
def _build_components_request(
|
|
186
210
|
self,
|
|
187
211
|
) -> Optional[dict]:
|
|
188
212
|
"""
|
|
189
213
|
Load the specified purls from a JSON file or a list of PURLs and return a dictionary
|
|
190
214
|
|
|
191
|
-
Args:
|
|
192
|
-
json_file (Optional[str], optional): The JSON file containing the PURLs. Defaults to None.
|
|
193
|
-
purls (Optional[List[str]], optional): The list of PURLs. Defaults to None.
|
|
194
|
-
|
|
195
215
|
Returns:
|
|
196
216
|
Optional[dict]: The dictionary containing the PURLs
|
|
197
217
|
"""
|
|
198
218
|
return {
|
|
199
|
-
'
|
|
219
|
+
'components': [
|
|
200
220
|
{
|
|
201
221
|
'purl': self._remove_version_from_purl(purl),
|
|
202
222
|
'requirement': self._extract_version_from_purl(purl),
|
scanoss/cyclonedx.py
CHANGED
|
@@ -394,6 +394,7 @@ class CycloneDx(ScanossBase):
|
|
|
394
394
|
def is_cyclonedx_json(self, json_string: str) -> bool:
|
|
395
395
|
"""
|
|
396
396
|
Validate if the given JSON string is a valid CycloneDX JSON string
|
|
397
|
+
|
|
397
398
|
Args:
|
|
398
399
|
json_string (str): JSON string to validate
|
|
399
400
|
Returns:
|
|
@@ -410,6 +411,27 @@ class CycloneDx(ScanossBase):
|
|
|
410
411
|
self.print_stderr(f'ERROR: Problem parsing input JSON: {e}')
|
|
411
412
|
return False
|
|
412
413
|
|
|
414
|
+
def get_purls_request_from_cdx(self, cdx_dict: dict, field: str = 'purls') -> dict:
|
|
415
|
+
"""
|
|
416
|
+
Get the list of PURL requests (purl + requirement) from the given CDX dictionary
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
cdx_dict (dict): CDX dictionary to parse
|
|
420
|
+
field (str): Field to extract from the CDX dictionary
|
|
421
|
+
Returns:
|
|
422
|
+
list[dict]: List of PURL requests (purl + requirement)
|
|
423
|
+
"""
|
|
424
|
+
components = cdx_dict.get('components', [])
|
|
425
|
+
parsed_purls = []
|
|
426
|
+
for component in components:
|
|
427
|
+
version = component.get('version')
|
|
428
|
+
if version:
|
|
429
|
+
parsed_purls.append({'purl': component.get('purl'), 'requirement': version})
|
|
430
|
+
else:
|
|
431
|
+
parsed_purls.append({'purl': component.get('purl')})
|
|
432
|
+
purl_request = {field: parsed_purls}
|
|
433
|
+
return purl_request
|
|
434
|
+
|
|
413
435
|
|
|
414
436
|
#
|
|
415
437
|
# End of CycloneDX Class
|
scanoss/data/build_date.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
date:
|
|
1
|
+
date: 20251006080454, utime: 1759737894
|