fosslight-binary 5.1.31__tar.gz → 5.1.32__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.
Files changed (25) hide show
  1. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/PKG-INFO +2 -2
  2. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/pyproject.toml +2 -2
  3. fosslight_binary-5.1.32/src/fosslight_binary/_exclude.py +15 -0
  4. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/_jar_analysis.py +42 -17
  5. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/_simple_mode.py +11 -4
  6. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/binary_analysis.py +14 -9
  7. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary.egg-info/PKG-INFO +2 -2
  8. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary.egg-info/SOURCES.txt +1 -0
  9. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary.egg-info/requires.txt +1 -1
  10. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/LICENSE +0 -0
  11. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/LICENSES/Apache-2.0.txt +0 -0
  12. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/LICENSES/LicenseRef-3rd-party-licenses.txt +0 -0
  13. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/MANIFEST.in +0 -0
  14. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/README.md +0 -0
  15. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/setup.cfg +0 -0
  16. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/__init__.py +0 -0
  17. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/_binary.py +0 -0
  18. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/_binary_dao.py +0 -0
  19. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/_help.py +0 -0
  20. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary/cli.py +0 -0
  21. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary.egg-info/dependency_links.txt +0 -0
  22. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary.egg-info/entry_points.txt +0 -0
  23. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/src/fosslight_binary.egg-info/top_level.txt +0 -0
  24. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/tests/test_fosslight_binary.py +0 -0
  25. {fosslight_binary-5.1.31 → fosslight_binary-5.1.32}/tests/test_kb_ssl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fosslight_binary
3
- Version: 5.1.31
3
+ Version: 5.1.32
4
4
  Summary: FOSSLight Binary Scanner
5
5
  Author: LG Electronics
6
6
  License-Expression: Apache-2.0
@@ -29,7 +29,7 @@ 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.8
32
+ Requires-Dist: fosslight_util>=2.2.14
33
33
  Requires-Dist: truststore
34
34
  Requires-Dist: python-magic-bin; sys_platform == "win32"
35
35
  Requires-Dist: python-magic; "darwin" 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.31"
10
+ version = "5.1.32"
11
11
  description = "FOSSLight Binary Scanner"
12
12
  readme = "README.md"
13
13
  license = "Apache-2.0"
