#!/usr/bin/env bash set -euo pipefail BASE_URL="${1:-${GE_INTEL_BASE_URL:-http://localhost:1202}}" TMP_DIR="$(mktemp -d)" trap 'rm -rf "${TMP_DIR}"' EXIT if ! command -v curl >/dev/null 2>&1; then echo "curl is required for workbench default-state verification" >&2 exit 1 fi if [ -n "${PYTHON_BIN:-}" ]; then PYTHON_BIN="${PYTHON_BIN}" else PYTHON_BIN="" for candidate in python3 python.exe python; do if command -v "${candidate}" >/dev/null 2>&1 && "${candidate}" -c "import json, sys" >/dev/null 2>&1; then PYTHON_BIN="${candidate}" break fi done fi if [ -z "${PYTHON_BIN}" ]; then echo "A Python interpreter is required for JSON parsing" >&2 exit 1 fi require_json_data() { local file_path="$1" "${PYTHON_BIN}" - "$file_path" <<'PY' import json import sys with open(sys.argv[1], "r", encoding="utf-8") as handle: payload = json.load(handle) if "data" not in payload: raise SystemExit("Response is not a canonical GeoIntel data envelope") PY } json_field() { local file_path="$1" local expression="$2" "${PYTHON_BIN}" - "$file_path" "$expression" <<'PY' import json import sys path, expression = sys.argv[1], sys.argv[2] with open(path, "r", encoding="utf-8") as handle: payload = json.load(handle) value = payload for part in expression.split("."): if part: value = value[part] print(value) PY } echo "== GeoIntel workbench default-state verification ==" echo "Base URL: ${BASE_URL}" frontend_status="$(curl -fsS -o "${TMP_DIR}/index.html" -w "%{http_code}" "${BASE_URL%/}" 2>/dev/null || true)" if [ "${frontend_status}" != "200" ]; then echo "Frontend returned HTTP ${frontend_status:-none}, expected 200" >&2 exit 1 fi if ! grep -q '
&2 exit 1 fi curl -fsS -X POST "${BASE_URL%/}/api/v1/demo/workflow" > "${TMP_DIR}/demo.json" require_json_data "${TMP_DIR}/demo.json" project_id="$(json_field "${TMP_DIR}/demo.json" "data.project_id")" area_id="$(json_field "${TMP_DIR}/demo.json" "data.area_id")" candidate_dataset_id="$(json_field "${TMP_DIR}/demo.json" "data.candidate_dataset_id")" reference_dataset_id="$(json_field "${TMP_DIR}/demo.json" "data.reference_dataset_id")" raster_dataset_id="$(json_field "${TMP_DIR}/demo.json" "data.raster_dataset_id")" quality_check_id="$(json_field "${TMP_DIR}/demo.json" "data.quality_check_id")" curl -fsS "${BASE_URL%/}/api/v1/projects" > "${TMP_DIR}/projects.json" require_json_data "${TMP_DIR}/projects.json" # The workbench lists below must all use canonical data.items envelopes. "${PYTHON_BIN}" - "${TMP_DIR}/projects.json" "${project_id}" <<'PY' import json import sys path, project_id = sys.argv[1], sys.argv[2] with open(path, "r", encoding="utf-8") as handle: payload = json.load(handle) items = payload["data"]["items"] matches = [item for item in items if item["id"] == project_id] if not matches: raise SystemExit("Seeded demo project is missing from project list") project = matches[0] if project.get("name") != "GeoIntel Demo - Building QA": raise SystemExit(f"Unexpected default demo project name: {project.get('name')}") PY curl -fsS "${BASE_URL%/}/api/v1/projects/${project_id}/areas" > "${TMP_DIR}/areas.json" require_json_data "${TMP_DIR}/areas.json" "${PYTHON_BIN}" - "${TMP_DIR}/areas.json" "${area_id}" <<'PY' import json import sys path, area_id = sys.argv[1], sys.argv[2] with open(path, "r", encoding="utf-8") as handle: payload = json.load(handle) items = payload["data"]["items"] matches = [item for item in items if item["id"] == area_id] if not matches: raise SystemExit("Seeded demo AOI is missing from project area list") area = matches[0] if area.get("name") != "Demo AOI - Geel buildings": raise SystemExit(f"Unexpected demo AOI name: {area.get('name')}") geometry = area.get("geometry") if not geometry or geometry.get("type") not in {"Polygon", "MultiPolygon"}: raise SystemExit("Demo AOI does not expose map-ready GeoJSON geometry") PY curl -fsS "${BASE_URL%/}/api/v1/projects/${project_id}/datasets" > "${TMP_DIR}/datasets.json" require_json_data "${TMP_DIR}/datasets.json" "${PYTHON_BIN}" - "${TMP_DIR}/datasets.json" "${candidate_dataset_id}" "${reference_dataset_id}" "${raster_dataset_id}" <<'PY' import json import sys path, candidate_id, reference_id, raster_id = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4] with open(path, "r", encoding="utf-8") as handle: payload = json.load(handle) items = payload["data"]["items"] ids = {item["id"]: item for item in items} if candidate_id not in ids: raise SystemExit("Candidate fixture dataset is missing from default workbench dataset list") if reference_id not in ids: raise SystemExit("Reference fixture dataset is missing from default workbench dataset list") if raster_id not in ids: raise SystemExit("Raster fixture dataset is missing from default workbench dataset list") if ids[candidate_id].get("status") != "ready" or ids[reference_id].get("status") != "ready" or ids[raster_id].get("status") != "ready": raise SystemExit("Expected 3/3 ready demo datasets") if ids[reference_id].get("dataset_role") != "reference": raise SystemExit("Default workbench reference dataset is not marked as reference") if ids[raster_id].get("dataset_type") != "raster" or ids[raster_id].get("source_name") != "fixture": raise SystemExit("Default workbench raster fixture lost its raster/source metadata") PY curl -fsS "${BASE_URL%/}/api/v1/projects/${project_id}/quality-checks" > "${TMP_DIR}/quality_checks.json" require_json_data "${TMP_DIR}/quality_checks.json" "${PYTHON_BIN}" - "${TMP_DIR}/quality_checks.json" "${quality_check_id}" <<'PY' import json import sys path, quality_check_id = sys.argv[1], sys.argv[2] with open(path, "r", encoding="utf-8") as handle: payload = json.load(handle) items = payload["data"]["items"] matches = [item for item in items if item["id"] == quality_check_id] if not matches: raise SystemExit("Seeded QA/QC check is missing from default workbench quality list") quality_check = matches[0] if quality_check.get("status") != "ok": raise SystemExit(f"Unexpected default workbench QA/QC status: {quality_check.get('status')}") metrics = {metric["metric_key"]: metric.get("metric_value") for metric in quality_check.get("metrics", [])} for key in ("precision", "recall", "f1", "mean_iou"): if key not in metrics: raise SystemExit(f"Default workbench QA/QC metric is missing: {key}") PY echo "Workbench default state verification passed" echo "Project: GeoIntel Demo - Building QA" echo "Area: Demo AOI - Geel buildings" echo "Datasets: 3/3 ready" echo "QA/QC: seeded check is available"