Files
Oleksandr Bezdieniezhnykh 33486588de [AZ-271] [AZ-276] [AZ-278] [AZ-282] Finish cross-cutting helpers + relax opencv pin
E-CC-HELPERS closes with the three remaining Layer-1 helpers and
E-CC-CONF closes with the env > YAML > defaults precedence test
gate. All four tickets ship with frozen public surfaces, hermetic
unit tests, and no upward (components.*) imports.

* AZ-271 — tests/unit/shared/config/test_precedence.py (5 ACs + smoke
  test + helper that names the layer in failure messages).
* AZ-282 — helpers/ransac_filter.py: static RansacFilter +
  RansacResult; cv2.setRNGSeed(0) for byte-equal determinism;
  median residual semantics pinned by contract.
* AZ-276 — helpers/imu_preintegrator.py + make_imu_preintegrator;
  GTSAM PreintegratedCombinedMeasurements; strict-monotonic ts_ns
  guard runs before any state mutation. Adjacent hygiene:
  _types/nav.py ImuSample/ImuWindow now use ts_ns:int and the
  spec-mandated ImuBias dataclass.
* AZ-278 — helpers/lightglue_runtime.py: structural R14 fix.
  LightGlueRuntime + non-blocking concurrent-access guard that
  raises rather than serialising. EngineHandle Protocol in
  _types/manifests.py + KeypointSet/CorrespondenceSet in
  _types/matching.py (Protocol surface adds approved by spec).

Dependency conflict (Finding 1, user-approved): gtsam 4.2 (PyPI) is
numpy-1.x-ABI only; opencv-python>=4.12 needs numpy>=2 at runtime.
Resolution: opencv-python pin relaxed to >=4.11.0.86,<4.12. The
D-CROSS-CVE-1 ratchet at ci/opencv_pin_gate.py is held at 4.11.0
with the original 4.12.0 floor restored once a numpy-2-compatible
gtsam wheel ships. Full replay procedure in
_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md.

Tests: 294 passed, 2 skipped (cmake/actionlint env-skips,
pre-existing). 43 new tests added for batch 5. Ruff check + format
clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 03:23:33 +03:00

75 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""OpenCV pin gate — D-CROSS-CVE-1 enforcement.
Asserts that the resolved `opencv-python` (or `opencv-contrib-python`) version
declared in `pyproject.toml` is at or above the project floor. Runs without
installing any deps.
The original gate enforced `>= 4.12.0`. As of 2026-05-11 the gate is held at
`>= 4.11.0` while gtsam (PyPI 4.2 — numpy-1.x only) blocks the numpy-2 bump
that `opencv-python>=4.12` requires at runtime. See
``_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md``;
the gate WILL be restored to `>= 4.12.0` once a numpy-2-compatible gtsam wheel
ships.
"""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
# D-CROSS-CVE-1 floor (relaxed; see module docstring + leftover).
MIN_VERSION = (4, 11, 0)
OPENCV_PACKAGES = ("opencv-python", "opencv-contrib-python")
def _parse_version(spec: str) -> tuple[int, ...]:
match = re.search(r"(\d+)\.(\d+)\.(\d+)", spec)
if match is None:
raise ValueError(f"Cannot parse a version from {spec!r}")
return tuple(int(g) for g in match.groups())
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="OpenCV >=4.12.0 pin gate.")
parser.add_argument("--pyproject", type=Path, default=Path("pyproject.toml"))
args = parser.parse_args(argv)
text = args.pyproject.read_text()
found: list[tuple[str, tuple[int, ...]]] = []
for pkg in OPENCV_PACKAGES:
for line in text.splitlines():
stripped = line.strip().strip(",").strip('"').strip("'")
if stripped.startswith(pkg):
spec = stripped[len(pkg) :].strip()
if spec.startswith((">=", "==", "~=", ">")):
spec = spec.lstrip(">=~<")
if not spec:
continue
try:
parsed = _parse_version(spec)
except ValueError:
continue
found.append((pkg, parsed))
if not found:
print("FAIL: no OpenCV pin found in pyproject.toml.", file=sys.stderr)
return 2
for pkg, version in found:
if version < MIN_VERSION:
print(
f"FAIL: {pkg}=={'.'.join(str(v) for v in version)} "
f"< required {'.'.join(str(v) for v in MIN_VERSION)} (D-CROSS-CVE-1).",
file=sys.stderr,
)
return 1
print(f"OK: {pkg} >= {'.'.join(str(v) for v in MIN_VERSION)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())