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.
Files changed (91) hide show
  1. pybinaryguard/__init__.py +78 -0
  2. pybinaryguard/__main__.py +7 -0
  3. pybinaryguard/_compat/__init__.py +0 -0
  4. pybinaryguard/agent/__init__.py +63 -0
  5. pybinaryguard/agent/guard.py +232 -0
  6. pybinaryguard/agent/recommender.py +283 -0
  7. pybinaryguard/agent/schema.py +200 -0
  8. pybinaryguard/agent/simulator.py +430 -0
  9. pybinaryguard/agent/tool_interface.py +474 -0
  10. pybinaryguard/analyzers/__init__.py +209 -0
  11. pybinaryguard/analyzers/base.py +40 -0
  12. pybinaryguard/analyzers/dependency_analyzer.py +336 -0
  13. pybinaryguard/analyzers/elf_analyzer.py +754 -0
  14. pybinaryguard/analyzers/symbol_analyzer.py +280 -0
  15. pybinaryguard/analyzers/wheel_analyzer.py +308 -0
  16. pybinaryguard/cli/__init__.py +5 -0
  17. pybinaryguard/cli/commands.py +414 -0
  18. pybinaryguard/cli/formatters.py +720 -0
  19. pybinaryguard/cli/main.py +250 -0
  20. pybinaryguard/diagnostics/__init__.py +13 -0
  21. pybinaryguard/diagnostics/explainer.py +356 -0
  22. pybinaryguard/diagnostics/findings.py +146 -0
  23. pybinaryguard/diagnostics/suggestions.py +508 -0
  24. pybinaryguard/frameworks/__init__.py +20 -0
  25. pybinaryguard/frameworks/onnxruntime.py +214 -0
  26. pybinaryguard/frameworks/pytorch.py +223 -0
  27. pybinaryguard/frameworks/tensorflow.py +266 -0
  28. pybinaryguard/frameworks/tensorrt.py +189 -0
  29. pybinaryguard/models/__init__.py +19 -0
  30. pybinaryguard/models/enums.py +102 -0
  31. pybinaryguard/models/finding.py +109 -0
  32. pybinaryguard/models/package.py +121 -0
  33. pybinaryguard/models/system.py +118 -0
  34. pybinaryguard/plugins/__init__.py +19 -0
  35. pybinaryguard/plugins/contrib/__init__.py +7 -0
  36. pybinaryguard/plugins/contrib/gstreamer.py +109 -0
  37. pybinaryguard/plugins/contrib/jetson.py +385 -0
  38. pybinaryguard/plugins/contrib/opencv.py +306 -0
  39. pybinaryguard/plugins/contrib/tensorrt.py +426 -0
  40. pybinaryguard/plugins/hooks.py +273 -0
  41. pybinaryguard/plugins/loader.py +190 -0
  42. pybinaryguard/predictor/__init__.py +23 -0
  43. pybinaryguard/predictor/dependency_graph.py +226 -0
  44. pybinaryguard/predictor/linker_simulator.py +161 -0
  45. pybinaryguard/predictor/predictor.py +144 -0
  46. pybinaryguard/predictor/resolver.py +282 -0
  47. pybinaryguard/probes/__init__.py +73 -0
  48. pybinaryguard/probes/base.py +45 -0
  49. pybinaryguard/probes/board_probe.py +248 -0
  50. pybinaryguard/probes/cpu_probe.py +176 -0
  51. pybinaryguard/probes/glibc_probe.py +215 -0
  52. pybinaryguard/probes/gpu_probe.py +430 -0
  53. pybinaryguard/probes/library_probe.py +132 -0
  54. pybinaryguard/probes/os_probe.py +227 -0
  55. pybinaryguard/probes/python_probe.py +135 -0
  56. pybinaryguard/probes/toolchain_probe.py +89 -0
  57. pybinaryguard/probes/venv_probe.py +111 -0
  58. pybinaryguard/profiles/__init__.py +12 -0
  59. pybinaryguard/profiles/engine.py +343 -0
  60. pybinaryguard/rules/__init__.py +24 -0
  61. pybinaryguard/rules/base.py +57 -0
  62. pybinaryguard/rules/builtin/__init__.py +136 -0
  63. pybinaryguard/rules/builtin/arch_rules.py +86 -0
  64. pybinaryguard/rules/builtin/board_profile_rules.py +282 -0
  65. pybinaryguard/rules/builtin/container_rules.py +170 -0
  66. pybinaryguard/rules/builtin/cpu_rules.py +204 -0
  67. pybinaryguard/rules/builtin/cuda_rules.py +760 -0
  68. pybinaryguard/rules/builtin/dependency_rules.py +278 -0
  69. pybinaryguard/rules/builtin/framework_rules.py +252 -0
  70. pybinaryguard/rules/builtin/glibc_rules.py +320 -0
  71. pybinaryguard/rules/builtin/numpy_rules.py +110 -0
  72. pybinaryguard/rules/builtin/predictive_rules.py +165 -0
  73. pybinaryguard/rules/builtin/python_abi_rules.py +259 -0
  74. pybinaryguard/rules/builtin/source_build_rules.py +150 -0
  75. pybinaryguard/rules/builtin/venv_rules.py +159 -0
  76. pybinaryguard/rules/engine.py +123 -0
  77. pybinaryguard/scanner.py +904 -0
  78. pybinaryguard/scoring/__init__.py +19 -0
  79. pybinaryguard/scoring/engine.py +416 -0
  80. pybinaryguard/snapshot/__init__.py +20 -0
  81. pybinaryguard/snapshot/generator.py +168 -0
  82. pybinaryguard/snapshot/lockfile.py +152 -0
  83. pybinaryguard/snapshot/verifier.py +315 -0
  84. pybinaryguard/validators/__init__.py +7 -0
  85. pybinaryguard/validators/import_validator.py +231 -0
  86. pybinaryguard-1.0.0.dist-info/METADATA +876 -0
  87. pybinaryguard-1.0.0.dist-info/RECORD +91 -0
  88. pybinaryguard-1.0.0.dist-info/WHEEL +5 -0
  89. pybinaryguard-1.0.0.dist-info/entry_points.txt +8 -0
  90. pybinaryguard-1.0.0.dist-info/licenses/LICENSE +21 -0
  91. 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")