scanoss 1.12.2__py3-none-any.whl → 1.43.1__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/__init__.py +13 -13
- protoc_gen_swagger/options/__init__.py +13 -13
- 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 +18 -18
- scanoss/api/__init__.py +17 -17
- scanoss/api/common/__init__.py +17 -17
- scanoss/api/common/v2/__init__.py +17 -17
- scanoss/api/common/v2/scanoss_common_pb2.py +49 -20
- scanoss/api/common/v2/scanoss_common_pb2_grpc.py +25 -0
- scanoss/api/components/__init__.py +17 -17
- scanoss/api/components/v2/__init__.py +17 -17
- scanoss/api/components/v2/scanoss_components_pb2.py +68 -43
- scanoss/api/components/v2/scanoss_components_pb2_grpc.py +83 -22
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +136 -21
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +766 -13
- scanoss/api/dependencies/__init__.py +17 -17
- scanoss/api/dependencies/v2/__init__.py +17 -17
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +56 -29
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +94 -8
- scanoss/api/geoprovenance/__init__.py +23 -0
- scanoss/api/geoprovenance/v2/__init__.py +23 -0
- scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +92 -0
- scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +381 -0
- scanoss/api/licenses/__init__.py +23 -0
- scanoss/api/licenses/v2/__init__.py +23 -0
- scanoss/api/licenses/v2/scanoss_licenses_pb2.py +84 -0
- scanoss/api/licenses/v2/scanoss_licenses_pb2_grpc.py +302 -0
- scanoss/api/scanning/__init__.py +17 -17
- scanoss/api/scanning/v2/__init__.py +17 -17
- scanoss/api/scanning/v2/scanoss_scanning_pb2.py +42 -13
- scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +86 -7
- scanoss/api/semgrep/__init__.py +17 -17
- scanoss/api/semgrep/v2/__init__.py +17 -17
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +50 -23
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +151 -16
- scanoss/api/vulnerabilities/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +78 -31
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +282 -18
- scanoss/cli.py +2359 -370
- scanoss/components.py +187 -94
- scanoss/constants.py +22 -0
- scanoss/cryptography.py +308 -0
- scanoss/csvoutput.py +91 -58
- scanoss/cyclonedx.py +221 -63
- scanoss/data/build_date.txt +1 -1
- scanoss/data/osadl-copyleft.json +133 -0
- scanoss/data/scanoss-settings-schema.json +254 -0
- scanoss/delta.py +197 -0
- scanoss/export/__init__.py +23 -0
- scanoss/export/dependency_track.py +227 -0
- scanoss/file_filters.py +582 -0
- scanoss/filecount.py +75 -69
- scanoss/gitlabqualityreport.py +214 -0
- scanoss/header_filter.py +563 -0
- scanoss/inspection/__init__.py +23 -0
- scanoss/inspection/policy_check/__init__.py +0 -0
- scanoss/inspection/policy_check/dependency_track/__init__.py +0 -0
- scanoss/inspection/policy_check/dependency_track/project_violation.py +479 -0
- scanoss/inspection/policy_check/policy_check.py +222 -0
- scanoss/inspection/policy_check/scanoss/__init__.py +0 -0
- scanoss/inspection/policy_check/scanoss/copyleft.py +243 -0
- scanoss/inspection/policy_check/scanoss/undeclared_component.py +309 -0
- scanoss/inspection/summary/__init__.py +0 -0
- scanoss/inspection/summary/component_summary.py +170 -0
- scanoss/inspection/summary/license_summary.py +191 -0
- scanoss/inspection/summary/match_summary.py +341 -0
- scanoss/inspection/utils/file_utils.py +44 -0
- scanoss/inspection/utils/license_utils.py +123 -0
- scanoss/inspection/utils/markdown_utils.py +63 -0
- scanoss/inspection/utils/scan_result_processor.py +417 -0
- scanoss/osadl.py +125 -0
- scanoss/results.py +275 -0
- scanoss/scancodedeps.py +87 -38
- scanoss/scanner.py +431 -539
- scanoss/scanners/__init__.py +23 -0
- scanoss/scanners/container_scanner.py +476 -0
- scanoss/scanners/folder_hasher.py +358 -0
- scanoss/scanners/scanner_config.py +73 -0
- scanoss/scanners/scanner_hfh.py +252 -0
- scanoss/scanoss_settings.py +337 -0
- scanoss/scanossapi.py +140 -101
- scanoss/scanossbase.py +59 -22
- scanoss/scanossgrpc.py +799 -251
- scanoss/scanpostprocessor.py +294 -0
- scanoss/scantype.py +22 -21
- scanoss/services/dependency_track_service.py +132 -0
- scanoss/spdxlite.py +532 -174
- scanoss/threadeddependencies.py +148 -47
- scanoss/threadedscanning.py +53 -37
- scanoss/utils/__init__.py +23 -0
- scanoss/utils/abstract_presenter.py +103 -0
- scanoss/utils/crc64.py +96 -0
- scanoss/utils/file.py +84 -0
- scanoss/utils/scanoss_scan_results_utils.py +41 -0
- scanoss/utils/simhash.py +198 -0
- scanoss/winnowing.py +241 -63
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/METADATA +18 -9
- scanoss-1.43.1.dist-info/RECORD +110 -0
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/WHEEL +1 -1
- scanoss-1.12.2.dist-info/RECORD +0 -58
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/entry_points.txt +0 -0
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info/licenses}/LICENSE +0 -0
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/top_level.txt +0 -0
scanoss/scanossapi.py
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2022, 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
23
|
"""
|
|
24
|
+
|
|
25
|
+
import http.client as http_client
|
|
24
26
|
import logging
|
|
25
27
|
import os
|
|
26
28
|
import sys
|
|
27
29
|
import time
|
|
30
|
+
import uuid
|
|
28
31
|
from json.decoder import JSONDecodeError
|
|
32
|
+
|
|
29
33
|
import requests
|
|
30
|
-
import uuid
|
|
31
|
-
import http.client as http_client
|
|
32
34
|
import urllib3
|
|
33
|
-
|
|
34
35
|
from pypac import PACSession
|
|
35
36
|
from pypac.parser import PACFile
|
|
36
37
|
from urllib3.exceptions import InsecureRequestWarning
|
|
37
|
-
from .scanossbase import ScanossBase
|
|
38
|
-
from . import __version__
|
|
39
38
|
|
|
39
|
+
from . import __version__
|
|
40
|
+
from .constants import DEFAULT_TIMEOUT, MIN_TIMEOUT
|
|
41
|
+
from .scanossbase import ScanossBase
|
|
40
42
|
|
|
41
|
-
DEFAULT_URL =
|
|
42
|
-
DEFAULT_URL2 =
|
|
43
|
-
SCANOSS_SCAN_URL = os.environ.get(
|
|
44
|
-
SCANOSS_API_KEY = os.environ.get(
|
|
43
|
+
DEFAULT_URL = 'https://api.osskb.org/scan/direct' # default free service URL
|
|
44
|
+
DEFAULT_URL2 = 'https://api.scanoss.com/scan/direct' # default premium service URL
|
|
45
|
+
SCANOSS_SCAN_URL = os.environ.get('SCANOSS_SCAN_URL') if os.environ.get('SCANOSS_SCAN_URL') else DEFAULT_URL
|
|
46
|
+
SCANOSS_API_KEY = os.environ.get('SCANOSS_API_KEY') if os.environ.get('SCANOSS_API_KEY') else ''
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
class ScanossApi(ScanossBase):
|
|
@@ -50,21 +52,33 @@ class ScanossApi(ScanossBase):
|
|
|
50
52
|
Currently support posting scan requests to the SCANOSS streaming API
|
|
51
53
|
"""
|
|
52
54
|
|
|
53
|
-
def __init__(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
def __init__( # noqa: PLR0912, PLR0913, PLR0915
|
|
56
|
+
self,
|
|
57
|
+
scan_format: str = None,
|
|
58
|
+
flags: str = None,
|
|
59
|
+
url: str = None,
|
|
60
|
+
api_key: str = None,
|
|
61
|
+
debug: bool = False,
|
|
62
|
+
trace: bool = False,
|
|
63
|
+
quiet: bool = False,
|
|
64
|
+
timeout: int = DEFAULT_TIMEOUT,
|
|
65
|
+
ver_details: str = None,
|
|
66
|
+
ignore_cert_errors: bool = False,
|
|
67
|
+
proxy: str = None,
|
|
68
|
+
ca_cert: str = None,
|
|
69
|
+
pac: PACFile = None,
|
|
70
|
+
retry: int = 5,
|
|
71
|
+
req_headers: dict = None,
|
|
72
|
+
):
|
|
57
73
|
"""
|
|
58
74
|
Initialise the SCANOSS API
|
|
59
|
-
:param scan_type: Scan type (default identify)
|
|
60
|
-
:param sbom_path: Input SBOM file to match scan type (default None)
|
|
61
75
|
:param scan_format: Scan format (default plain)
|
|
62
76
|
:param flags: Scanning flags (default None)
|
|
63
77
|
:param url: API URL (default https://api.osskb.org/scan/direct)
|
|
64
78
|
:param api_key: API Key (default None)
|
|
65
79
|
:param debug: Enable debug (default False)
|
|
66
80
|
:param trace: Enable trace (default False)
|
|
67
|
-
:param quiet: Enable
|
|
81
|
+
:param quiet: Enable quiet mode (default False)
|
|
68
82
|
|
|
69
83
|
To set a custom certificate use:
|
|
70
84
|
REQUESTS_CA_BUNDLE=/path/to/cert.pem
|
|
@@ -73,38 +87,40 @@ class ScanossApi(ScanossBase):
|
|
|
73
87
|
HTTPS_PROXY='http://<ip>:<port>'
|
|
74
88
|
"""
|
|
75
89
|
super().__init__(debug, trace, quiet)
|
|
76
|
-
self.
|
|
77
|
-
self.api_key = api_key if api_key else SCANOSS_API_KEY
|
|
78
|
-
if self.api_key and not url and not os.environ.get("SCANOSS_SCAN_URL"):
|
|
79
|
-
self.url = DEFAULT_URL2 # API key specific and no alternative URL, so use the default premium
|
|
80
|
-
self.scan_type = scan_type
|
|
90
|
+
self.sbom = None
|
|
81
91
|
self.scan_format = scan_format if scan_format else 'plain'
|
|
82
|
-
self.sbom_path = sbom_path
|
|
83
92
|
self.flags = flags
|
|
84
|
-
self.timeout = timeout if timeout >
|
|
93
|
+
self.timeout = timeout if timeout > MIN_TIMEOUT else DEFAULT_TIMEOUT
|
|
85
94
|
self.retry_limit = retry if retry >= 0 else 5
|
|
86
95
|
self.ignore_cert_errors = ignore_cert_errors
|
|
96
|
+
self.req_headers = req_headers if req_headers else {}
|
|
87
97
|
self.headers = {}
|
|
98
|
+
# Set the correct URL/API key combination
|
|
99
|
+
self.url = url if url else SCANOSS_SCAN_URL
|
|
100
|
+
self.api_key = api_key if api_key else SCANOSS_API_KEY
|
|
101
|
+
if self.api_key and not url and not os.environ.get('SCANOSS_SCAN_URL'):
|
|
102
|
+
self.url = DEFAULT_URL2 # API key specific and no alternative URL, so use the default premium
|
|
88
103
|
if ver_details:
|
|
89
104
|
self.headers['x-scanoss-client'] = ver_details
|
|
90
105
|
if self.api_key:
|
|
91
106
|
self.headers['X-Session'] = self.api_key
|
|
92
107
|
self.headers['x-api-key'] = self.api_key
|
|
93
|
-
|
|
94
|
-
self.headers['
|
|
95
|
-
self.
|
|
96
|
-
self.
|
|
108
|
+
user_agent = f'scanoss-py/{__version__}'
|
|
109
|
+
self.headers['User-Agent'] = user_agent
|
|
110
|
+
self.headers['user-agent'] = user_agent
|
|
111
|
+
self.load_generic_headers(url)
|
|
112
|
+
|
|
97
113
|
if self.trace:
|
|
98
114
|
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
|
99
115
|
http_client.HTTPConnection.debuglevel = 1
|
|
100
116
|
if pac and not proxy: # Setup PAC session if requested (and no proxy has been explicitly set)
|
|
101
|
-
self.print_debug(
|
|
117
|
+
self.print_debug('Setting up PAC session...')
|
|
102
118
|
self.session = PACSession(pac=pac)
|
|
103
119
|
else:
|
|
104
120
|
self.session = requests.sessions.Session()
|
|
105
121
|
self.verify = None
|
|
106
122
|
if self.ignore_cert_errors:
|
|
107
|
-
self.print_debug(
|
|
123
|
+
self.print_debug('Ignoring cert errors...')
|
|
108
124
|
urllib3.disable_warnings(InsecureRequestWarning)
|
|
109
125
|
self.verify = False
|
|
110
126
|
self.session.verify = False
|
|
@@ -112,21 +128,10 @@ class ScanossApi(ScanossBase):
|
|
|
112
128
|
self.verify = ca_cert
|
|
113
129
|
self.session.verify = ca_cert
|
|
114
130
|
self.proxies = {'https': proxy, 'http': proxy} if proxy else None
|
|
115
|
-
if self.
|
|
131
|
+
if self.proxies:
|
|
116
132
|
self.session.proxies = self.proxies
|
|
117
133
|
|
|
118
|
-
def
|
|
119
|
-
"""
|
|
120
|
-
Load the input SBOM if one exists
|
|
121
|
-
"""
|
|
122
|
-
if self.sbom_path:
|
|
123
|
-
if not self.scan_type:
|
|
124
|
-
self.scan_type = 'identify' # Default to identify SBOM type if it's not set
|
|
125
|
-
self.print_debug(f'Loading {self.scan_type} SBOM {self.sbom_path}...')
|
|
126
|
-
with open(self.sbom_path) as f:
|
|
127
|
-
self.sbom = f.read()
|
|
128
|
-
|
|
129
|
-
def scan(self, wfp: str, context: str = None, scan_id: int = None):
|
|
134
|
+
def scan(self, wfp: str, context: str = None, scan_id: int = None): # noqa: PLR0912, PLR0915
|
|
130
135
|
"""
|
|
131
136
|
Scan the specified WFP and return the JSON object
|
|
132
137
|
:param wfp: WFP to scan
|
|
@@ -137,15 +142,16 @@ class ScanossApi(ScanossBase):
|
|
|
137
142
|
request_id = str(uuid.uuid4())
|
|
138
143
|
form_data = {}
|
|
139
144
|
if self.sbom:
|
|
140
|
-
form_data['type'] = self.scan_type
|
|
141
|
-
form_data['assets'] = self.sbom
|
|
145
|
+
form_data['type'] = self.sbom.get('scan_type')
|
|
146
|
+
form_data['assets'] = self.sbom.get('assets')
|
|
142
147
|
if self.scan_format:
|
|
143
148
|
form_data['format'] = self.scan_format
|
|
144
149
|
if self.flags:
|
|
145
150
|
form_data['flags'] = self.flags
|
|
146
151
|
if context:
|
|
147
152
|
form_data['context'] = context
|
|
148
|
-
|
|
153
|
+
|
|
154
|
+
scan_files = {'file': ('%s.wfp' % request_id, wfp)}
|
|
149
155
|
headers = self.headers
|
|
150
156
|
headers['x-request-id'] = request_id # send a unique request id for each post
|
|
151
157
|
r = None
|
|
@@ -154,75 +160,87 @@ class ScanossApi(ScanossBase):
|
|
|
154
160
|
retry += 1
|
|
155
161
|
try:
|
|
156
162
|
r = None
|
|
157
|
-
r = self.session.post(
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
r = self.session.post(
|
|
164
|
+
self.url, files=scan_files, data=form_data, headers=self.headers, timeout=self.timeout
|
|
165
|
+
)
|
|
160
166
|
except (requests.exceptions.SSLError, requests.exceptions.ProxyError) as e:
|
|
161
167
|
self.print_stderr(f'ERROR: Exception ({e.__class__.__name__}) POSTing data - {e}.')
|
|
162
|
-
raise Exception(f
|
|
168
|
+
raise Exception(f'ERROR: The SCANOSS API request failed for {self.url}') from e
|
|
163
169
|
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
|
|
164
170
|
if retry > self.retry_limit: # Timed out retry_limit or more times, fail
|
|
165
171
|
self.print_stderr(f'ERROR: {e.__class__.__name__} POSTing data ({request_id}) - {e}: {scan_files}')
|
|
166
|
-
raise Exception(
|
|
167
|
-
|
|
172
|
+
raise Exception(
|
|
173
|
+
f'ERROR: The SCANOSS API request timed out ({e.__class__.__name__}) for {self.url}'
|
|
174
|
+
) from e
|
|
168
175
|
else:
|
|
169
176
|
self.print_stderr(f'Warning: {e.__class__.__name__} communicating with {self.url}. Retrying...')
|
|
170
177
|
time.sleep(5)
|
|
171
178
|
except Exception as e:
|
|
172
|
-
self.print_stderr(
|
|
173
|
-
|
|
174
|
-
|
|
179
|
+
self.print_stderr(
|
|
180
|
+
f'ERROR: Exception ({e.__class__.__name__}) POSTing data ({request_id}) - {e}: {scan_files}'
|
|
181
|
+
)
|
|
182
|
+
raise Exception(f'ERROR: The SCANOSS API request failed for {self.url}') from e
|
|
175
183
|
else:
|
|
176
184
|
if r is None:
|
|
177
185
|
if retry > self.retry_limit: # No response retry_limit or more times, fail
|
|
178
186
|
self.save_bad_req_wfp(scan_files, request_id, scan_id)
|
|
179
|
-
raise Exception(
|
|
180
|
-
|
|
187
|
+
raise Exception(
|
|
188
|
+
f'ERROR: The SCANOSS API request ({request_id}) response object is empty for {self.url}'
|
|
189
|
+
)
|
|
181
190
|
else:
|
|
182
191
|
self.print_stderr(f'Warning: No response received from {self.url}. Retrying...')
|
|
183
192
|
time.sleep(5)
|
|
184
|
-
elif r.status_code ==
|
|
185
|
-
self.print_stderr(
|
|
186
|
-
|
|
193
|
+
elif r.status_code == requests.codes.service_unavailable: # Service limits most likely reached
|
|
194
|
+
self.print_stderr(
|
|
195
|
+
f'ERROR: SCANOSS API rejected the scan request ({request_id}) due to '
|
|
196
|
+
f'service limits being exceeded'
|
|
197
|
+
)
|
|
187
198
|
self.print_stderr(f'ERROR: Details: {r.text.strip()}')
|
|
188
|
-
raise Exception(
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
raise Exception(
|
|
200
|
+
f'ERROR: {r.status_code} - The SCANOSS API request ({request_id}) rejected '
|
|
201
|
+
f'for {self.url} due to service limits being exceeded.'
|
|
202
|
+
)
|
|
203
|
+
elif r.status_code >= requests.codes.bad_request:
|
|
191
204
|
if retry > self.retry_limit: # No response retry_limit or more times, fail
|
|
192
205
|
self.save_bad_req_wfp(scan_files, request_id, scan_id)
|
|
193
206
|
raise Exception(
|
|
194
|
-
f
|
|
195
|
-
f
|
|
207
|
+
f'ERROR: The SCANOSS API returned the following error: HTTP {r.status_code}, '
|
|
208
|
+
f'{r.text.strip()}'
|
|
209
|
+
)
|
|
196
210
|
else:
|
|
197
211
|
self.save_bad_req_wfp(scan_files, request_id, scan_id)
|
|
198
|
-
self.print_stderr(
|
|
199
|
-
|
|
212
|
+
self.print_stderr(
|
|
213
|
+
f'Warning: Error response code {r.status_code} ({r.text.strip()}) from '
|
|
214
|
+
f'{self.url}. Retrying...'
|
|
215
|
+
)
|
|
200
216
|
time.sleep(5)
|
|
201
217
|
else:
|
|
202
218
|
break # Valid response, break out of the retry loop
|
|
203
219
|
# End of while loop
|
|
204
220
|
if r is None:
|
|
205
221
|
self.save_bad_req_wfp(scan_files, request_id, scan_id)
|
|
206
|
-
raise Exception(f
|
|
222
|
+
raise Exception(f'ERROR: The SCANOSS API request response object is empty for {self.url}')
|
|
207
223
|
try:
|
|
208
224
|
if 'xml' in self.scan_format: # TODO remove XML parsing option?
|
|
209
225
|
return r.text
|
|
210
226
|
json_resp = r.json()
|
|
211
227
|
return json_resp
|
|
212
228
|
except (JSONDecodeError, Exception) as e:
|
|
213
|
-
self.print_stderr(
|
|
214
|
-
|
|
229
|
+
self.print_stderr(
|
|
230
|
+
f'ERROR: The SCANOSS API returned an invalid JSON ({e.__class__.__name__} - {request_id}): {e}'
|
|
231
|
+
)
|
|
215
232
|
bad_json_file = f'bad_json-{scan_id}-{request_id}.txt' if scan_id else f'bad_json-{request_id}.txt'
|
|
216
233
|
self.print_stderr(f'Ignoring result. Please look in "{bad_json_file}" for more details.')
|
|
217
234
|
try:
|
|
218
235
|
with open(bad_json_file, 'w') as f:
|
|
219
|
-
f.write(f
|
|
220
|
-
f.write(f
|
|
236
|
+
f.write(f'---Request ID Begin---\n{request_id}\n---Request ID End---\n')
|
|
237
|
+
f.write(f'---WFP Begin---\n{scan_files}\n---WFP End---\n---Bad JSON Begin---\n')
|
|
221
238
|
f.write(r.text)
|
|
222
|
-
f.write(
|
|
239
|
+
f.write('---Bad JSON End---\n')
|
|
223
240
|
except Exception as ee:
|
|
224
|
-
self.print_stderr(
|
|
225
|
-
|
|
241
|
+
self.print_stderr(
|
|
242
|
+
f'Warning: Issue writing bad json file - {bad_json_file} ({ee.__class__.__name__}): {ee}'
|
|
243
|
+
)
|
|
226
244
|
return None
|
|
227
245
|
|
|
228
246
|
def save_bad_req_wfp(self, scan_files, request_id, scan_id):
|
|
@@ -234,14 +252,35 @@ class ScanossApi(ScanossBase):
|
|
|
234
252
|
"""
|
|
235
253
|
bad_req_file = f'bad_request-{scan_id}-{request_id}.txt' if scan_id else f'bad_request-{request_id}.txt'
|
|
236
254
|
try:
|
|
237
|
-
self.print_stderr(
|
|
238
|
-
|
|
255
|
+
self.print_stderr(
|
|
256
|
+
f'No response object returned from API. Please look in "{bad_req_file}" for the offending WFP.'
|
|
257
|
+
)
|
|
239
258
|
with open(bad_req_file, 'w') as f:
|
|
240
|
-
f.write(f
|
|
241
|
-
f.write(f
|
|
259
|
+
f.write(f'---Request ID Begin---\n{request_id}\n---Request ID End---\n')
|
|
260
|
+
f.write(f'---WFP Begin---\n{scan_files}\n---WFP End---\n')
|
|
242
261
|
except Exception as ee:
|
|
243
|
-
self.print_stderr(
|
|
244
|
-
|
|
262
|
+
self.print_stderr(
|
|
263
|
+
f'Warning: Issue writing bad request file - {bad_req_file} ({ee.__class__.__name__}): {ee}'
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def set_sbom(self, sbom):
|
|
267
|
+
self.sbom = sbom
|
|
268
|
+
return self
|
|
269
|
+
|
|
270
|
+
def load_generic_headers(self, url):
|
|
271
|
+
"""
|
|
272
|
+
Adds custom headers from req_headers to the headers collection.
|
|
273
|
+
|
|
274
|
+
If x-api-key is present and no URL is configured (directly or via
|
|
275
|
+
environment), sets URL to the premium endpoint (DEFAULT_URL2).
|
|
276
|
+
"""
|
|
277
|
+
if self.req_headers: # Load generic headers
|
|
278
|
+
for key, value in self.req_headers.items():
|
|
279
|
+
if key == 'x-api-key': # Set premium URL if x-api-key header is set
|
|
280
|
+
if not url and not os.environ.get('SCANOSS_SCAN_URL'):
|
|
281
|
+
self.url = DEFAULT_URL2 # API key specific and no alternative URL, so use the default premium
|
|
282
|
+
self.api_key = value
|
|
283
|
+
self.headers[key] = value
|
|
245
284
|
|
|
246
285
|
#
|
|
247
286
|
# End of ScanossApi Class
|
scanoss/scanossbase.py
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2021, 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
23
|
"""
|
|
24
24
|
|
|
25
25
|
import sys
|
|
@@ -50,7 +50,7 @@ class ScanossBase:
|
|
|
50
50
|
|
|
51
51
|
def print_msg(self, *args, **kwargs):
|
|
52
52
|
"""
|
|
53
|
-
Print message if
|
|
53
|
+
Print message if quiet mode is not enabled
|
|
54
54
|
"""
|
|
55
55
|
if not self.quiet:
|
|
56
56
|
self.print_stderr(*args, **kwargs)
|
|
@@ -68,3 +68,40 @@ class ScanossBase:
|
|
|
68
68
|
"""
|
|
69
69
|
if self.trace:
|
|
70
70
|
self.print_stderr(*args, **kwargs)
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def print_stdout(*args, **kwargs):
|
|
74
|
+
"""
|
|
75
|
+
Print message to STDOUT
|
|
76
|
+
"""
|
|
77
|
+
print(
|
|
78
|
+
*args,
|
|
79
|
+
file=sys.stdout,
|
|
80
|
+
**kwargs,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def print_to_file_or_stdout(self, content: str, file: str = None):
|
|
84
|
+
"""
|
|
85
|
+
Print message to file if provided or stdout
|
|
86
|
+
"""
|
|
87
|
+
if not content:
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
if file:
|
|
91
|
+
with open(file, 'w') as f:
|
|
92
|
+
f.write(content)
|
|
93
|
+
else:
|
|
94
|
+
self.print_stdout(content)
|
|
95
|
+
|
|
96
|
+
def print_to_file_or_stderr(self, msg: str, file: str = None):
|
|
97
|
+
"""
|
|
98
|
+
Print message to file if provided or stderr
|
|
99
|
+
"""
|
|
100
|
+
if not msg:
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
if file:
|
|
104
|
+
with open(file, 'w') as f:
|
|
105
|
+
f.write(msg)
|
|
106
|
+
else:
|
|
107
|
+
self.print_stderr(msg)
|