Files
buzz/crates
Duncan cd0b9798f0 feat(nip-fi): introduce JwksSourceContract as required IssuerPolicy input
The three JWKS deployment fields (jwks_uri, refresh_interval_seconds,
key_snapshot_hard_deadline_seconds) were absent from AssertionPolicyId.
A different endpoint serves different keys; a looser hard deadline extends
the valid window beyond what the new policy intends. Both changes must
invalidate prepared evidence by moving the policy ID.

Introduce JwksSourceContract, a closed value type that:
- validates the URI (HTTPS, no credentials/fragment, no bare private-IP)
  and both timing fields (positive, bounded, refresh < deadline) at
  construction — invalid values are caught at config time, not at first
  token verification
- is the single source of truth for these fields; IssuerJwksConfig embeds
  it instead of independently restating the three values, eliminating the
  silent-drift hazard
- is a required parameter to IssuerPolicy::new, included in
  derive_assertion_policy_id after a domain separator; each of the three
  fields independently changes the policy ID when mutated (tested)

Startup validation replaces per-field URI/timing checks (now redundant
since JwksSourceContract::new performs them) with a contract mismatch
check — NipFiStartupError::JwksContractMismatch fires when the config
contract and policy contract drift apart.

Behavior tests added:
- assertion_policy_id_moves_when_jwks_uri_changes
- assertion_policy_id_moves_when_refresh_interval_changes
- assertion_policy_id_moves_when_hard_deadline_changes
- assertion_policy_id_is_stable_for_same_jwks_contract (determinism)
- key_rotation_does_not_change_assertion_policy_id
Each test carries a mutation comment naming the hash-omission that turns
it red.

JwksSourceContract exported from nip_fi/mod.rs and lib.rs.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-31 20:38:11 -04:00
..