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.
Files changed (109) hide show
  1. protoc_gen_swagger/__init__.py +13 -13
  2. protoc_gen_swagger/options/__init__.py +13 -13
  3. protoc_gen_swagger/options/annotations_pb2.py +18 -12
  4. protoc_gen_swagger/options/annotations_pb2.pyi +48 -0
  5. protoc_gen_swagger/options/annotations_pb2_grpc.py +20 -0
  6. protoc_gen_swagger/options/openapiv2_pb2.py +110 -99
  7. protoc_gen_swagger/options/openapiv2_pb2.pyi +1317 -0
  8. protoc_gen_swagger/options/openapiv2_pb2_grpc.py +20 -0
  9. scanoss/__init__.py +18 -18
  10. scanoss/api/__init__.py +17 -17
  11. scanoss/api/common/__init__.py +17 -17
  12. scanoss/api/common/v2/__init__.py +17 -17
  13. scanoss/api/common/v2/scanoss_common_pb2.py +49 -20
  14. scanoss/api/common/v2/scanoss_common_pb2_grpc.py +25 -0
  15. scanoss/api/components/__init__.py +17 -17
  16. scanoss/api/components/v2/__init__.py +17 -17
  17. scanoss/api/components/v2/scanoss_components_pb2.py +68 -43
  18. scanoss/api/components/v2/scanoss_components_pb2_grpc.py +83 -22
  19. scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +136 -21
  20. scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +766 -13
  21. scanoss/api/dependencies/__init__.py +17 -17
  22. scanoss/api/dependencies/v2/__init__.py +17 -17
  23. scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +56 -29
  24. scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +94 -8
  25. scanoss/api/geoprovenance/__init__.py +23 -0
  26. scanoss/api/geoprovenance/v2/__init__.py +23 -0
  27. scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +92 -0
  28. scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +381 -0
  29. scanoss/api/licenses/__init__.py +23 -0
  30. scanoss/api/licenses/v2/__init__.py +23 -0
  31. scanoss/api/licenses/v2/scanoss_licenses_pb2.py +84 -0
  32. scanoss/api/licenses/v2/scanoss_licenses_pb2_grpc.py +302 -0
  33. scanoss/api/scanning/__init__.py +17 -17
  34. scanoss/api/scanning/v2/__init__.py +17 -17
  35. scanoss/api/scanning/v2/scanoss_scanning_pb2.py +42 -13
  36. scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +86 -7
  37. scanoss/api/semgrep/__init__.py +17 -17
  38. scanoss/api/semgrep/v2/__init__.py +17 -17
  39. scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +50 -23
  40. scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +151 -16
  41. scanoss/api/vulnerabilities/__init__.py +17 -17
  42. scanoss/api/vulnerabilities/v2/__init__.py +17 -17
  43. scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +78 -31
  44. scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +282 -18
  45. scanoss/cli.py +2359 -370
  46. scanoss/components.py +187 -94
  47. scanoss/constants.py +22 -0
  48. scanoss/cryptography.py +308 -0
  49. scanoss/csvoutput.py +91 -58
  50. scanoss/cyclonedx.py +221 -63
  51. scanoss/data/build_date.txt +1 -1
  52. scanoss/data/osadl-copyleft.json +133 -0
  53. scanoss/data/scanoss-settings-schema.json +254 -0
  54. scanoss/delta.py +197 -0
  55. scanoss/export/__init__.py +23 -0
  56. scanoss/export/dependency_track.py +227 -0
  57. scanoss/file_filters.py +582 -0
  58. scanoss/filecount.py +75 -69
  59. scanoss/gitlabqualityreport.py +214 -0
  60. scanoss/header_filter.py +563 -0
  61. scanoss/inspection/__init__.py +23 -0
  62. scanoss/inspection/policy_check/__init__.py +0 -0
  63. scanoss/inspection/policy_check/dependency_track/__init__.py +0 -0
  64. scanoss/inspection/policy_check/dependency_track/project_violation.py +479 -0
  65. scanoss/inspection/policy_check/policy_check.py +222 -0
  66. scanoss/inspection/policy_check/scanoss/__init__.py +0 -0
  67. scanoss/inspection/policy_check/scanoss/copyleft.py +243 -0
  68. scanoss/inspection/policy_check/scanoss/undeclared_component.py +309 -0
  69. scanoss/inspection/summary/__init__.py +0 -0
  70. scanoss/inspection/summary/component_summary.py +170 -0
  71. scanoss/inspection/summary/license_summary.py +191 -0
  72. scanoss/inspection/summary/match_summary.py +341 -0
  73. scanoss/inspection/utils/file_utils.py +44 -0
  74. scanoss/inspection/utils/license_utils.py +123 -0
  75. scanoss/inspection/utils/markdown_utils.py +63 -0
  76. scanoss/inspection/utils/scan_result_processor.py +417 -0
  77. scanoss/osadl.py +125 -0
  78. scanoss/results.py +275 -0
  79. scanoss/scancodedeps.py +87 -38
  80. scanoss/scanner.py +431 -539
  81. scanoss/scanners/__init__.py +23 -0
  82. scanoss/scanners/container_scanner.py +476 -0
  83. scanoss/scanners/folder_hasher.py +358 -0
  84. scanoss/scanners/scanner_config.py +73 -0
  85. scanoss/scanners/scanner_hfh.py +252 -0
  86. scanoss/scanoss_settings.py +337 -0
  87. scanoss/scanossapi.py +140 -101
  88. scanoss/scanossbase.py +59 -22
  89. scanoss/scanossgrpc.py +799 -251
  90. scanoss/scanpostprocessor.py +294 -0
  91. scanoss/scantype.py +22 -21
  92. scanoss/services/dependency_track_service.py +132 -0
  93. scanoss/spdxlite.py +532 -174
  94. scanoss/threadeddependencies.py +148 -47
  95. scanoss/threadedscanning.py +53 -37
  96. scanoss/utils/__init__.py +23 -0
  97. scanoss/utils/abstract_presenter.py +103 -0
  98. scanoss/utils/crc64.py +96 -0
  99. scanoss/utils/file.py +84 -0
  100. scanoss/utils/scanoss_scan_results_utils.py +41 -0
  101. scanoss/utils/simhash.py +198 -0
  102. scanoss/winnowing.py +241 -63
  103. {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/METADATA +18 -9
  104. scanoss-1.43.1.dist-info/RECORD +110 -0
  105. {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/WHEEL +1 -1
  106. scanoss-1.12.2.dist-info/RECORD +0 -58
  107. {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/entry_points.txt +0 -0
  108. {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info/licenses}/LICENSE +0 -0
  109. {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
- 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.
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 = "https://api.osskb.org/scan/direct" # default free service URL
42
- DEFAULT_URL2 = "https://api.scanoss.com/scan/direct" # default premium service URL
43
- SCANOSS_SCAN_URL = os.environ.get("SCANOSS_SCAN_URL") if os.environ.get("SCANOSS_SCAN_URL") else DEFAULT_URL
44
- SCANOSS_API_KEY = os.environ.get("SCANOSS_API_KEY") if os.environ.get("SCANOSS_API_KEY") else ''
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__(self, scan_type: str = None, sbom_path: str = None, scan_format: str = None, flags: str = None,
54
- url: str = None, api_key: str = None, debug: bool = False, trace: bool = False, quiet: bool = False,
55
- timeout: int = 180, ver_details: str = None, ignore_cert_errors: bool = False,
56
- proxy: str = None, ca_cert: str = None, pac: PACFile = None, retry: int = 5):
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 quite mode (default False)
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.url = url if url else SCANOSS_SCAN_URL
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 > 5 else 180
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
- self.headers['User-Agent'] = f'scanoss-py/{__version__}'
94
- self.headers['user-agent'] = f'scanoss-py/{__version__}'
95
- self.sbom = None
96
- self.load_sbom() # Load an input SBOM if one is specified
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(f'Setting up PAC session...')
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(f'Ignoring cert errors...')
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. proxies:
131
+ if self.proxies:
116
132
  self.session.proxies = self.proxies
117
133
 
118
- def load_sbom(self):
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
- scan_files = {'file': ("%s.wfp" % request_id, wfp)}
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(self.url, files=scan_files, data=form_data, headers=self.headers,
158
- timeout=self.timeout
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"ERROR: The SCANOSS API request failed for {self.url}") from e
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(f"ERROR: The SCANOSS API request timed out ({e.__class__.__name__}) for"
167
- f" {self.url}") from e
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(f'ERROR: Exception ({e.__class__.__name__}) POSTing data ({request_id}) - {e}:'
173
- f' {scan_files}')
174
- raise Exception(f"ERROR: The SCANOSS API request failed for {self.url}") from e
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(f"ERROR: The SCANOSS API request ({request_id}) response object is empty "
180
- f"for {self.url}")
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 == 503: # Service limits have most likely been reached
185
- self.print_stderr(f'ERROR: SCANOSS API rejected the scan request ({request_id}) due to '
186
- f'service limits being exceeded')
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(f"ERROR: {r.status_code} - The SCANOSS API request ({request_id}) rejected "
189
- f"for {self.url} due to service limits being exceeded.")
190
- elif r.status_code >= 400:
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"ERROR: The SCANOSS API returned the following error: HTTP {r.status_code}, "
195
- f"{r.text.strip()}")
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(f'Warning: Error response code {r.status_code} ({r.text.strip()}) from '
199
- f'{self.url}. Retrying...')
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"ERROR: The SCANOSS API request response object is empty for {self.url}")
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(f'ERROR: The SCANOSS API returned an invalid JSON '
214
- f'({e.__class__.__name__} - {request_id}): {e}')
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"---Request ID Begin---\n{request_id}\n---Request ID End---\n")
220
- f.write(f"---WFP Begin---\n{scan_files}\n---WFP End---\n---Bad JSON Begin---\n")
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("---Bad JSON End---\n")
239
+ f.write('---Bad JSON End---\n')
223
240
  except Exception as ee:
224
- self.print_stderr(f'Warning: Issue writing bad json file - {bad_json_file} ({ee.__class__.__name__}):'
225
- f' {ee}')
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(f'No response object returned from API. Please look in "{bad_req_file}" for the '
238
- f'offending WFP.')
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"---Request ID Begin---\n{request_id}\n---Request ID End---\n")
241
- f.write(f"---WFP Begin---\n{scan_files}\n---WFP End---\n")
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(f'Warning: Issue writing bad request file - {bad_req_file} ({ee.__class__.__name__}):'
244
- f' {ee}')
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
- 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.
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 quite mode is not enabled
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)