Automate RC8 release journeys
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:
Codex
2026-07-18 06:07:44 +02:00
parent 0fae53a7de
commit 55685ba1bd
22 changed files with 2665 additions and 11 deletions
+31
View File
@@ -1889,3 +1889,34 @@ python scripts/verify_python_lock.py
The complete gate and vulnerability/SBOM policy are documented in
`docs/CI_SUPPLY_CHAIN.md`.
## Release golden areas
The RC browser suite uses seven deterministic, bounded regression areas across
Belgium and the Belgian North Sea. Preview the required changes without
mutating the runtime:
```bash
python scripts/provision_release_golden_areas.py \
--base-url http://127.0.0.1:8000 \
--output artifacts/rc8-golden-areas.json
```
Create only missing Areas through the canonical project/area APIs:
```bash
python scripts/provision_release_golden_areas.py \
--base-url http://127.0.0.1:8000 \
--output artifacts/rc8-golden-areas.json \
--apply
```
The operator copies the governed Mol and Kempen geometries into the national
workbench with their source project/Area identifiers and provisions bounded
Wallonia, Brussels, language-boundary, coast and offshore multi-zone Areas.
Every geometry receives a deterministic SHA-256 fingerprint in the evidence
file. It never imports provider data or writes directly to database tables.
Explicit demo seeding also reactivates its own archived technical project.
This keeps the opt-in fixture workflow selectable without changing the normal
active-project lifecycle.
+14 -1
View File
@@ -102,6 +102,16 @@ class DemoWorkflowService:
return project
return projects[0] if projects else None
@staticmethod
def _activate_explicit_demo_project(db: Session, project: Project | None) -> Project | None:
if project is None or project.status == "active":
return project
project.status = "active"
db.add(project)
db.commit()
db.refresh(project)
return project
@staticmethod
def _has_complete_demo_state(db: Session, project_id: UUID) -> bool:
area = db.query(Area).filter(Area.project_id == project_id).first()
@@ -398,7 +408,10 @@ class DemoWorkflowService:
@staticmethod
def seed(db: Session) -> DemoWorkflowResponse:
existing = DemoWorkflowService._find_existing_project(db)
existing = DemoWorkflowService._activate_explicit_demo_project(
db,
DemoWorkflowService._find_existing_project(db),
)
reference_payload, reference_raw = DemoWorkflowService._load_fixture("reference_buildings.geojson")
candidate_payload, candidate_raw = DemoWorkflowService._load_fixture("predicted_buildings.geojson")
if existing:
@@ -0,0 +1,74 @@
from __future__ import annotations
import importlib.util
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
SCRIPT_PATH = ROOT / "scripts" / "provision_release_golden_areas.py"
def load_operator():
spec = importlib.util.spec_from_file_location("provision_release_golden_areas_test", SCRIPT_PATH)
assert spec and spec.loader
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def test_release_golden_area_contract_covers_belgium_and_north_sea() -> None:
module = load_operator()
created_keys = {item["key"] for item in module.GOLDEN_AREAS}
source_keys = {item["key"] for item in module.SOURCE_AREAS}
assert created_keys == {
"wallonia_urban_rural",
"brussels_urban",
"language_boundary",
"coast_land_sea",
"north_sea_multi_zone",
}
assert source_keys == {"mol_municipality", "kempen_region"}
assert len(created_keys | source_keys) == 7
assert all(item["source_project"] != module.NATIONAL_PROJECT for item in module.SOURCE_AREAS)
expected_zones = {
zone
for definition in (*module.GOLDEN_AREAS, *module.SOURCE_AREAS)
for zone in definition["expected_zones"]
}
assert {
"flanders",
"wallonia",
"brussels",
"territorial_sea",
"exclusive_economic_zone",
"continental_shelf",
} <= expected_zones
def test_release_golden_area_geometries_are_bounded_and_fingerprintable() -> None:
module = load_operator()
hashes = set()
for definition in module.GOLDEN_AREAS:
bbox = module.geometry_bbox(definition["geometry"])
assert -180 <= bbox["minx"] < bbox["maxx"] <= 180
assert -90 <= bbox["miny"] < bbox["maxy"] <= 90
assert bbox["maxx"] - bbox["minx"] <= 0.25
assert bbox["maxy"] - bbox["miny"] <= 0.20
digest = module.canonical_hash(definition["geometry"])
assert len(digest) == 64
hashes.add(digest)
assert len(hashes) == len(module.GOLDEN_AREAS)
def test_rc8_runner_and_container_operator_are_release_wired() -> None:
readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
dockerfile = (ROOT / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8")
package = (ROOT / "frontend" / "package.json").read_text(encoding="utf-8")
assert "npm run test:unit" in readiness
assert '--check frontend/e2e/releaseJourneys.mjs' in readiness
assert "bash -n scripts/run_rc8_release_journeys.sh" in readiness
assert "COPY scripts/provision_release_golden_areas.py" in dockerfile
assert '"test:e2e": "node e2e/releaseJourneys.mjs"' in package
@@ -5,6 +5,7 @@ from uuid import uuid4
from fastapi.testclient import TestClient
from app.main import app
from app.models import Project
from app.schemas.demo import DemoWorkflowResponse
from app.services.demo_workflow_service import DemoWorkflowService
@@ -80,3 +81,30 @@ def test_demo_workflow_prefers_complete_existing_demo_project() -> None:
assert "order_by(Project.created_at.asc())" in service
assert "if DemoWorkflowService._has_complete_demo_state(db, project.id):" in service
assert "return projects[0] if projects else None" in service
def test_explicit_demo_seed_reactivates_an_archived_fixture_project() -> None:
project = Project(id=uuid4(), name=DemoWorkflowService.PROJECT_NAME, status="archived")
class Session:
added = []
commits = 0
refreshed = []
def add(self, value) -> None:
self.added.append(value)
def commit(self) -> None:
self.commits += 1
def refresh(self, value) -> None:
self.refreshed.append(value)
db = Session()
result = DemoWorkflowService._activate_explicit_demo_project(db, project)
assert result is project
assert project.status == "active"
assert db.added == [project]
assert db.commits == 1
assert db.refreshed == [project]