from __future__ import annotations from pathlib import Path from unittest.mock import patch import urllib.error import yaml from reuse_surface.federation import ( compose_federated_index, fetch_remote_index_text, load_federation_manifest, resolve_source_index_path, ) ROOT = Path(__file__).resolve().parent.parent REMOTE_INDEX = """ version: 1 domain: helix_forge updated: "2026-06-15" capabilities: - id: capability.remote.sample name: Remote Sample domain: helix_forge vector: D2/A0/C0/R0 owner: example path: registry/capabilities/capability.remote.sample.md summary: Sample capability from a remote index tags: [sample] consumption_modes: [planning] """ def _remote_manifest() -> dict: return { "version": 1, "domain": "helix_forge", "collision_policy": "warn", "sources": [ { "repo": "local", "index": "registry/indexes/capabilities.yaml", "enabled": True, "required": True, }, { "repo": "remote-repo", "url": "https://example.com/capabilities.yaml", "enabled": True, "required": False, "cache_ttl_seconds": 3600, }, ], } def test_manifest_with_url_source_validates(): manifest = _remote_manifest() schema_path = ROOT / "schemas" / "federation.schema.yaml" from jsonschema import Draft202012Validator schema = yaml.safe_load(schema_path.read_text(encoding="utf-8")) errors = list(Draft202012Validator(schema).iter_errors(manifest)) assert errors == [] def test_fetch_remote_index_text(): source = {"repo": "remote-repo", "url": "https://example.com/capabilities.yaml"} payload = REMOTE_INDEX.encode("utf-8") class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return payload with patch("urllib.request.urlopen", return_value=FakeResponse()): text = fetch_remote_index_text(source["url"], source) assert "capability.remote.sample" in text def test_remote_fetch_writes_cache(tmp_path, monkeypatch): monkeypatch.setattr("reuse_surface.federation.CACHE_DIR", tmp_path / "cache") source = { "repo": "remote-repo", "url": "https://example.com/capabilities.yaml", "cache_ttl_seconds": 3600, } payload = REMOTE_INDEX.encode("utf-8") class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return payload with patch("urllib.request.urlopen", return_value=FakeResponse()): path, warnings = resolve_source_index_path(source) assert path is not None assert warnings == [] assert path.exists() assert "capability.remote.sample" in path.read_text(encoding="utf-8") def test_remote_fetch_uses_fresh_cache_without_refetch(tmp_path, monkeypatch): monkeypatch.setattr("reuse_surface.federation.CACHE_DIR", tmp_path / "cache") source = { "repo": "remote-repo", "url": "https://example.com/capabilities.yaml", "cache_ttl_seconds": 3600, } payload = REMOTE_INDEX.encode("utf-8") class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return payload with patch("urllib.request.urlopen", return_value=FakeResponse()) as urlopen: resolve_source_index_path(source) path, warnings = resolve_source_index_path(source) assert warnings == [] assert path is not None urlopen.assert_called_once() def test_remote_fetch_falls_back_to_stale_cache(tmp_path, monkeypatch): monkeypatch.setattr("reuse_surface.federation.CACHE_DIR", tmp_path / "cache") source = { "repo": "remote-repo", "url": "https://example.com/capabilities.yaml", "cache_ttl_seconds": 0, } payload = REMOTE_INDEX.encode("utf-8") class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return payload with patch("urllib.request.urlopen", return_value=FakeResponse()): resolve_source_index_path(source) with patch( "urllib.request.urlopen", side_effect=urllib.error.URLError("network down"), ): path, warnings = resolve_source_index_path(source) assert path is not None assert any("stale cache" in warning for warning in warnings) def test_compose_merges_remote_capabilities(tmp_path, monkeypatch): monkeypatch.setattr("reuse_surface.federation.CACHE_DIR", tmp_path / "cache") source = { "repo": "remote-repo", "url": "https://example.com/capabilities.yaml", "enabled": True, "cache_ttl_seconds": 3600, } payload = REMOTE_INDEX.encode("utf-8") class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return payload manifest = _remote_manifest() with patch("urllib.request.urlopen", return_value=FakeResponse()): federated, warnings = compose_federated_index(manifest) ids = {item["id"] for item in federated["capabilities"]} assert "capability.remote.sample" in ids assert "capability.registry.register" in ids remote = next( item for item in federated["capabilities"] if item["id"] == "capability.remote.sample" ) assert remote["source_repo"] == "remote-repo" assert remote["source_url"] == "https://example.com/capabilities.yaml" def test_load_production_manifest_still_validates(): manifest = load_federation_manifest() assert manifest["domain"] == "helix_forge" assert any(source["repo"] == "reuse-surface" for source in manifest["sources"]) def _compose_with_remote_body(body: str, tmp_path, monkeypatch): """Compose with the remote member index serving `body` verbatim.""" monkeypatch.setattr("reuse_surface.federation.CACHE_DIR", tmp_path / "cache") payload = body.encode("utf-8") class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return payload with patch("urllib.request.urlopen", return_value=FakeResponse()): return compose_federated_index(_remote_manifest()) def _local_ids_survived(federated) -> bool: return any(item["source_repo"] == "local" for item in federated["capabilities"]) def test_compose_skips_capability_without_id(tmp_path, monkeypatch): body = """ version: 1 domain: helix_forge capabilities: - type: library title: No id at all - id: capability.remote.sample name: Remote Sample """ federated, warnings = _compose_with_remote_body(body, tmp_path, monkeypatch) ids = {item["id"] for item in federated["capabilities"]} assert "capability.remote.sample" in ids assert _local_ids_survived(federated) assert any("remote-repo" in w and "no id" in w for w in warnings) def test_compose_skips_non_mapping_index(tmp_path, monkeypatch): federated, warnings = _compose_with_remote_body( "just a string, not a mapping\n", tmp_path, monkeypatch ) assert _local_ids_survived(federated) assert any("not a mapping" in w for w in warnings) def test_compose_skips_empty_index(tmp_path, monkeypatch): federated, warnings = _compose_with_remote_body("", tmp_path, monkeypatch) assert _local_ids_survived(federated) assert any("remote-repo" in w for w in warnings) def test_compose_skips_unparseable_index(tmp_path, monkeypatch): federated, warnings = _compose_with_remote_body( "capabilities: [unclosed\n", tmp_path, monkeypatch ) assert _local_ids_survived(federated) assert any("unparseable" in w for w in warnings) def test_compose_skips_capabilities_not_a_list(tmp_path, monkeypatch): federated, warnings = _compose_with_remote_body( "version: 1\ncapabilities: not-a-list\n", tmp_path, monkeypatch ) assert _local_ids_survived(federated) assert any("not a list" in w for w in warnings) def test_malformed_source_still_listed_with_zero_count(tmp_path, monkeypatch): federated, _ = _compose_with_remote_body( "just a string, not a mapping\n", tmp_path, monkeypatch ) remote = next(s for s in federated["sources"] if s["repo"] == "remote-repo") assert remote["count"] == 0