Initial public release
GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s

This commit is contained in:
Jens
2026-08-31 21:56:53 +02:00
commit faeb58ef6d
1386 changed files with 263203 additions and 0 deletions
@@ -0,0 +1,217 @@
from __future__ import annotations
from hashlib import sha256
import importlib.util
import json
from pathlib import Path
from uuid import uuid4
from app.services.runtime_model_provenance_service import RuntimeModelProvenanceService
ROOT = Path(__file__).resolve().parents[2]
SCRIPT = ROOT / "scripts" / "migrate_runtime_model_provenance.py"
SPEC = importlib.util.spec_from_file_location("migrate_runtime_model_provenance", SCRIPT)
assert SPEC and SPEC.loader
module = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(module)
def _sha(value: bytes) -> str:
return sha256(value).hexdigest()
def _args(tmp_path: Path):
model = tmp_path / "active.pt"
checkpoint = tmp_path / "best.pt"
base_model = tmp_path / "base.pt"
training_args = tmp_path / "args.yaml"
training_results = tmp_path / "results.csv"
dataset_summary = tmp_path / "dataset-summary.json"
dataset_yaml = tmp_path / "dataset.yaml"
training_summary = tmp_path / "training-summary.json"
model.write_bytes(b"exact promoted model bytes")
checkpoint.write_bytes(model.read_bytes())
base_model.write_bytes(b"exact base model bytes")
training_args.write_text("epochs: 30\nseed: 0\n", encoding="utf-8")
training_results.write_text("epoch,metric\n1,0.1\n", encoding="utf-8")
dataset_yaml.write_text("names:\n 0: building\n", encoding="utf-8")
dataset_summary.write_text(
json.dumps(
{
"status": "ok",
"class_names": ["building"],
"tile_count": 198,
"train_tile_count": 180,
"val_tile_count": 18,
"label_count": 58_820,
}
),
encoding="utf-8",
)
training_summary.write_text(
json.dumps(
{
"status": "ok",
"trained_model_sha256": _sha(model.read_bytes()),
"base_model_sha256": _sha(base_model.read_bytes()),
"dataset_summary_sha256": _sha(dataset_summary.read_bytes()),
"dataset_yaml_sha256": _sha(dataset_yaml.read_bytes()),
}
),
encoding="utf-8",
)
return module.parse_args(
[
"--model-path",
str(model),
"--checkpoint-path",
str(checkpoint),
"--base-model-path",
str(base_model),
"--training-summary-path",
str(training_summary),
"--training-args-path",
str(training_args),
"--training-results-path",
str(training_results),
"--dataset-summary-path",
str(dataset_summary),
"--dataset-yaml-path",
str(dataset_yaml),
"--source-version",
"sprint174-smallbld-minpx3-img640-ft30",
"--framework-version",
"8.4.93",
]
)
def test_recovered_evidence_requires_byte_identical_checkpoint_and_recorded_hashes(tmp_path: Path) -> None:
args = _args(tmp_path)
evidence = module.inspect_evidence(args)
assert evidence["checksums"]["model"] == evidence["checksums"]["checkpoint"]
assert evidence["checksums"]["training_summary"] == _sha(
Path(args.training_summary_path).read_bytes()
)
assert evidence["class_mapping"] == {"0": "building"}
def test_recovered_evidence_rejects_changed_checkpoint(tmp_path: Path) -> None:
args = _args(tmp_path)
Path(args.checkpoint_path).write_bytes(b"other checkpoint")
exit_code, payload = module.migrate(args)
assert exit_code == 2
assert payload["status"] == "evidence_invalid"
assert "checkpoint/model SHA-256 mismatch" in payload["message"]
def test_generated_sidecar_passes_exact_runtime_contract(tmp_path: Path) -> None:
args = _args(tmp_path)
evidence = module.inspect_evidence(args)
payload = module._manifest_payload(
args=args,
evidence=evidence,
source_registry_id=str(uuid4()),
source_snapshot_id=str(uuid4()),
imported_at="2026-08-23T21:00:00+00:00",
)
manifest_path = RuntimeModelProvenanceService.manifest_path_for_model(args.model_path)
assert module._write_manifest_atomically(manifest_path, payload) is True
validated = RuntimeModelProvenanceService.validate_for_runtime(
model_path=args.model_path,
model_id="yolo-configured",
task_type="object_detection",
expected_model_version="sprint174-smallbld-minpx3-img640-ft30",
allowed_frameworks=("ultralytics/pytorch",),
)
assert validated.model_sha256 == evidence["checksums"]["model"]
assert validated.runtime_manifest_sha256 == payload["metadata"]["runtime_manifest_sha256"]
assert module._write_manifest_atomically(manifest_path, payload) is False
def test_model_registry_definition_is_runtime_ready_without_mutating_server_owned_row() -> None:
from app.services.source_registry_service import SourceRegistryService
definition = SourceRegistryService.definition_for("model")
assert definition.ingest_status == "configured"
assert definition.freshness_status == "current"
script = SCRIPT.read_text(encoding="utf-8")
assert 'source.ingest_status = "configured"' not in script
assert 'source.freshness_status = "current"' not in script
def test_model_registry_status_migration_is_narrow_and_restores_write_guard() -> None:
migration = (
ROOT
/ "backend"
/ "alembic"
/ "versions"
/ "202608230001_configure_model_source_registry.py"
).read_text(encoding="utf-8")
assert "WHERE source_key = 'model'" in migration
assert "registry_owner' = 'server'" in migration
assert migration.count("DISABLE TRIGGER trg_source_registry_write_guard") == 1
assert migration.count("ENABLE TRIGGER trg_source_registry_write_guard") == 1
assert 'down_revision = "202608010001"' in migration
def test_recovery_receipt_requires_hashed_backup_inventory(tmp_path: Path) -> None:
args = _args(tmp_path)
evidence = module.inspect_evidence(args)
receipt = tmp_path / "dry-run.json"
receipt.write_text(
json.dumps(
{
"status": "ready_to_apply",
"claim_boundary": module.CLAIM_BOUNDARY,
"evidence": evidence,
}
),
encoding="utf-8",
)
storage_manifest = tmp_path / "storage-manifest.tsv"
missing_names = ("checkpoint", "training_summary", "training_args", "training_results")
rows = ["relative_path\tsize_bytes\tmtime_ns\tsha256"]
for name in missing_names:
original = Path(evidence["paths"][name])
evidence["paths"][name] = f"/app/storage/training/{original.name}"
rows.append(f"training/{original.name}\t1\t0\t{evidence['checksums'][name]}")
receipt.write_text(
json.dumps(
{
"status": "ready_to_apply",
"claim_boundary": module.CLAIM_BOUNDARY,
"evidence": evidence,
}
),
encoding="utf-8",
)
storage_manifest.write_text("\n".join(rows) + "\n", encoding="utf-8")
backup_checksums = tmp_path / "CHECKSUMS.sha256"
backup_checksums.write_text(
f"{_sha(storage_manifest.read_bytes())} storage-manifest.tsv\n",
encoding="utf-8",
)
args.evidence_receipt_path = str(receipt)
args.backup_storage_manifest_path = str(storage_manifest)
args.backup_checksums_path = str(backup_checksums)
recovered = module.inspect_evidence(args)
assert recovered["checksums"] == evidence["checksums"]
assert recovered["recovery_receipt"]["missing_artifacts_not_recreated"] == list(missing_names)
storage_manifest.write_text(storage_manifest.read_text(encoding="utf-8") + "tampered\n", encoding="utf-8")
exit_code, payload = module.migrate(args)
assert exit_code == 2
assert "backup storage manifest SHA-256 mismatch" in payload["message"]