Harden federated compose against malformed member indexes (REUSE-WP-0020)

Repointing the production hub's 50 Gitea-hosted federation sources to Forgejo
ahead of the 2026-08-31 CoulombCore retirement took /v1/federated to HTTP 500.
One member index (evidence-binder) has capability rows with no `id`, and
compose_federated_index dereferenced item["id"] unguarded. Its Gitea copy was a
stale snapshot returning a non-mapping, so those rows had never been parsed.

A single malformed member index must not take down the whole endpoint. Extract
_read_index_entries(): unparseable YAML, a non-mapping body, an empty file, and
a non-list `capabilities` each degrade to a warning and an empty row list, and
rows without an `id` are skipped individually. A failed source stays listed with
count 0 so it remains visible to operators rather than silently disappearing.

Also fix wall-clock rot in tests/test_plan_check.py, which was already failing
at clean HEAD: three tests pinned the compose date to a literal that has now
aged past STALE_DAYS.

Add workplan REUSE-WP-0020 covering the full cutover.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-21 00:04:39 +02:00
parent fa1235474f
commit 0c6b1e2538
5 changed files with 403 additions and 16 deletions

View file

@ -1,6 +1,20 @@
from __future__ import annotations
import json
from datetime import datetime, timedelta, timezone
from reuse_surface.plan_check import STALE_DAYS
def _recent_date() -> str:
"""A compose date that is always inside the staleness window.
A hardcoded literal here made the test rot: it passed when written and
began failing once wall-clock time drifted past STALE_DAYS.
"""
fresh = datetime.now(timezone.utc) - timedelta(days=max(STALE_DAYS - 1, 0))
return fresh.strftime("%Y-%m-%d")
from reuse_surface.plan_check import (
Match,
@ -93,7 +107,7 @@ Build a single interface for issue tracking across Gitea, GitHub, and GitLab.
def test_run_plan_check_reuse_verdict(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, "2026-07-06"),
lambda: (SAMPLE_CAPABILITIES, _recent_date()),
)
query = MatchQuery(
source="intent",
@ -236,7 +250,7 @@ def test_cmd_plan_check_file_request_flag(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, "2026-07-06"),
lambda: (SAMPLE_CAPABILITIES, _recent_date()),
)
filed_calls = []
monkeypatch.setattr(
@ -255,7 +269,7 @@ def test_cmd_plan_check_intent_json(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, "2026-07-06"),
lambda: (SAMPLE_CAPABILITIES, _recent_date()),
)
exit_code = main(
["plan-check", "--intent", "issue tracking gitea github gitlab", "--format", "json"]