reuse-surface/docs/assessments/cust81-private-reader/owner-review-r1.md
tegwick b181240b35 Protect authenticated federation sources with exact runtime URL bindings
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a137ca-5c77-7a71-b9ae-23ad9b0b5684
2026-10-15 01:25:49 +02:00

6.3 KiB

Reuse-surface independent consumer preparation review

Disposition: changes_requested for reader provisioning proposal CUST81-PRIVATE-READER-PROVISIONING-PREPARATION-R1, SHA256 7819eb51d249f5c7aff4df9fb520afcfb76603b05a4104439499102b6c20af99. Reviewer: delegated reuse-surface owner preparation worker, supervised local scope. This review does not authorize credentials, approve another owner's implementation, claim deployment success, or grant permanent repo authority.

INTENT requires inspectable registry membership and evidence-driven consumer reliability. Acquisition must protect source custody while making the explicitly consented metadata discoverable. The proposal's seven-repository reader, separate KV path and exact commit pins fit that purpose, but its unchanged-image rollout assumption fails consumer credential isolation.

Findings and prepared correction

  1. Native fetch_remote_index_text originally supplies Authorization to urllib's default opener. Redirect handling copies headers to the redirect target. A source redirect can disclose the PAT to another origin or unreviewed path. Prepared patch rejects all authenticated redirects, even same-origin ones. Anonymous federation keeps its previous behavior.
  2. Hub registration accepts caller-selected auth_env, auth_header and url. Composition passes these to _auth_headers, which reads the named runtime env and sends its value to that URL. A holder of the writer token can therefore induce credential exfiltration without a redirect. Prepared patch validates operator-owned REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST JSON before looking up the credential. Exact allowed env name and URL are mandatory; missing/malformed configuration fails closed. Authenticated HTTP is rejected.
  3. resolve_source_index_path(refresh=True) may return stale cache after remote failure. A fresh composition timestamp alone cannot prove private acquisition. Prepared helper calls native fetch directly, never the resolver/cache path, and verifies exact consented index and Markdown entry SHA256 plus capability identity, owner and entry schema. Failed receipts contain bounded categories, never raw exception text, bodies, headers, or secrets.

Exact prepared artifacts

  • reuse_surface/federation.py SHA256 dbaa40f25cc0f090143578cd1c7068cb2cb00960fafd17d5239bf8a5bac514dd
  • reuse_surface/private_source_verify.py SHA256 c67a284091cc4dd62dca56658a14b8ea1357e2b3df1518120da4c51e0ee8d85c
  • tests/test_private_source_verify.py SHA256 5f0c0b30b98b4db96d695bdda952b25707916e297d566744fadb6dde7bea18b2
  • runtime-auth-source-allowlist-r1.json SHA256 e1948c537e206b30fc72b9e4732a3f600d92e131813e6f7ecfd4bfbb18c27286 is the exact fourteen commit-pinned index/entry URLs for reader env REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN. Serialize this object as the runtime value of REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST; do not use host wildcards.

Validation and limits

Focused fake transport tests cover native Bearer header handling, all fourteen fetches, no cache path, mismatched index/entry hashes, tampered consent packet, missing authentication, sanitized errors, same/cross-origin redirects without second requests, HTTP rejection, missing/malformed/unapproved allowlists, and broadened reader URL scope. Focused tests: 30 passed. Whole test suite initially reported 226 passed, 1 failed: existing test_federation_compose resolved a required sibling index to missing /tmp/access-engine/registry/indexes/capabilities.yaml. The first sibling fixture preparation also stopped at maturity-engine's untracked registry index, and that partial fixture run reported 226 passed, 1 failed. Both outcomes remain in suite-environment-validation.json; no consumer test failure or failed preparation is hidden.

With the complete task-owned fixture environment, the unchanged source patch passes the entire suite: 227 passed, 1 existing dependency warning. Command: /home/worsch/reuse-surface/.venv/bin/python -m pytest -q tests, cwd /tmp/cust81-reuse-suite-fixtures-r1/reuse-surface. That fixture contains sixty required local registry indexes and thirty-nine seeded anonymous caches to avoid live network dependencies. Fifty-nine local indexes are copied from committed HEAD; maturity-engine's existing untracked index is copied read-only and labeled as a test fixture, never publication evidence. Member indexes are only read; composition writes its own copied registry/cache. No foreign checkout is written. Tests rewrite generated catalog/graph files in their own fixture checkout; earlier generated changes in the integration checkout were restored to its HEAD.

local-consented-metadata-validation.json proves schema and exact hashes for all seven repositories' consented committed metadata using a fake transport and a fixture-only token. It is explicitly not a network, credential, rollout or live federation verification receipt.

Static registry/federation/sources.yaml contains no auth_env, but public hub registration responses intentionally omit it and do not prove live SQLite dynamic source inventory. This patch changes authenticated-source behavior: every existing authenticated lane needs a reviewed exact-URL allowlist entry. Before rollout, platform/apps must safely inventory only auth env names and registered URLs, preserve approved existing lanes in runtime config, and prove no unrelated runtime secret name can be routed. No raw env dump or Secret read is required for that inventory. Until this migration and the reviewed new consumer image are complete, do not deliver the new PAT to the existing hub image.

After separate exact credential/rollout approval, invoke the helper from inside the hub process environment with the pinned proposal/disclosure/consent files:

python -m reuse_surface.private_source_verify --proposal /review/private-reader-provisioning-preparation-r1.json --disclosure /review/private-source-disclosure-proposal-r1.json --consent /review/private-source-owner-consent-r1.json

It accepts no credential argument and returns only bounded metadata receipts. Exit zero means all seven native index/entry fetches matched pinned consent; it does not prove registration/federation completion. Final admission still needs separate live source registrations and exact 70-ID fresh hosted audit.