@@ -36,7 +36,7 @@ dependencies = [
36
36
  "pytz",
37
37
  "XlsxWriter",
38
38
  "PyYAML",
39
- "fosslight_util>=2.2.8",
39
+ "fosslight_util>=2.2.14",
40
40
  "truststore",
41
41
  "python-magic-bin; sys_platform == 'win32'",
42
42
  "python-magic; 'darwin' in sys_platform",
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2026 LG Electronics Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ """Binary-scanner filename excludes."""
5
+
6
+ from fosslight_util.exclude import is_excluded_filename
7
+
8
+ # Scanner output binaries that should not be re-analyzed.
9
+ EXCLUDE_FILENAME_BINARY = frozenset({
10
+ "fosslight_bin", "fosslight_bin.exe",
11
+ })
12
+
13
+
14
+ def is_excluded_binary_filename(file_path: str) -> bool:
15
+ return is_excluded_filename(file_path, EXCLUDE_FILENAME_BINARY)
@@ -19,9 +19,16 @@ from fosslight_util.oss_item import OssItem
19
19
 
20
20
  logger = logging.getLogger(constant.LOGGER_NAME)
21
21
 
22
- _CENTRAL_SEARCH_URL = "https://search.maven.org/solrsearch/select"
22
+ # Both hosts serve the same Central Solr index and the same g/a/v fields, but
23
+ # search.maven.org answers only about one query in six: the TCP connect always
24
+ # succeeds and then the response never starts, so no timeout budget rescues it.
25
+ # The Portal host answers every query in about half a second, so it goes first.
26
+ _CENTRAL_SEARCH_URLS = (
27
+ "https://central.sonatype.com/solrsearch/select",
28
+ "https://search.maven.org/solrsearch/select",
29
+ )
23
30
  _REQUEST_TIMEOUT = 10 # seconds - used for HEAD / POM download
24
- _CENTRAL_SEARCH_TIMEOUT = 2.5 # seconds - tight timeout for Search API (retried on timeout)
31
+ _CENTRAL_SEARCH_TIMEOUT = 2.5 # seconds - per-host budget, retried on timeout
25
32
  _MAVEN_JAR_HTTP_TIMEOUT = (2, 2) # match Util probe timeouts for multi-repo jar checks
26
33
  _MAX_RETRY = 3 # maximum Central API retry attempts per JAR
27
34
  _central_network_warned = False # Flag to suppress repeated network-unavailable warnings within one run
@@ -116,16 +123,37 @@ def _warn_network_once(context=""):
116
123
 
117
124
 
118
125
  def _search_central_by_sha1(sha1, timeout=None):
126
+ """Look up Maven coordinates by JAR checksum, trying each Central host in turn.
127
+
128
+ An answer from any host is authoritative for the whole index, so a miss ends
129
+ the search. ``timed_out`` is reported only when no host answered at all.
130
+ """
119
131
  if not sha1:
120
132
  return {}, False
121
133
  _timeout = timeout if timeout is not None else _CENTRAL_SEARCH_TIMEOUT
122
- try:
123
- params = {"q": f"1:{sha1}", "rows": 1, "wt": "json"}
124
- resp = requests.get(_CENTRAL_SEARCH_URL, params=params, timeout=_timeout)
125
- resp.raise_for_status()
126
- docs = resp.json().get("response", {}).get("docs", [])
134
+ params = {"q": f"1:{sha1}", "rows": 1, "wt": "json"}
135
+ any_timeout = False
136
+ unreachable = False
137
+
138
+ for url in _CENTRAL_SEARCH_URLS:
139
+ try:
140
+ resp = requests.get(url, params=params, timeout=_timeout)
141
+ resp.raise_for_status()
142
+ docs = resp.json().get("response", {}).get("docs", [])
143
+ except requests.exceptions.Timeout:
144
+ logger.debug(f"Maven Central SHA-1 search timed out ({sha1}) at {url} - will retry")
145
+ any_timeout = True
146
+ continue
147
+ except Exception as ex:
148
+ if _is_network_error(ex):
149
+ unreachable = True
150
+ else:
151
+ logger.debug(f"Maven Central SHA-1 search failed ({sha1}) at {url}: {ex}")
152
+ continue
153
+
127
154
  if not docs:
128
155
  return {}, False
156
+
129
157
  doc = docs[0]
130
158
  groupId = doc.get("g", "")
131
159
  artifactId = doc.get("a", "")
@@ -140,15 +168,11 @@ def _search_central_by_sha1(sha1, timeout=None):
140
168
  "artifactId": artifactId,
141
169
  "version": version,
142
170
  }, False
143
- except requests.exceptions.Timeout:
144
- logger.debug(f"Maven Central SHA-1 search timed out ({sha1}) - will retry")
145
- return {}, True
146
- except Exception as ex:
147
- if _is_network_error(ex):
148
- _warn_network_once(f"SHA-1 search: {sha1[:10]}...")
149
- else:
150
- logger.debug(f"Maven Central SHA-1 search failed ({sha1}): {ex}")
151
- return {}, False
171
+
172
+ # Warn only once every host has failed: a fallback answer is not a failure.
173
+ if unreachable:
174
+ _warn_network_once(f"SHA-1 search: {sha1[:10]}...")
175
+ return {}, any_timeout
152
176
 
153
177
 
154
178
  def _download_pom_to_tempfile(group_id, artifact_id, version, timeout=None):
