feat: add governed nationwide AOI orchestration and CUDA enforcement
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Jens
2026-07-26 05:23:33 +02:00
parent 25b6f1ab39
commit 2be72fac58
50 changed files with 1596 additions and 51 deletions
+43 -1
View File
@@ -2,13 +2,15 @@ from __future__ import annotations
import json
from pathlib import Path
import sys
from types import SimpleNamespace
from uuid import uuid4
import pytest
from app.core.config import Settings
from app.core.errors import AppError
from app.models import AnalysisRun, Dataset, Detection, Job, Project
from app.models import AnalysisRun, Area, Dataset, Detection, Job, Project
from app.services.detection_georeferencing import pixel_bbox_to_epsg4326_polygon
from app.services.detection_service import DetectionService
from app.services.model_registry_service import ModelRegistryService
@@ -235,6 +237,7 @@ def test_yolo_configured_model_reports_configured_with_local_model_and_dependenc
assert model.nationally_validated is False
assert model.operator_review_required is True
assert model.validated_regions == ["flanders_mol_kempen"]
assert model.supported_classes == ["building"]
assert "Mol and the Kempen" in (model.validation_scope or "")
@@ -246,6 +249,45 @@ def test_yolo_dependency_check_uses_real_imports_not_find_spec() -> None:
assert "import torch" in source
def test_yolo_runtime_fails_closed_when_cuda_is_required_but_unavailable(tmp_path: Path, monkeypatch) -> None:
settings = _settings(tmp_path, yolo_device="cuda:0", yolo_require_cuda=True)
monkeypatch.setitem(sys.modules, "torch", SimpleNamespace(cuda=SimpleNamespace(is_available=lambda: False)))
with pytest.raises(AppError) as exc_info:
YoloDetectionAdapter(settings).validate_runtime()
assert exc_info.value.code == "DETECTION_ACCELERATOR_UNAVAILABLE"
def test_yolo_runtime_rejects_cpu_device_when_cuda_is_required(tmp_path: Path, monkeypatch) -> None:
settings = _settings(tmp_path, yolo_device="cpu", yolo_require_cuda=True)
monkeypatch.setitem(sys.modules, "torch", SimpleNamespace(cuda=SimpleNamespace(is_available=lambda: True)))
with pytest.raises(AppError) as exc_info:
YoloDetectionAdapter(settings).validate_runtime()
assert exc_info.value.code == "DETECTION_ACCELERATOR_MISCONFIGURED"
def test_yolo_validation_scope_requires_persisted_validated_area(tmp_path: Path) -> None:
dataset = Dataset(id=uuid4(), project_id=uuid4(), name="image.tif", dataset_type="raster", source="test", area_id=uuid4())
wrong_area = Area(id=dataset.area_id, project_id=dataset.project_id, name="Brussels", geometry="MULTIPOLYGON EMPTY")
db = FakeSession(objects={(Area, dataset.area_id): wrong_area})
with pytest.raises(AppError) as exc_info:
DetectionService._validate_model_area_scope(db, dataset, _settings(tmp_path, yolo_validated_area_names="Mol,Kempen"))
assert exc_info.value.code == "DETECTION_VALIDATION_SCOPE_UNAVAILABLE"
def test_yolo_validation_scope_accepts_bound_mol_area(tmp_path: Path) -> None:
dataset = Dataset(id=uuid4(), project_id=uuid4(), name="image.tif", dataset_type="raster", source="test", area_id=uuid4())
area = Area(id=dataset.area_id, project_id=dataset.project_id, name="Gemeente Mol", geometry="MULTIPOLYGON EMPTY")
db = FakeSession(objects={(Area, dataset.area_id): area})
DetectionService._validate_model_area_scope(db, dataset, _settings(tmp_path, yolo_validated_area_names="Mol,Kempen"))
def test_yolo_run_requires_tile_manifest_path(tmp_path: Path) -> None:
db, project_id, dataset_id = _project_and_dataset()
settings = _settings(tmp_path)