#!/usr/bin/env bash set -euo pipefail # Prepare Export Center handoff metadata for mirror thin bundles and optionally schedule a run. # Usage (handoff only): # scripts/mirror/export-center-wire.sh # Usage (handoff + schedule when secrets exist): # EXPORT_CENTER_BASE_URL=https://export.example.com \ # EXPORT_CENTER_TOKEN=token123 \ # EXPORT_CENTER_TENANT=tenant-a \ # EXPORT_CENTER_AUTO_SCHEDULE=1 \ # scripts/mirror/export-center-wire.sh # Inputs: # - MILESTONE_PATH: path to milestone.json (default: out/mirror/thin/milestone.json) # - EXPORT_CENTER_OUT_DIR: output directory for handoff files (default: out/mirror/thin/export-center) # - EXPORT_CENTER_PROFILE_ID: profile identifier for the Export Center run (default: mirror:thin) # - EXPORT_CENTER_TARGETS_JSON: override targets array sent to Export Center (JSON array string) # - EXPORT_CENTER_FORMATS_JSON: override formats array (JSON array string; default: ["tar.gz","json","dsse"]) # - EXPORT_CENTER_AUTO_SCHEDULE: when "1", schedule a run using schedule-export-center-run.sh # - EXPORT_CENTER_BASE_URL / EXPORT_CENTER_TENANT / EXPORT_CENTER_PROJECT / EXPORT_CENTER_TOKEN: forwarded to scheduler # - EXPORT_CENTER_AUDIT_LOG: optional override for scheduler audit log path MILESTONE_PATH="${MILESTONE_PATH:-out/mirror/thin/milestone.json}" OUT_DIR="${EXPORT_CENTER_OUT_DIR:-out/mirror/thin/export-center}" PROFILE_ID="${EXPORT_CENTER_PROFILE_ID:-mirror:thin}" FORMATS_JSON="${EXPORT_CENTER_FORMATS_JSON:-[\"tar.gz\",\"json\",\"dsse\"]}" AUTO_SCHEDULE="${EXPORT_CENTER_AUTO_SCHEDULE:-0}" HANDOFF_PATH="${OUT_DIR}/export-center-handoff.json" TARGETS_PATH="${OUT_DIR}/export-center-targets.json" RESPONSE_PATH="${OUT_DIR}/schedule-response.json" export HANDOFF_PATH TARGETS_PATH RESPONSE_PATH PROFILE_ID MILESTONE_PATH mkdir -p "${OUT_DIR}" PROFILE_ID="${PROFILE_ID}" MILESTONE_PATH="${MILESTONE_PATH}" HANDOFF_PATH="${HANDOFF_PATH}" TARGETS_PATH="${TARGETS_PATH}" python3 - <<'PY' import datetime import json import os import sys from typing import Dict, Any milestone_path = os.environ["MILESTONE_PATH"] handoff_path = os.environ["HANDOFF_PATH"] targets_path = os.environ["TARGETS_PATH"] profile = os.environ.get("PROFILE_ID", "mirror:thin") try: with open(milestone_path, encoding="utf-8") as f: milestone = json.load(f) except FileNotFoundError: print(f"milestone file not found: {milestone_path}", file=sys.stderr) sys.exit(1) artifacts = [] def add_artifact(name: str, entry: Dict[str, Any] | None) -> None: if not isinstance(entry, dict): return path = entry.get("path") sha = entry.get("sha256") if path and sha: artifacts.append({"name": name, "path": path, "sha256": sha}) add_artifact("manifest", milestone.get("manifest")) add_artifact("manifest_dsse", milestone.get("dsse")) add_artifact("bundle", milestone.get("tarball")) add_artifact("bundle_meta", milestone.get("bundle")) add_artifact("bundle_meta_dsse", milestone.get("bundle_dsse")) add_artifact("time_anchor", milestone.get("time_anchor")) for name, entry in sorted((milestone.get("policies") or {}).items()): add_artifact(f"policy_{name}", entry) handoff = { "profileId": profile, "generatedAt": datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z"), "sourceMilestone": os.path.abspath(milestone_path), "artifacts": artifacts, } with open(handoff_path, "w", encoding="utf-8") as f: json.dump(handoff, f, indent=2) with open(targets_path, "w", encoding="utf-8") as f: json.dump([a["name"] for a in artifacts], f) PY ARTIFACTS_JSON=$(python3 - <<'PY' import json import os with open(os.environ["HANDOFF_PATH"], encoding="utf-8") as f: data = json.load(f) print(json.dumps(data.get("artifacts", []))) PY ) ARTIFACTS_JSON="${ARTIFACTS_JSON//$'\n'/}" TARGETS_JSON_DEFAULT=$(tr -d '\r\n' < "${TARGETS_PATH}") TARGETS_JSON="${EXPORT_CENTER_TARGETS_JSON:-$TARGETS_JSON_DEFAULT}" echo "[info] Export Center handoff written to ${HANDOFF_PATH}" echo "[info] Recommended targets: ${TARGETS_JSON}" schedule_note="AUTO_SCHEDULE=0" if [[ "${AUTO_SCHEDULE}" == "1" ]]; then schedule_note="missing EXPORT_CENTER_BASE_URL" if [[ -n "${EXPORT_CENTER_BASE_URL:-}" ]]; then export EXPORT_CENTER_ARTIFACTS_JSON="${ARTIFACTS_JSON}" schedule_note="scheduled" bash src/Mirror/StellaOps.Mirror.Creator/schedule-export-center-run.sh "${PROFILE_ID}" "${TARGETS_JSON}" "${FORMATS_JSON}" | tee "${RESPONSE_PATH}" fi fi if [[ ! -f "${RESPONSE_PATH}" ]]; then cat > "${RESPONSE_PATH}" <