pybinaryguard 1.0.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.
- pybinaryguard/__init__.py +78 -0
- pybinaryguard/__main__.py +7 -0
- pybinaryguard/_compat/__init__.py +0 -0
- pybinaryguard/agent/__init__.py +63 -0
- pybinaryguard/agent/guard.py +232 -0
- pybinaryguard/agent/recommender.py +283 -0
- pybinaryguard/agent/schema.py +200 -0
- pybinaryguard/agent/simulator.py +430 -0
- pybinaryguard/agent/tool_interface.py +474 -0
- pybinaryguard/analyzers/__init__.py +209 -0
- pybinaryguard/analyzers/base.py +40 -0
- pybinaryguard/analyzers/dependency_analyzer.py +336 -0
- pybinaryguard/analyzers/elf_analyzer.py +754 -0
- pybinaryguard/analyzers/symbol_analyzer.py +280 -0
- pybinaryguard/analyzers/wheel_analyzer.py +308 -0
- pybinaryguard/cli/__init__.py +5 -0
- pybinaryguard/cli/commands.py +414 -0
- pybinaryguard/cli/formatters.py +720 -0
- pybinaryguard/cli/main.py +250 -0
- pybinaryguard/diagnostics/__init__.py +13 -0
- pybinaryguard/diagnostics/explainer.py +356 -0
- pybinaryguard/diagnostics/findings.py +146 -0
- pybinaryguard/diagnostics/suggestions.py +508 -0
- pybinaryguard/frameworks/__init__.py +20 -0
- pybinaryguard/frameworks/onnxruntime.py +214 -0
- pybinaryguard/frameworks/pytorch.py +223 -0
- pybinaryguard/frameworks/tensorflow.py +266 -0
- pybinaryguard/frameworks/tensorrt.py +189 -0
- pybinaryguard/models/__init__.py +19 -0
- pybinaryguard/models/enums.py +102 -0
- pybinaryguard/models/finding.py +109 -0
- pybinaryguard/models/package.py +121 -0
- pybinaryguard/models/system.py +118 -0
- pybinaryguard/plugins/__init__.py +19 -0
- pybinaryguard/plugins/contrib/__init__.py +7 -0
- pybinaryguard/plugins/contrib/gstreamer.py +109 -0
- pybinaryguard/plugins/contrib/jetson.py +385 -0
- pybinaryguard/plugins/contrib/opencv.py +306 -0
- pybinaryguard/plugins/contrib/tensorrt.py +426 -0
- pybinaryguard/plugins/hooks.py +273 -0
- pybinaryguard/plugins/loader.py +190 -0
- pybinaryguard/predictor/__init__.py +23 -0
- pybinaryguard/predictor/dependency_graph.py +226 -0
- pybinaryguard/predictor/linker_simulator.py +161 -0
- pybinaryguard/predictor/predictor.py +144 -0
- pybinaryguard/predictor/resolver.py +282 -0
- pybinaryguard/probes/__init__.py +73 -0
- pybinaryguard/probes/base.py +45 -0
- pybinaryguard/probes/board_probe.py +248 -0
- pybinaryguard/probes/cpu_probe.py +176 -0
- pybinaryguard/probes/glibc_probe.py +215 -0
- pybinaryguard/probes/gpu_probe.py +430 -0
- pybinaryguard/probes/library_probe.py +132 -0
- pybinaryguard/probes/os_probe.py +227 -0
- pybinaryguard/probes/python_probe.py +135 -0
- pybinaryguard/probes/toolchain_probe.py +89 -0
- pybinaryguard/probes/venv_probe.py +111 -0
- pybinaryguard/profiles/__init__.py +12 -0
- pybinaryguard/profiles/engine.py +343 -0
- pybinaryguard/rules/__init__.py +24 -0
- pybinaryguard/rules/base.py +57 -0
- pybinaryguard/rules/builtin/__init__.py +136 -0
- pybinaryguard/rules/builtin/arch_rules.py +86 -0
- pybinaryguard/rules/builtin/board_profile_rules.py +282 -0
- pybinaryguard/rules/builtin/container_rules.py +170 -0
- pybinaryguard/rules/builtin/cpu_rules.py +204 -0
- pybinaryguard/rules/builtin/cuda_rules.py +760 -0
- pybinaryguard/rules/builtin/dependency_rules.py +278 -0
- pybinaryguard/rules/builtin/framework_rules.py +252 -0
- pybinaryguard/rules/builtin/glibc_rules.py +320 -0
- pybinaryguard/rules/builtin/numpy_rules.py +110 -0
- pybinaryguard/rules/builtin/predictive_rules.py +165 -0
- pybinaryguard/rules/builtin/python_abi_rules.py +259 -0
- pybinaryguard/rules/builtin/source_build_rules.py +150 -0
- pybinaryguard/rules/builtin/venv_rules.py +159 -0
- pybinaryguard/rules/engine.py +123 -0
- pybinaryguard/scanner.py +904 -0
- pybinaryguard/scoring/__init__.py +19 -0
- pybinaryguard/scoring/engine.py +416 -0
- pybinaryguard/snapshot/__init__.py +20 -0
- pybinaryguard/snapshot/generator.py +168 -0
- pybinaryguard/snapshot/lockfile.py +152 -0
- pybinaryguard/snapshot/verifier.py +315 -0
- pybinaryguard/validators/__init__.py +7 -0
- pybinaryguard/validators/import_validator.py +231 -0
- pybinaryguard-1.0.0.dist-info/METADATA +876 -0
- pybinaryguard-1.0.0.dist-info/RECORD +91 -0
- pybinaryguard-1.0.0.dist-info/WHEEL +5 -0
- pybinaryguard-1.0.0.dist-info/entry_points.txt +8 -0
- pybinaryguard-1.0.0.dist-info/licenses/LICENSE +21 -0
- pybinaryguard-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"""OpenCV plugin for PyBinaryGuard.
|
|
2
|
+
|
|
3
|
+
Activates when the ``cv2`` package is importable. Parses
|
|
4
|
+
``cv2.getBuildInformation()`` to detect build flags and checks for
|
|
5
|
+
common misconfiguration issues on embedded and GPU-equipped systems.
|
|
6
|
+
|
|
7
|
+
Provides
|
|
8
|
+
--------
|
|
9
|
+
- **OpenCVBuildProbe** -- Parses the OpenCV build information string to
|
|
10
|
+
extract enabled/disabled modules and backend support.
|
|
11
|
+
- **OpenCVNoCUDARule** -- Reports when OpenCV lacks CUDA support on a
|
|
12
|
+
GPU-equipped board (INFO severity).
|
|
13
|
+
- **OpenCVNoGStreamerRule** -- Reports when OpenCV lacks GStreamer support
|
|
14
|
+
on an embedded board (WARNING severity).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
import re
|
|
21
|
+
from typing import Any, Dict, FrozenSet, List, Optional, TYPE_CHECKING
|
|
22
|
+
|
|
23
|
+
from pybinaryguard.models.enums import Severity
|
|
24
|
+
from pybinaryguard.models.finding import Finding
|
|
25
|
+
from pybinaryguard.models.package import PackageBinaryInfo
|
|
26
|
+
from pybinaryguard.models.system import SystemProfile
|
|
27
|
+
from pybinaryguard.probes.base import ProbeBase
|
|
28
|
+
from pybinaryguard.rules.base import Rule
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from pybinaryguard.plugins.hooks import HookRegistry
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# -- Build-info parser ------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _parse_build_information(build_info: str) -> Dict[str, Any]:
|
|
40
|
+
"""Parse the string returned by ``cv2.getBuildInformation()``.
|
|
41
|
+
|
|
42
|
+
The output is a multi-section text block. We extract key boolean
|
|
43
|
+
flags (CUDA, GStreamer, FFmpeg, etc.) and the OpenCV version.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
build_info: The raw string from ``cv2.getBuildInformation()``.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
A dict with parsed flags. Keys include ``"cuda"``, ``"gstreamer"``,
|
|
50
|
+
``"ffmpeg"``, ``"opencl"``, ``"version"``, etc. Values are booleans
|
|
51
|
+
for feature flags and strings for version info.
|
|
52
|
+
"""
|
|
53
|
+
result: Dict[str, Any] = {}
|
|
54
|
+
|
|
55
|
+
# Extract version
|
|
56
|
+
version_match = re.search(r"OpenCV\s+([\d.]+)", build_info)
|
|
57
|
+
if version_match:
|
|
58
|
+
result["version"] = version_match.group(1)
|
|
59
|
+
|
|
60
|
+
# Common yes/no feature flags. The build info uses patterns like:
|
|
61
|
+
# NVIDIA CUDA: YES (ver 11.4, ...)
|
|
62
|
+
# GStreamer: NO
|
|
63
|
+
# FFMPEG: YES
|
|
64
|
+
_flag_patterns = {
|
|
65
|
+
"cuda": r"NVIDIA CUDA:\s+(YES|NO)",
|
|
66
|
+
"cudnn": r"cuDNN:\s+(YES|NO)",
|
|
67
|
+
"gstreamer": r"GStreamer:\s+(YES|NO)",
|
|
68
|
+
"ffmpeg": r"FFMPEG:\s+(YES|NO)",
|
|
69
|
+
"opencl": r"OpenCL:\s+(YES|NO)",
|
|
70
|
+
"v4l2": r"v4l/v4l2:\s+(YES|NO)",
|
|
71
|
+
"gtk": r"GTK\+:\s+(YES|NO)",
|
|
72
|
+
"qt": r"QT:\s+(YES|NO)",
|
|
73
|
+
"tbb": r"TBB:\s+(YES|NO)",
|
|
74
|
+
"openmp": r"OpenMP:\s+(YES|NO)",
|
|
75
|
+
"vulkan": r"Vulkan:\s+(YES|NO)",
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for key, pattern in _flag_patterns.items():
|
|
79
|
+
match = re.search(pattern, build_info, re.IGNORECASE)
|
|
80
|
+
if match:
|
|
81
|
+
result[key] = match.group(1).upper() == "YES"
|
|
82
|
+
else:
|
|
83
|
+
result[key] = False
|
|
84
|
+
|
|
85
|
+
# Extract CUDA version if present
|
|
86
|
+
cuda_ver_match = re.search(r"NVIDIA CUDA:\s+YES\s+\(ver\s+([\d.]+)", build_info)
|
|
87
|
+
if cuda_ver_match:
|
|
88
|
+
result["cuda_version"] = cuda_ver_match.group(1)
|
|
89
|
+
|
|
90
|
+
# Extract cuDNN version if present
|
|
91
|
+
cudnn_ver_match = re.search(r"cuDNN:\s+YES\s+\(ver\s+([\d.]+)", build_info)
|
|
92
|
+
if cudnn_ver_match:
|
|
93
|
+
result["cudnn_version"] = cudnn_ver_match.group(1)
|
|
94
|
+
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# -- Probe ------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class OpenCVBuildProbe(ProbeBase):
|
|
102
|
+
"""Probe that extracts OpenCV build configuration.
|
|
103
|
+
|
|
104
|
+
This probe imports ``cv2`` and parses the build information string
|
|
105
|
+
to determine which backends and accelerators are available. It is
|
|
106
|
+
read-only and does not modify any system state.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
name = "opencv_build"
|
|
110
|
+
|
|
111
|
+
def is_applicable(self) -> bool:
|
|
112
|
+
"""Only run when ``cv2`` is importable."""
|
|
113
|
+
try:
|
|
114
|
+
import cv2 # noqa: F401
|
|
115
|
+
return True
|
|
116
|
+
except ImportError:
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
def collect(self) -> Dict[str, Any]:
|
|
120
|
+
"""Parse ``cv2.getBuildInformation()`` and return feature flags.
|
|
121
|
+
|
|
122
|
+
The returned dict does not map directly to ``SystemProfile``
|
|
123
|
+
fields; instead it provides supplementary data that framework
|
|
124
|
+
checkers and rules can access.
|
|
125
|
+
"""
|
|
126
|
+
try:
|
|
127
|
+
import cv2
|
|
128
|
+
build_info = cv2.getBuildInformation()
|
|
129
|
+
except Exception:
|
|
130
|
+
logger.debug("Failed to call cv2.getBuildInformation()")
|
|
131
|
+
return {}
|
|
132
|
+
|
|
133
|
+
parsed = _parse_build_information(build_info)
|
|
134
|
+
logger.debug("OpenCV build flags: %s", parsed)
|
|
135
|
+
return parsed
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# -- Rules ------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class OpenCVNoCUDARule(Rule):
|
|
142
|
+
"""Report when OpenCV lacks CUDA support on a GPU-equipped board.
|
|
143
|
+
|
|
144
|
+
On systems with a GPU, having an OpenCV build without CUDA support
|
|
145
|
+
means GPU-accelerated image processing is unavailable. This is
|
|
146
|
+
informational -- it may be intentional.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
rule_id = "OPENCV_NO_CUDA"
|
|
150
|
+
description = (
|
|
151
|
+
"Check whether OpenCV was built with CUDA support on a "
|
|
152
|
+
"GPU-equipped system."
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def is_applicable(self, profile: SystemProfile) -> bool:
|
|
156
|
+
"""Only applies when a GPU is available."""
|
|
157
|
+
return profile.gpu_available
|
|
158
|
+
|
|
159
|
+
def evaluate(
|
|
160
|
+
self,
|
|
161
|
+
profile: SystemProfile,
|
|
162
|
+
packages: List[PackageBinaryInfo],
|
|
163
|
+
) -> List[Finding]:
|
|
164
|
+
"""Check OpenCV's CUDA build flag."""
|
|
165
|
+
findings: List[Finding] = []
|
|
166
|
+
|
|
167
|
+
build_flags = self._get_opencv_build_flags()
|
|
168
|
+
if build_flags is None:
|
|
169
|
+
# OpenCV not installed or not importable -- nothing to check.
|
|
170
|
+
return findings
|
|
171
|
+
|
|
172
|
+
has_cuda = build_flags.get("cuda", False)
|
|
173
|
+
if not has_cuda:
|
|
174
|
+
findings.append(Finding(
|
|
175
|
+
rule_id=self.rule_id,
|
|
176
|
+
severity=Severity.INFO,
|
|
177
|
+
title="OpenCV built without CUDA support",
|
|
178
|
+
explanation=(
|
|
179
|
+
"This system has a GPU, but the installed OpenCV was "
|
|
180
|
+
"built without CUDA support. GPU-accelerated image "
|
|
181
|
+
"processing via cv2.cuda will not be available."
|
|
182
|
+
),
|
|
183
|
+
suggestion=(
|
|
184
|
+
"Install opencv-contrib-python or build OpenCV from "
|
|
185
|
+
"source with -D WITH_CUDA=ON to enable GPU acceleration."
|
|
186
|
+
),
|
|
187
|
+
package="opencv-python",
|
|
188
|
+
confidence=0.9,
|
|
189
|
+
))
|
|
190
|
+
else:
|
|
191
|
+
findings.append(Finding(
|
|
192
|
+
rule_id=self.rule_id,
|
|
193
|
+
severity=Severity.PASSED,
|
|
194
|
+
title="OpenCV has CUDA support",
|
|
195
|
+
explanation="OpenCV was built with CUDA support enabled.",
|
|
196
|
+
package="opencv-python",
|
|
197
|
+
))
|
|
198
|
+
|
|
199
|
+
return findings
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def _get_opencv_build_flags() -> Optional[Dict[str, Any]]:
|
|
203
|
+
"""Import cv2 and parse build flags, returning None on failure."""
|
|
204
|
+
try:
|
|
205
|
+
import cv2
|
|
206
|
+
return _parse_build_information(cv2.getBuildInformation())
|
|
207
|
+
except ImportError:
|
|
208
|
+
return None
|
|
209
|
+
except Exception:
|
|
210
|
+
logger.debug("Failed to parse OpenCV build information", exc_info=True)
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class OpenCVNoGStreamerRule(Rule):
|
|
215
|
+
"""Report when OpenCV lacks GStreamer support on an embedded board.
|
|
216
|
+
|
|
217
|
+
On embedded systems (Jetson, Raspberry Pi, etc.), GStreamer is the
|
|
218
|
+
primary multimedia pipeline. An OpenCV build without GStreamer
|
|
219
|
+
support limits video capture and processing capabilities.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
rule_id = "OPENCV_NO_GSTREAMER"
|
|
223
|
+
description = (
|
|
224
|
+
"Check whether OpenCV was built with GStreamer support on an "
|
|
225
|
+
"embedded board."
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
def is_applicable(self, profile: SystemProfile) -> bool:
|
|
229
|
+
"""Only applies on embedded boards."""
|
|
230
|
+
return profile.is_embedded_board
|
|
231
|
+
|
|
232
|
+
def evaluate(
|
|
233
|
+
self,
|
|
234
|
+
profile: SystemProfile,
|
|
235
|
+
packages: List[PackageBinaryInfo],
|
|
236
|
+
) -> List[Finding]:
|
|
237
|
+
"""Check OpenCV's GStreamer build flag."""
|
|
238
|
+
findings: List[Finding] = []
|
|
239
|
+
|
|
240
|
+
build_flags = self._get_opencv_build_flags()
|
|
241
|
+
if build_flags is None:
|
|
242
|
+
return findings
|
|
243
|
+
|
|
244
|
+
has_gstreamer = build_flags.get("gstreamer", False)
|
|
245
|
+
if not has_gstreamer:
|
|
246
|
+
board_desc = profile.board_name or "embedded board"
|
|
247
|
+
findings.append(Finding(
|
|
248
|
+
rule_id=self.rule_id,
|
|
249
|
+
severity=Severity.WARNING,
|
|
250
|
+
title="OpenCV built without GStreamer support",
|
|
251
|
+
explanation=(
|
|
252
|
+
f"This {board_desc} relies on GStreamer for hardware-"
|
|
253
|
+
f"accelerated video pipelines, but the installed OpenCV "
|
|
254
|
+
f"was built without GStreamer support. Video capture "
|
|
255
|
+
f"with cv2.VideoCapture using GStreamer pipelines will fail."
|
|
256
|
+
),
|
|
257
|
+
suggestion=(
|
|
258
|
+
"Build OpenCV from source with -D WITH_GSTREAMER=ON, or "
|
|
259
|
+
"install a distribution-provided OpenCV package that "
|
|
260
|
+
"includes GStreamer support."
|
|
261
|
+
),
|
|
262
|
+
package="opencv-python",
|
|
263
|
+
))
|
|
264
|
+
else:
|
|
265
|
+
findings.append(Finding(
|
|
266
|
+
rule_id=self.rule_id,
|
|
267
|
+
severity=Severity.PASSED,
|
|
268
|
+
title="OpenCV has GStreamer support",
|
|
269
|
+
explanation="OpenCV was built with GStreamer support enabled.",
|
|
270
|
+
package="opencv-python",
|
|
271
|
+
))
|
|
272
|
+
|
|
273
|
+
return findings
|
|
274
|
+
|
|
275
|
+
@staticmethod
|
|
276
|
+
def _get_opencv_build_flags() -> Optional[Dict[str, Any]]:
|
|
277
|
+
"""Import cv2 and parse build flags, returning None on failure."""
|
|
278
|
+
try:
|
|
279
|
+
import cv2
|
|
280
|
+
return _parse_build_information(cv2.getBuildInformation())
|
|
281
|
+
except ImportError:
|
|
282
|
+
return None
|
|
283
|
+
except Exception:
|
|
284
|
+
logger.debug("Failed to parse OpenCV build information", exc_info=True)
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# -- Plugin entry point -----------------------------------------------------
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def register(registry: HookRegistry) -> None:
|
|
292
|
+
"""Register OpenCV extensions if cv2 is importable.
|
|
293
|
+
|
|
294
|
+
This function is called by the plugin loader. It only activates
|
|
295
|
+
when ``cv2`` can be imported, indicating that OpenCV is installed.
|
|
296
|
+
"""
|
|
297
|
+
try:
|
|
298
|
+
import cv2 # noqa: F401
|
|
299
|
+
except ImportError:
|
|
300
|
+
logger.debug("OpenCV plugin: cv2 not importable; not activating")
|
|
301
|
+
return
|
|
302
|
+
|
|
303
|
+
registry.add_probe(OpenCVBuildProbe())
|
|
304
|
+
registry.add_rule(OpenCVNoCUDARule())
|
|
305
|
+
registry.add_rule(OpenCVNoGStreamerRule())
|
|
306
|
+
logger.info("OpenCV plugin activated")
|