mirror of
https://github.com/block/buzz.git
synced 2026-11-05 08:51:10 +00:00
Four production-blocking defects identified in Carl's Pass 1 review, plus the fourth issue (policy ID / JWKS config fields) reported as a contract question requiring design decision before implementation: 1. Arc<S> forwarding IssuerKeySource impl: FederatedAssertionVerifier<S> consumed S by value, making ProductionJwksSource (not Clone) non-shareable across verifiers. Add sealed::Sealed blanket for Arc<S> and IssuerKeySource for Arc<S>, forwarding to the inner source. Shared-rotation regression test proves one long-lived verifier observes key rotation through a shared Arc cache; the mutation (no sharing) turns the test red. 2. IPv6 host normalization: fetch_jwks_inner called Url::host_str() which returns bracket-wrapped IPv6 literals (e.g. '[2606:4700::1]'). IpAddr::parse fails on bracketed form, falling to DNS; reqwest resolve() keyed on bracketed host doesn't match the URL authority, bypassing DNS pinning. Fix: use typed Url::host() and stringify Ipv6Addr without brackets. Tests verify loopback and fec0::1 site-local URIs are rejected as InvalidUri via the correct SSRF-check path. 3. fec0::/10 deprecated site-local: is_not_global_unicast didn't block fec0::/10 (RFC 3879 deprecated IPv6 site-local). Add the predicate and table-driven tests confirming fec0::1 through feff::1 are blocked; verify boundary addresses. All three existing callers (JWKS, webhook, link-preview) inherit the stricter predicate by construction. Issue 4 (IssuerPolicy::id() missing JWKS endpoint/timing fields): IssuerJwksConfig fields live outside IssuerPolicy; folding them into the existing id() would change the settled identity contract. Two minimal options reported to Paul for product decision before implementing. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>