Files
buzz/crates
Duncan 272dacadb2 fix(buzz-auth): complete SSRF policy, cancellation-safe permit, and invariant tests
Network policy (buzz-core):
- Rename is_private_ip → is_not_global_unicast; is_private_ip alias preserved for
  unowned callers. Registry source: IANA IPv4/IPv6 Special-Purpose Address Space
  (registries last updated 2025-10-09, retrieved 2026-08-31; URLs in source doc
  comment).
- Implement the IANA deny/exception table: outer predicate denies ranges whose
  registry entry is non-global or blank; explicit globally-reachable exceptions
  carved out inside otherwise-denied envelopes. IPv4 embedded in IPv4-mapped,
  IPv4-compatible, NAT64 well-known (64:ff9b::/96), and SIIT IPv4-translated space
  is evaluated recursively against the IPv4 table — registry global=True on the
  IPv6 wrapper does not bypass the embedded-address check.
- IPv4: add 192.0.0.0/24 IETF Protocol Assignments (global=False) with globally-
  reachable exceptions 192.0.0.9 (PCP anycast, RFC 7723) and 192.0.0.10 (TURN
  anycast, RFC 8155); add 192.88.99.0/24 deprecated 6to4 relay anycast (global=None
  — conservative posture: block).
- IPv6: replace individual Teredo/benchmarking/ORCHID checks with the 2001::/23
  IETF Protocol Assignments envelope (global=False). Globally-reachable exceptions
  inside the /23 are allowed: 2001:1::1/2/3 (PCP/TURN/DNS-SD anycast), 2001:3::/32
  (AMT), 2001:4:112::/48 (AS112-v6), 2001:20::/28 (ORCHIDv2, global=True),
  2001:30::/28 (DETs, global=True). Add 100:0:0:1::/64 dummy prefix (RFC 9780),
  3fff::/20 documentation (RFC 9637), 5f00::/16 SRv6 SIDs (RFC 9252).
  2001:db8::/32 (outside 2001::/23) remains a separate check.
- Consumer audit: buzz-workflow (CallWebhook) and desktop link_preview use the
  is_private_ip alias; the stricter predicate closes all new ranges for both callers.

Cancellation-safe refresh permit (buzz-auth):
- Per-issuer OwnedMutexGuard spans the complete fetch and state commit; cancelled
  callers release the permit on drop — no manual flag to poison.
- ScriptedFetcher replaces BlockingFetcher + SequencedFetcher: a VecDeque of
  FetchStep{entered, release} makes call order self-documenting without comments.
- concurrent_refresh_coalesces_without_second_fetch: entered barrier proves permit
  ownership before the second call; assert call_count == 1.
- aborted_first_caller_releases_permit_for_next_caller: pending_step returns the
  release sender, which is held until after abort — task is genuinely blocked (not
  resolved via error path) when cancelled. assert call_count == 2.

Central invariant regressions (buzz-auth):
- expired_snapshot_never_served_after_hard_deadline: hard-deadline expiry closes
  both the async and synchronous snapshot paths.
- two_issuer_keys_and_generations_are_isolated: advancing A's document advances
  A's generation only; B's key binding and generation are unchanged.

Architecture docs (ARCHITECTURE.md):
- Update is_private_ip function-table entry to is_not_global_unicast with compat alias.
- Rewrite SSRF Protection section: deny/exception-table framing, embedded-IPv4
  recursive evaluation, all three audited callers.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-31 19:43:33 -04:00
..