Implement WP-0011 hub service, CLI, and deployment artifacts
Some checks failed
ci / validate-registry (push) Has been cancelled

Add FederationHubAPI spec, hub registration schema, FastAPI hub with SQLite
persistence, reuse-surface hub CLI client, Dockerfile, and hub tests. Activate
workplan; T05 deploy and T06 ops docs remain open pending railiance01 cutover.
This commit is contained in:
2026-06-15 08:48:06 +02:00
parent b9a406feee
commit ea5918b1e6
17 changed files with 1222 additions and 17 deletions

View File

@@ -56,9 +56,14 @@ def _path_label(path: Path) -> str:
return str(path)
def _cache_paths(repo: str) -> tuple[Path, Path]:
def _cache_root(cache_dir: Path | None = None) -> Path:
return cache_dir or CACHE_DIR
def _cache_paths(repo: str, cache_dir: Path | None = None) -> tuple[Path, Path]:
root = _cache_root(cache_dir)
slug = _safe_repo_slug(repo)
return CACHE_DIR / f"{slug}.yaml", CACHE_DIR / f"{slug}.meta.yaml"
return root / f"{slug}.yaml", root / f"{slug}.meta.yaml"
def _read_cache_meta(meta_path: Path) -> dict[str, Any] | None:
@@ -114,9 +119,12 @@ def fetch_remote_index_text(url: str, source: dict[str, Any]) -> str:
) from exc
def _write_remote_cache(repo: str, url: str, content: str) -> Path:
CACHE_DIR.mkdir(parents=True, exist_ok=True)
index_path, meta_path = _cache_paths(repo)
def _write_remote_cache(
repo: str, url: str, content: str, cache_dir: Path | None = None
) -> Path:
root = _cache_root(cache_dir)
root.mkdir(parents=True, exist_ok=True)
index_path, meta_path = _cache_paths(repo, cache_dir)
index_path.write_text(content, encoding="utf-8")
meta = {
"fetched_at": datetime.now(timezone.utc).isoformat(),
@@ -131,6 +139,7 @@ def resolve_source_index_path(
source: dict[str, Any],
*,
refresh: bool = False,
cache_dir: Path | None = None,
) -> tuple[Path | None, list[str]]:
warnings: list[str] = []
if "index" in source:
@@ -145,7 +154,7 @@ def resolve_source_index_path(
url = source["url"]
ttl_seconds = int(source.get("cache_ttl_seconds", DEFAULT_CACHE_TTL_SECONDS))
index_path, meta_path = _cache_paths(source["repo"])
index_path, meta_path = _cache_paths(source["repo"], cache_dir)
meta = _read_cache_meta(meta_path)
use_cache = (
index_path.exists()
@@ -171,13 +180,14 @@ def resolve_source_index_path(
warnings.append(message)
return None, warnings
return _write_remote_cache(source["repo"], url, content), warnings
return _write_remote_cache(source["repo"], url, content, cache_dir), warnings
def compose_federated_index(
manifest: dict[str, Any] | None = None,
*,
refresh: bool = False,
cache_dir: Path | None = None,
) -> tuple[dict[str, Any], list[str]]:
manifest = manifest or load_federation_manifest()
warnings: list[str] = []
@@ -189,7 +199,7 @@ def compose_federated_index(
if not source.get("enabled", False):
continue
index_path, source_warnings = resolve_source_index_path(
source, refresh=refresh
source, refresh=refresh, cache_dir=cache_dir
)
warnings.extend(source_warnings)
if index_path is None: