#!/usr/bin/env bash set -euo pipefail base_url="${INTER_HUB_BASE_URL:-https://hub.coulomb.social}" base_url="${base_url%/}" tmpdir="$(mktemp -d)" trap 'rm -rf "$tmpdir"' EXIT request() { local name="$1" local url="$2" local expected_status="$3" local body="$tmpdir/${name}.json" local status status="$(curl -sS -o "$body" -w "%{http_code}" "$url")" if [[ "$status" != "$expected_status" ]]; then echo "ERROR: expected $url to return $expected_status, got $status" >&2 cat "$body" >&2 echo >&2 exit 1 fi echo "$body" } hubs_body="$(request hubs "${base_url}/api/v2/hubs" 200)" python3 - "$hubs_body" <<'PY' import json import sys with open(sys.argv[1], encoding="utf-8") as fh: payload = json.load(fh) if not isinstance(payload, dict) or not isinstance(payload.get("data"), list): raise SystemExit("/api/v2/hubs did not return a paginated data list") print("ok: /api/v2/hubs returned public discovery JSON") PY widgets_body="$(request widgets "${base_url}/api/v2/widgets" 401)" hub_registry_body="$(request hub-registry "${base_url}/api/v2/hub-registry" 401)" python3 - "$widgets_body" "$hub_registry_body" <<'PY' import json import sys for path, filename in ( ("/api/v2/widgets", sys.argv[1]), ("/api/v2/hub-registry", sys.argv[2]), ): with open(filename, encoding="utf-8") as fh: payload = json.load(fh) code = payload.get("code") if isinstance(payload, dict) else None if code != "invalid_api_key": raise SystemExit(f"{path} returned 401 but not invalid_api_key JSON") print(f"ok: {path} requires an API key") PY openapi_body="$(request openapi "${base_url}/api/v2/openapi.json" 200)" python3 - "$openapi_body" <<'PY' import json import sys required_paths = { "/hubs", "/hub-capability-manifests", "/api-consumers", "/policy-scopes", "/widgets", "/hub-registry", } with open(sys.argv[1], encoding="utf-8") as fh: payload = json.load(fh) paths = payload.get("paths") if not isinstance(paths, dict): raise SystemExit("/api/v2/openapi.json did not include an OpenAPI paths object") missing = sorted(required_paths - set(paths)) if missing: raise SystemExit("OpenAPI missing paths: " + ", ".join(missing)) print("ok: /api/v2/openapi.json lists expected v2 resources") PY