BoundedAuthorityReportAdapter.Conformance.VectorCase (Bounded Authority Report Adapter v0.5.0)

Copy Markdown View Source

TEST-ONLY loader + builder for RA2's conformance round-trip harness.

Loads BAP's published grant-holder-proof.json vector (at the pinned dep ref) once, decodes it, and builds the ExpectedRequest (bars i / iii / iv) / ExpectedGrant (bar i-grant) / TrustedIssuer structs BAP's check_envelope/2 + verify_grant/3 consume.

The three non-obvious pieces (design §1.6 — all first-hand verified)

  • (A) Typed-tuple translation. cast_arguments MUST be BAP's tagged Json.value() form, not a raw map. The vector carries the typed form as a JSON array ["type", value]; Tag.from_json/1 translates it. No type guard on the object/array arms — :json.decode yields maps for JSON objects, and Enum.map over a map yields {k,v} tuples.
  • (B) Synthesized :bounds. The vector's expected_context carries no bounds; the structs require it (@enforce_keys). V1.Bounds.maximum/0 is synthesized (BAP's default).
  • (C) Per-case nonce derivation. The shared expected_context.nonce is {"required": "challenge-001"}, but positive_cases.nonce_absent is a declared-VALID case whose proof payload carries NO nonce. Deriving the nonce expectation from the SHARED context reds that case; the expectation is derived PER CASE from the proof payload's nonce presence.

The selector_denied sub-cases carry their OWN typed_cast_arguments (a different ba_req), so cast_arguments is derived per case when present.

Summary

Functions

The expected_context block (shared across the published cases).

Builds an %ExpectedGrant{} for bar (i-grant) — the grant-only verifier surface. No nonce field on ExpectedGrant; bounds synthesized.

Builds an %ExpectedRequest{} for a published case.

The 32-byte raw issuer public key — the verifier's TRUST ANCHOR.

The %TrustedIssuer{} from the vector's expected_context.

The tagged Json.value() form of the vector's top-level cast_arguments, via Tag.from_json/1. Verified: RequestDigest.digest_raw of this value matches the vector's published ba_req.

The decoded published vector.

Functions

expected_context()

The expected_context block (shared across the published cases).

expected_grant()

Builds an %ExpectedGrant{} for bar (i-grant) — the grant-only verifier surface. No nonce field on ExpectedGrant; bounds synthesized.

expected_request(case)

Builds an %ExpectedRequest{} for a published case.

case is either :top_level (the top-level envelope) or a case map from the vector (received_member_order_variant, a positive_cases / negative_cases entry, a selector_denied sub-case). The builder:

  • derives cast_arguments from the case's OWN typed_cast_arguments when present (selector_denied carries a distinct ba_req), else from the top-level request.typed_cast_arguments;
  • derives nonce PER CASE (design §1.6 C): if the case's proof payload has a "nonce" key, {:required, that_nonce}; otherwise :not_required (the shared expected_context.nonce would red nonce_absent);
  • synthesizes bounds: V1.Bounds.maximum/0 (design §1.6 B);
  • carries the shared expected_context's request fields.

issuer_public_key()

The 32-byte raw issuer public key — the verifier's TRUST ANCHOR.

Sourced from expected_context.trusted_issuer.public_key_base64url (the authoritative trust anchor the verifier is configured with), NOT from public_keys.issuer.raw_base64url (the signer's own published key). The two match in the published vector, but sourcing from the expected_context means a hypothetical signer-key/context-key mismatch fails the trust-anchor check rather than silently verifying against the signer key (cross-vendor CV-trust finding).

trusted_issuer()

The %TrustedIssuer{} from the vector's expected_context.

typed_cast_arguments()

The tagged Json.value() form of the vector's top-level cast_arguments, via Tag.from_json/1. Verified: RequestDigest.digest_raw of this value matches the vector's published ba_req.

vector()

The decoded published vector.