@@ -367,7 +391,8 @@ def _process_one_jar(jar_path, rel_path, sha1, search_timeout=None, skip_central
367
391
 
368
392
 
369
393
  def _has_valid_jar_oss(oss_list):
370
- return any(oss.name and oss.license for oss in oss_list)
394
+ """True if any entry is identified. A missing license is reported as empty."""
395
+ return any(oss.name for oss in oss_list)
371
396
 
372
397
 
373
398
  def _store_jar_result(jar_items, sha1, result):
@@ -4,10 +4,10 @@
4
4
  # Copyright (c) 2024 LG Electronics Inc.
5
5
  # SPDX-License-Identifier: Apache-2.0
6
6
  import os
7
- import re
8
7
  import logging
9
8
  import zipfile
10
9
  import tarfile
10
+ import magic
11
11
  import yaml
12
12
  import fosslight_util.constant as constant
13
13
  from fosslight_util.set_log import init_log
@@ -18,7 +18,14 @@ logger = logging.getLogger(constant.LOGGER_NAME)
18
18
 
19
19
 
20
20
  def is_compressed_file(filename):
21
- return zipfile.is_zipfile(filename) or tarfile.is_tarfile(filename)
21
+ if zipfile.is_zipfile(filename) or tarfile.is_tarfile(filename):
22
+ return True
23
+
24
+ try:
25
+ file_type = magic.from_file(filename).lower()
26
+ return 'archive' in file_type or 'compressed' in file_type
27
+ except Exception:
28
+ return False
22
29
 
23
30
 
24
31
  def is_jar_file(filename):
@@ -35,9 +42,9 @@ def exclude_bin_for_simple_mode(binary_list):
35
42
 
36
43
  path = bin.bin_name_with_path
37
44
 
38
- if is_jar_file(path) and not re.search(r".*sources\.jar", path.lower()):
45
+ if is_jar_file(path) and not path.lower().endswith('-sources.jar'):
39
46
  bin_list_exclude_compressed.append(path)
40
- elif re.search(r".*sources\.jar", path.lower()) or is_compressed_file(path):
47
+ elif path.lower().endswith('-sources.jar') or is_compressed_file(path):
41
48
  compressed_list.append(path)
42
49
  else:
43
50
  bin_list_exclude_compressed.append(path)
@@ -22,6 +22,7 @@ from fosslight_util.time import current_timestamp_utc, format_running_time, time
22
22
  from fosslight_util.correct import correct_with_yaml
23
23
  from fosslight_util.oss_item import ScannerItem
24
24
  from fosslight_util.exclude import get_excluded_paths
25
+ from ._exclude import EXCLUDE_FILENAME_BINARY, is_excluded_binary_filename
25
26
  import hashlib
26
27
  import tlsh
27
28
  from io import open
@@ -93,15 +94,14 @@ def init(path_to_find_bin, output_file_name, formats, path_to_exclude=[]):
93
94
  for i, output_extension in enumerate(output_extensions):
94
95
  if output_files[i] is None or output_files[i] == "":
95
96
  if formats:
96
- if formats[i].startswith('spdx') or formats[i].startswith('cyclonedx'):
97
+ if formats[i].startswith('spdx'):
97
98
  if platform.system() == 'Windows':
98
99
  logger.warning(f'{formats[i]} is not supported on Windows. Please remove {formats[i]} from format.')
99
100
  to_remove.append(i)
100
101
  else:
101
- if formats[i].startswith('spdx'):
102
- output_files[i] = f"fosslight_spdx_bin_{file_time}"
103
- elif formats[i].startswith('cyclonedx'):
104
- output_files[i] = f'fosslight_cyclonedx_bin_{file_time}'
102
+ output_files[i] = f"fosslight_spdx_bin_{file_time}"
103
+ elif formats[i].startswith('cyclonedx'):
104
+ output_files[i] = f'fosslight_cyclonedx_bin_{file_time}'
105
105
  else:
106
106
  if output_extension == _json_ext:
107
107
  output_files[i] = f"fosslight_opossum_bin_{file_time}"
@@ -147,7 +147,7 @@ def get_file_list(path_to_find, excluded_files):
147
147
  for file in files:
148
148
  bin_with_path = os.path.join(root, file)
149
149
  rel_path_file = os.path.relpath(bin_with_path, path_to_find).replace('\\', '/')
150
- if rel_path_file in excluded_files:
150
+ if rel_path_file in excluded_files or is_excluded_binary_filename(rel_path_file):
151
151
  continue
152
152
  file_lower_case = file.lower()
153
153
  extension = os.path.splitext(file_lower_case)[1][1:].strip()
@@ -200,10 +200,14 @@ def find_binaries(path_to_find_bin, output_dir, formats, kb_url="", kb_token="",
200
200
  excluded_path_with_default_exclusion, excluded_path_without_dot, excluded_files, cnt_file_except_skipped = all_exclude_mode
201
201
  elif simple_mode:
202
202
  excluded_path_with_default_exclusion, excluded_path_without_dot, excluded_files, cnt_file_except_skipped \
203
- = get_excluded_paths(path_to_find_bin, path_to_exclude, REMOVE_FILE_EXTENSION_SIMPLE)
203
+ = get_excluded_paths(
204
+ path_to_find_bin, path_to_exclude, REMOVE_FILE_EXTENSION_SIMPLE,
205
+ exclude_filenames=EXCLUDE_FILENAME_BINARY)
204
206
  else:
205
207
  excluded_path_with_default_exclusion, excluded_path_without_dot, excluded_files, cnt_file_except_skipped \
206
- = get_excluded_paths(path_to_find_bin, path_to_exclude)
208
+ = get_excluded_paths(
209
+ path_to_find_bin, path_to_exclude,
210
+ exclude_filenames=EXCLUDE_FILENAME_BINARY)
207
211
  logger.debug(f"Skipped paths: {excluded_path_with_default_exclusion}")
208
212
 
209
213
  if not os.path.isdir(path_to_find_bin):
@@ -273,7 +277,8 @@ def find_binaries(path_to_find_bin, output_dir, formats, kb_url="", kb_token="",
273
277
 
274
278
  for combined_path_and_file, output_extension, output_format in zip(result_reports, output_extensions, formats):
275
279
  results.append(write_output_file(combined_path_and_file, output_extension, scan_item,
276
- BIN_EXT_HEADER, HIDE_HEADER, output_format))
280
+ BIN_EXT_HEADER, HIDE_HEADER, output_format,
281
+ scanner_covers=[scan_item.cover]))
277
282
 
278
283
  except Exception as ex:
279
284
  error_occured(error_msg=str(ex), exit=False)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fosslight_binary
3
- Version: 5.1.31
3
+ Version: 5.1.32
4
4
  Summary: FOSSLight Binary Scanner
5
5
  Author: LG Electronics
6
6
  License-Expression: Apache-2.0
@@ -29,7 +29,7 @@ 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.8
32
+ Requires-Dist: fosslight_util>=2.2.14
33
33
  Requires-Dist: truststore
34
34
  Requires-Dist: python-magic-bin; sys_platform == "win32"
35
35
  Requires-Dist: python-magic; "darwin" in sys_platform
@@ -8,6 +8,7 @@ LICENSES/LicenseRef-3rd-party-licenses.txt
8
8
  src/fosslight_binary/__init__.py
9
9
  src/fosslight_binary/_binary.py
10
10
  src/fosslight_binary/_binary_dao.py
11
+ src/fosslight_binary/_exclude.py
11
12
  src/fosslight_binary/_help.py
12
13
  src/fosslight_binary/_jar_analysis.py
13
14
  src/fosslight_binary/_simple_mode.py
@@ -9,7 +9,7 @@ py-tlsh
9
9
  pytz
10
10
  XlsxWriter
11
11
  PyYAML
12
- fosslight_util>=2.2.8
12
+ fosslight_util>=2.2.14
13
13
  truststore
14
14
 
15
15
  [:"darwin" in sys_platform]