fosslight-binary 5.1.30__tar.gz → 5.1.31__tar.gz
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.
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/PKG-INFO +3 -2
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/pyproject.toml +3 -2
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/_binary_dao.py +32 -2
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/_help.py +2 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/_jar_analysis.py +82 -34
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/PKG-INFO +3 -2
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/SOURCES.txt +2 -1
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/requires.txt +2 -1
- fosslight_binary-5.1.31/tests/test_kb_ssl.py +54 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/LICENSE +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/LICENSES/Apache-2.0.txt +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/LICENSES/LicenseRef-3rd-party-licenses.txt +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/MANIFEST.in +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/README.md +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/setup.cfg +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/__init__.py +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/_binary.py +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/_simple_mode.py +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/binary_analysis.py +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary/cli.py +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/dependency_links.txt +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/entry_points.txt +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/top_level.txt +0 -0
- {fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/tests/test_fosslight_binary.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fosslight_binary
|
|
3
|
-
Version: 5.1.
|
|
3
|
+
Version: 5.1.31
|
|
4
4
|
Summary: FOSSLight Binary Scanner
|
|
5
5
|
Author: LG Electronics
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,7 +29,8 @@ Requires-Dist: py-tlsh
|
|
|
29
29
|
Requires-Dist: pytz
|
|
30
30
|
Requires-Dist: XlsxWriter
|
|
31
31
|
Requires-Dist: PyYAML
|
|
32
|
-
Requires-Dist: fosslight_util>=2.2.
|
|
32
|
+
Requires-Dist: fosslight_util>=2.2.8
|
|
33
|
+
Requires-Dist: truststore
|
|
33
34
|
Requires-Dist: python-magic-bin; sys_platform == "win32"
|
|
34
35
|
Requires-Dist: python-magic; "darwin" in sys_platform
|
|
35
36
|
Requires-Dist: python-magic; "linux" in sys_platform
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "fosslight_binary"
|
|
10
|
-
version = "5.1.
|
|
10
|
+
version = "5.1.31"
|
|
11
11
|
description = "FOSSLight Binary Scanner"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
license = "Apache-2.0"
|
|
@@ -36,7 +36,8 @@ dependencies = [
|
|
|
36
36
|
"pytz",
|
|
37
37
|
"XlsxWriter",
|
|
38
38
|
"PyYAML",
|
|
39
|
-
"fosslight_util>=2.2.
|
|
39
|
+
"fosslight_util>=2.2.8",
|
|
40
|
+
"truststore",
|
|
40
41
|
"python-magic-bin; sys_platform == 'win32'",
|
|
41
42
|
"python-magic; 'darwin' in sys_platform",
|
|
42
43
|
"python-magic; 'linux' in sys_platform",
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import json
|
|
8
8
|
import logging
|
|
9
9
|
import os
|
|
10
|
+
import ssl
|
|
10
11
|
import urllib.error
|
|
11
12
|
import urllib.request
|
|
12
13
|
from typing import Dict, List, Optional, Tuple
|
|
@@ -43,6 +44,31 @@ def _get_chunk_size() -> int:
|
|
|
43
44
|
_CHUNK_SIZE = _get_chunk_size()
|
|
44
45
|
|
|
45
46
|
MatchKey = Tuple[str, str]
|
|
47
|
+
_KB_SSL_VERIFY_FALSE = {"0", "false", "no", "off"}
|
|
48
|
+
_logged_insecure_kb_ssl = False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def kb_ssl_verify_enabled() -> bool:
|
|
52
|
+
raw = os.environ.get("KB_SSL_VERIFY", "true")
|
|
53
|
+
return raw.strip().lower() not in _KB_SSL_VERIFY_FALSE
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def create_kb_ssl_context() -> ssl.SSLContext:
|
|
57
|
+
"""TLS context for KB HTTPS. Uses the OS trust store (Windows store, like the browser)."""
|
|
58
|
+
global _logged_insecure_kb_ssl
|
|
59
|
+
if not kb_ssl_verify_enabled():
|
|
60
|
+
if not _logged_insecure_kb_ssl:
|
|
61
|
+
logger.warning("KB TLS certificate verification is disabled (KB_SSL_VERIFY)")
|
|
62
|
+
_logged_insecure_kb_ssl = True
|
|
63
|
+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
64
|
+
ctx.check_hostname = False
|
|
65
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
66
|
+
return ctx
|
|
67
|
+
try:
|
|
68
|
+
import truststore
|
|
69
|
+
return truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
70
|
+
except ImportError:
|
|
71
|
+
return ssl.create_default_context()
|
|
46
72
|
|
|
47
73
|
|
|
48
74
|
def resolve_kb_config(kb_url: str = "", kb_token: str = "") -> Tuple[str, str]:
|
|
@@ -78,7 +104,9 @@ def check_binary_match_endpoint(kb_url: str, kb_token: str = "") -> Tuple[bool,
|
|
|
78
104
|
request.add_header("Authorization", f"Bearer {kb_token}")
|
|
79
105
|
|
|
80
106
|
try:
|
|
81
|
-
with urllib.request.urlopen(
|
|
107
|
+
with urllib.request.urlopen(
|
|
108
|
+
request, timeout=_PROBE_TIMEOUT_SEC, context=create_kb_ssl_context()
|
|
109
|
+
) as response:
|
|
82
110
|
response.read()
|
|
83
111
|
return True, ""
|
|
84
112
|
except urllib.error.HTTPError as ex:
|
|
@@ -257,7 +285,9 @@ def _post_binary_match(kb_url: str, kb_token: str, items: list) -> Optional[dict
|
|
|
257
285
|
request.add_header("Authorization", f"Bearer {kb_token}")
|
|
258
286
|
|
|
259
287
|
try:
|
|
260
|
-
with urllib.request.urlopen(
|
|
288
|
+
with urllib.request.urlopen(
|
|
289
|
+
request, timeout=_HTTP_TIMEOUT_SEC, context=create_kb_ssl_context()
|
|
290
|
+
) as response:
|
|
261
291
|
body = response.read().decode()
|
|
262
292
|
return json.loads(body) if body else {}
|
|
263
293
|
except urllib.error.HTTPError as ex:
|
|
@@ -34,6 +34,8 @@ _HELP_MESSAGE_BINARY = f"""
|
|
|
34
34
|
────────────────────────────────────────────────────────────────────
|
|
35
35
|
--kb_url <url> KB API URL (priority: parameter > KB_URL env > default)
|
|
36
36
|
--kb_token <token> KB bearer token (priority: parameter > KB_TOKEN env)
|
|
37
|
+
HTTPS uses the OS certificate store. Set KB_SSL_VERIFY=false
|
|
38
|
+
only if certificate verification must be skipped.
|
|
37
39
|
--notice Print the open source license notice text
|
|
38
40
|
--no_correction Skip OSS information correction with sbom-info.yaml
|
|
39
41
|
--correct_fpath <path> Path to custom sbom-info.yaml file
|
|
@@ -7,21 +7,25 @@
|
|
|
7
7
|
import hashlib
|
|
8
8
|
import logging
|
|
9
9
|
import os
|
|
10
|
+
import re
|
|
10
11
|
import tempfile
|
|
11
12
|
import zipfile
|
|
12
13
|
import defusedxml.ElementTree as ET
|
|
13
14
|
import requests
|
|
14
15
|
import fosslight_util.constant as constant
|
|
16
|
+
from fosslight_util._get_downloadable_url import _maven_repo_bases_for
|
|
15
17
|
from fosslight_util.get_pom_license import get_license_from_pom
|
|
16
18
|
from fosslight_util.oss_item import OssItem
|
|
17
19
|
|
|
18
20
|
logger = logging.getLogger(constant.LOGGER_NAME)
|
|
19
21
|
|
|
20
22
|
_CENTRAL_SEARCH_URL = "https://search.maven.org/solrsearch/select"
|
|
21
|
-
_REQUEST_TIMEOUT = 10 # seconds
|
|
22
|
-
_CENTRAL_SEARCH_TIMEOUT = 2.5 # seconds
|
|
23
|
+
_REQUEST_TIMEOUT = 10 # seconds - used for HEAD / POM download
|
|
24
|
+
_CENTRAL_SEARCH_TIMEOUT = 2.5 # seconds - tight timeout for Search API (retried on timeout)
|
|
25
|
+
_MAVEN_JAR_HTTP_TIMEOUT = (2, 2) # match Util probe timeouts for multi-repo jar checks
|
|
23
26
|
_MAX_RETRY = 3 # maximum Central API retry attempts per JAR
|
|
24
27
|
_central_network_warned = False # Flag to suppress repeated network-unavailable warnings within one run
|
|
28
|
+
_COORD_TOKEN = re.compile(r'[A-Za-z0-9._+-]+') # shape of a Maven groupId / artifactId / version
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
def _sha1_of_file(filepath):
|
|
@@ -123,13 +127,21 @@ def _search_central_by_sha1(sha1, timeout=None):
|
|
|
123
127
|
if not docs:
|
|
124
128
|
return {}, False
|
|
125
129
|
doc = docs[0]
|
|
130
|
+
groupId = doc.get("g", "")
|
|
131
|
+
artifactId = doc.get("a", "")
|
|
132
|
+
version = doc.get("v") or doc.get("latestVersion", "")
|
|
133
|
+
|
|
134
|
+
if not (groupId and artifactId and version):
|
|
135
|
+
logger.debug(f"Maven Central returned an incomplete document for {sha1}: {doc}")
|
|
136
|
+
return {}, False
|
|
137
|
+
|
|
126
138
|
return {
|
|
127
|
-
"groupId":
|
|
128
|
-
"artifactId":
|
|
129
|
-
"version":
|
|
139
|
+
"groupId": groupId,
|
|
140
|
+
"artifactId": artifactId,
|
|
141
|
+
"version": version,
|
|
130
142
|
}, False
|
|
131
143
|
except requests.exceptions.Timeout:
|
|
132
|
-
logger.debug(f"Maven Central SHA-1 search timed out ({sha1})
|
|
144
|
+
logger.debug(f"Maven Central SHA-1 search timed out ({sha1}) - will retry")
|
|
133
145
|
return {}, True
|
|
134
146
|
except Exception as ex:
|
|
135
147
|
if _is_network_error(ex):
|
|
@@ -157,7 +169,7 @@ def _download_pom_to_tempfile(group_id, artifact_id, version, timeout=None):
|
|
|
157
169
|
logger.debug(f"POM downloaded to {tmp.name} from {url}")
|
|
158
170
|
return tmp.name, False
|
|
159
171
|
except requests.exceptions.Timeout:
|
|
160
|
-
logger.debug(f"POM download timed out from {url}
|
|
172
|
+
logger.debug(f"POM download timed out from {url} - will retry")
|
|
161
173
|
any_timeout = True
|
|
162
174
|
except Exception as ex:
|
|
163
175
|
if _is_network_error(ex):
|
|
@@ -167,40 +179,69 @@ def _download_pom_to_tempfile(group_id, artifact_id, version, timeout=None):
|
|
|
167
179
|
return None, any_timeout
|
|
168
180
|
|
|
169
181
|
|
|
170
|
-
def
|
|
171
|
-
if
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
def _is_maven_coordinate(*parts):
|
|
183
|
+
"""True only if every part could be a Maven coordinate token.
|
|
184
|
+
|
|
185
|
+
MANIFEST.MF vendor fields are display names ("The Apache Software
|
|
186
|
+
Foundation", "Google, Inc.", "%bundleVendor"), not groupIds. Rejecting them
|
|
187
|
+
keeps bogus URLs out of the report and avoids HEAD requests that can only 404.
|
|
188
|
+
"""
|
|
189
|
+
return all(p and _COORD_TOKEN.fullmatch(p) for p in parts)
|
|
175
190
|
|
|
176
191
|
|
|
177
|
-
def
|
|
178
|
-
if
|
|
179
|
-
|
|
180
|
-
url = _build_central_jar_url(group_id, artifact_id, version)
|
|
192
|
+
def _maven_jar_url_exists(url, timeout=None):
|
|
193
|
+
"""True if a Maven host serves this jar URL (HEAD, with GET fallback)."""
|
|
194
|
+
_timeout = timeout if timeout is not None else _MAVEN_JAR_HTTP_TIMEOUT
|
|
181
195
|
try:
|
|
182
|
-
resp = requests.head(url, timeout=
|
|
183
|
-
|
|
196
|
+
resp = requests.head(url, timeout=_timeout, allow_redirects=True)
|
|
197
|
+
if resp.status_code == 200:
|
|
198
|
+
return True
|
|
199
|
+
# Some Maven hosts reject HEAD; fall back to a streamed GET (Util pattern).
|
|
200
|
+
if resp.status_code in (403, 405, 501):
|
|
201
|
+
resp = requests.get(url, stream=True, allow_redirects=True, timeout=_timeout)
|
|
202
|
+
try:
|
|
203
|
+
return resp.status_code == 200
|
|
204
|
+
finally:
|
|
205
|
+
resp.close()
|
|
184
206
|
except Exception as ex:
|
|
185
207
|
if _is_network_error(ex):
|
|
186
|
-
_warn_network_once(f"existence check: {
|
|
208
|
+
_warn_network_once(f"jar existence check: {url}")
|
|
187
209
|
else:
|
|
188
|
-
logger.debug(f"
|
|
189
|
-
|
|
210
|
+
logger.debug(f"Maven jar existence check failed ({url}): {ex}")
|
|
211
|
+
return False
|
|
212
|
+
|
|
190
213
|
|
|
214
|
+
def _find_jar_download_url(group_id, artifact_id, version):
|
|
215
|
+
"""Return the first known-repo URL that hosts ``{artifact}-{version}.jar``.
|
|
216
|
+
Uses FOSSLight Util's repository order (group hints + MAVEN_REPOSITORY_BASES)
|
|
217
|
+
so non-Central artifacts (Google, Confluent, Spring, …) can still fill
|
|
218
|
+
Download Location.
|
|
219
|
+
"""
|
|
220
|
+
if not _is_maven_coordinate(group_id, artifact_id, version):
|
|
221
|
+
return ""
|
|
222
|
+
group_path = group_id.replace('.', '/')
|
|
223
|
+
jar_name = f"{artifact_id}-{version}.jar"
|
|
224
|
+
for repo_base in _maven_repo_bases_for(group_path):
|
|
225
|
+
url = f"{repo_base}/{group_path}/{artifact_id}/{version}/{jar_name}"
|
|
226
|
+
if _maven_jar_url_exists(url):
|
|
227
|
+
logger.debug(f"Maven jar found: {url}")
|
|
228
|
+
return url
|
|
229
|
+
return ""
|
|
191
230
|
|
|
192
|
-
|
|
231
|
+
|
|
232
|
+
def _process_one_jar(jar_path, rel_path, sha1, search_timeout=None, skip_central_search=False):
|
|
193
233
|
groupId = artifactId = version = project_url = license_str = ''
|
|
194
234
|
confirmed_in_central = False
|
|
235
|
+
trusted_coordinates = False
|
|
195
236
|
source = ''
|
|
196
237
|
|
|
197
|
-
if
|
|
238
|
+
if skip_central_search:
|
|
198
239
|
central_info = {}
|
|
199
240
|
timed_out = False
|
|
200
241
|
else:
|
|
201
242
|
central_info, timed_out = _search_central_by_sha1(sha1, timeout=search_timeout)
|
|
202
243
|
if timed_out:
|
|
203
|
-
logger.debug(f"{rel_path}: Central SHA-1 search timed out
|
|
244
|
+
logger.debug(f"{rel_path}: Central SHA-1 search timed out - will retry")
|
|
204
245
|
return None, True
|
|
205
246
|
|
|
206
247
|
g2, a2, v2, url2, pom_tmp_path = _read_pom_from_jar(jar_path)
|
|
@@ -215,10 +256,11 @@ def _process_one_jar(jar_path, rel_path, sha1, search_timeout=None, skip_central
|
|
|
215
256
|
names_match = (central_oss_name == jar_oss_name and c_version == v2)
|
|
216
257
|
|
|
217
258
|
if names_match:
|
|
218
|
-
logger.debug(f"{rel_path}: Central and JAR pom.xml match ({central_oss_name} {c_version})
|
|
259
|
+
logger.debug(f"{rel_path}: Central and JAR pom.xml match ({central_oss_name} {c_version}) - using JAR pom.xml for license")
|
|
219
260
|
groupId, artifactId, version, project_url = g2, a2, v2, url2
|
|
220
261
|
source = 'pom.xml'
|
|
221
262
|
confirmed_in_central = True
|
|
263
|
+
trusted_coordinates = True
|
|
222
264
|
|
|
223
265
|
if pom_tmp_path:
|
|
224
266
|
try:
|
|
@@ -239,11 +281,12 @@ def _process_one_jar(jar_path, rel_path, sha1, search_timeout=None, skip_central
|
|
|
239
281
|
groupId, artifactId, version = c_groupId, c_artifactId, c_version
|
|
240
282
|
source = 'Maven Central'
|
|
241
283
|
confirmed_in_central = True
|
|
284
|
+
trusted_coordinates = True
|
|
242
285
|
|
|
243
286
|
tmp_path, timed_out = _download_pom_to_tempfile(
|
|
244
287
|
groupId, artifactId, version, timeout=search_timeout)
|
|
245
288
|
if timed_out:
|
|
246
|
-
logger.debug(f"{rel_path}: POM download timed out
|
|
289
|
+
logger.debug(f"{rel_path}: POM download timed out - will retry")
|
|
247
290
|
if pom_tmp_path:
|
|
248
291
|
try:
|
|
249
292
|
os.remove(pom_tmp_path)
|
|
@@ -271,11 +314,12 @@ def _process_one_jar(jar_path, rel_path, sha1, search_timeout=None, skip_central
|
|
|
271
314
|
pass
|
|
272
315
|
|
|
273
316
|
else:
|
|
274
|
-
logger.debug(f"{rel_path}: not found in Maven Central
|
|
317
|
+
logger.debug(f"{rel_path}: not found in Maven Central - falling back to JAR internals")
|
|
275
318
|
|
|
276
319
|
if g2 or a2:
|
|
277
320
|
groupId, artifactId, version, project_url = g2, a2, v2, url2
|
|
278
321
|
source = 'pom.xml'
|
|
322
|
+
trusted_coordinates = True
|
|
279
323
|
|
|
280
324
|
if pom_tmp_path:
|
|
281
325
|
try:
|
|
@@ -291,8 +335,6 @@ def _process_one_jar(jar_path, rel_path, sha1, search_timeout=None, skip_central
|
|
|
291
335
|
os.remove(pom_tmp_path)
|
|
292
336
|
except Exception:
|
|
293
337
|
pass
|
|
294
|
-
if not confirmed_in_central and not skip_central:
|
|
295
|
-
confirmed_in_central = _exists_in_central(groupId, artifactId, version)
|
|
296
338
|
|
|
297
339
|
if not (groupId and artifactId):
|
|
298
340
|
g3, a3, v3, url3 = _read_manifest_from_jar(jar_path)
|
|
@@ -300,14 +342,20 @@ def _process_one_jar(jar_path, rel_path, sha1, search_timeout=None, skip_central
|
|
|
300
342
|
groupId = g3
|
|
301
343
|
artifactId = a3
|
|
302
344
|
version = version or v3
|
|
345
|
+
confirmed_in_central = False
|
|
303
346
|
project_url = project_url or url3
|
|
304
347
|
source = 'MANIFEST.MF'
|
|
348
|
+
trusted_coordinates = False
|
|
305
349
|
|
|
306
350
|
if not (groupId or artifactId):
|
|
307
351
|
return None, False
|
|
308
352
|
|
|
353
|
+
if confirmed_in_central or trusted_coordinates:
|
|
354
|
+
dl_url = _find_jar_download_url(groupId, artifactId, version)
|
|
355
|
+
else:
|
|
356
|
+
dl_url = ""
|
|
357
|
+
|
|
309
358
|
oss_name = f"{groupId}:{artifactId}" if groupId and artifactId else (artifactId or groupId)
|
|
310
|
-
dl_url = _build_central_jar_url(groupId, artifactId, version) if confirmed_in_central else ""
|
|
311
359
|
|
|
312
360
|
oss = OssItem(oss_name, version, license_str, dl_url)
|
|
313
361
|
oss.comment = source
|
|
@@ -345,7 +393,7 @@ def analyze_jar_file(path_to_find_bin, path_to_exclude):
|
|
|
345
393
|
jar_files.append(os.path.join(root_dir, fname))
|
|
346
394
|
|
|
347
395
|
if not jar_files:
|
|
348
|
-
logger.info("No .jar files found
|
|
396
|
+
logger.info("No .jar files found - skipping JAR OSS analysis.")
|
|
349
397
|
return jar_items, success
|
|
350
398
|
|
|
351
399
|
for jar_path in jar_files:
|
|
@@ -361,7 +409,7 @@ def analyze_jar_file(path_to_find_bin, path_to_exclude):
|
|
|
361
409
|
jar_path, rel_path, sha1, search_timeout=_CENTRAL_SEARCH_TIMEOUT)
|
|
362
410
|
|
|
363
411
|
if needs_retry:
|
|
364
|
-
logger.debug(f"{rel_path}: Central API timed out
|
|
412
|
+
logger.debug(f"{rel_path}: Central API timed out - queued for retry (attempt 1/{_MAX_RETRY})")
|
|
365
413
|
pending_sha1s.add(sha1)
|
|
366
414
|
retry_queue.append((jar_path, rel_path, sha1, 1))
|
|
367
415
|
elif result is not None:
|
|
@@ -373,8 +421,8 @@ def analyze_jar_file(path_to_find_bin, path_to_exclude):
|
|
|
373
421
|
if attempt >= _MAX_RETRY:
|
|
374
422
|
logger.warning(
|
|
375
423
|
f"{rel_path}: Maven Central API timed out after {_MAX_RETRY} attempts"
|
|
376
|
-
"
|
|
377
|
-
result, _ = _process_one_jar(jar_path, rel_path, sha1,
|
|
424
|
+
" - falling back to JAR internals")
|
|
425
|
+
result, _ = _process_one_jar(jar_path, rel_path, sha1, skip_central_search=True)
|
|
378
426
|
if result is not None:
|
|
379
427
|
_store_jar_result(jar_items, sha1, result)
|
|
380
428
|
continue
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fosslight_binary
|
|
3
|
-
Version: 5.1.
|
|
3
|
+
Version: 5.1.31
|
|
4
4
|
Summary: FOSSLight Binary Scanner
|
|
5
5
|
Author: LG Electronics
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,7 +29,8 @@ Requires-Dist: py-tlsh
|
|
|
29
29
|
Requires-Dist: pytz
|
|
30
30
|
Requires-Dist: XlsxWriter
|
|
31
31
|
Requires-Dist: PyYAML
|
|
32
|
-
Requires-Dist: fosslight_util>=2.2.
|
|
32
|
+
Requires-Dist: fosslight_util>=2.2.8
|
|
33
|
+
Requires-Dist: truststore
|
|
33
34
|
Requires-Dist: python-magic-bin; sys_platform == "win32"
|
|
34
35
|
Requires-Dist: python-magic; "darwin" in sys_platform
|
|
35
36
|
Requires-Dist: python-magic; "linux" in sys_platform
|
{fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/SOURCES.txt
RENAMED
|
@@ -19,4 +19,5 @@ src/fosslight_binary.egg-info/dependency_links.txt
|
|
|
19
19
|
src/fosslight_binary.egg-info/entry_points.txt
|
|
20
20
|
src/fosslight_binary.egg-info/requires.txt
|
|
21
21
|
src/fosslight_binary.egg-info/top_level.txt
|
|
22
|
-
tests/test_fosslight_binary.py
|
|
22
|
+
tests/test_fosslight_binary.py
|
|
23
|
+
tests/test_kb_ssl.py
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright (c) 2026 LG Electronics Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Tests for KB HTTPS SSL context selection."""
|
|
4
|
+
|
|
5
|
+
import ssl
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
from fosslight_binary._binary_dao import create_kb_ssl_context, kb_ssl_verify_enabled
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_kb_ssl_verify_enabled_default(monkeypatch):
|
|
12
|
+
monkeypatch.delenv("KB_SSL_VERIFY", raising=False)
|
|
13
|
+
assert kb_ssl_verify_enabled() is True
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_kb_ssl_verify_disabled_values(monkeypatch):
|
|
17
|
+
for value in ("false", "0", "no", "OFF"):
|
|
18
|
+
monkeypatch.setenv("KB_SSL_VERIFY", value)
|
|
19
|
+
assert kb_ssl_verify_enabled() is False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_create_kb_ssl_context_insecure(monkeypatch):
|
|
23
|
+
monkeypatch.setenv("KB_SSL_VERIFY", "false")
|
|
24
|
+
ctx = create_kb_ssl_context()
|
|
25
|
+
assert ctx.verify_mode == ssl.CERT_NONE
|
|
26
|
+
assert ctx.check_hostname is False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_create_kb_ssl_context_uses_truststore_when_verify_on(monkeypatch):
|
|
30
|
+
monkeypatch.setenv("KB_SSL_VERIFY", "true")
|
|
31
|
+
ctx = create_kb_ssl_context()
|
|
32
|
+
assert ctx.verify_mode != ssl.CERT_NONE
|
|
33
|
+
assert ctx.check_hostname is True
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_probe_passes_ssl_context():
|
|
37
|
+
from fosslight_binary._binary_dao import check_binary_match_endpoint
|
|
38
|
+
|
|
39
|
+
class _Resp:
|
|
40
|
+
def read(self):
|
|
41
|
+
return b"{}"
|
|
42
|
+
|
|
43
|
+
def __enter__(self):
|
|
44
|
+
return self
|
|
45
|
+
|
|
46
|
+
def __exit__(self, *args):
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
with patch("fosslight_binary._binary_dao.urllib.request.urlopen", return_value=_Resp()) as urlopen:
|
|
50
|
+
available, comment = check_binary_match_endpoint("https://kb.example/", "")
|
|
51
|
+
assert available is True
|
|
52
|
+
assert comment == ""
|
|
53
|
+
assert urlopen.call_args.kwargs["context"] is not None
|
|
54
|
+
assert isinstance(urlopen.call_args.kwargs["context"], ssl.SSLContext)
|
|
File without changes
|
|
File without changes
|
{fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/LICENSES/LicenseRef-3rd-party-licenses.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{fosslight_binary-5.1.30 → fosslight_binary-5.1.31}/src/fosslight_binary.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|