Feature/random unique value - #46
Open
EugeneDymo wants to merge 15 commits into
Open
Conversation
…the resource The comment already said the id is assigned by the Exchange, but an implementation historically derived it from the resource, so two offers for the same resource collided. The comment now states the id is opaque and unique per offer. No wire change; changelog mirrored on the website. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KAjPGWneSodefKfA3EauY
…the resource The comment already said the id is assigned by the Exchange, but an implementation historically derived it from the resource, so two offers for the same resource collided. The comment now states the id is opaque and unique per offer. No wire change; changelog mirrored on the website. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KAjPGWneSodefKfA3EauY
…o feature/random-unique-value
…e test Two example ids survived the sweep (offer-001 in extension-profiles, fake in the poc-walkthrough denial demo); both are now UUID v4. TestDocOfferIDsAreOpaque scans every offer_id value in the docs and rejects anything that is not an opaque UUID v4, so a structured example id cannot reappear silently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STq1uLaq6mVSKAn73xQnwC
…-value # Conflicts: # docs/sdk-parity-matrix.md # gen/descriptor.binpb # gen/ts/wire/schemas.ts # proto/CHANGELOG.md # sdk/python/ramp_sdk/__init__.py # sdk/ts/client/index.ts # website/src/content/docs/reference/changelog.mdx
… its guards The Execute tests in all three SDKs now read agent_request_acceptance back off the recorded wire body and verify it the way a receiving Exchange would (Go through the projection check, Python and TypeScript through the verify wrappers), pinning the exact wire spelling of the payload. Go test offers now carry an exchange, so the signing branch actually runs under test; each runtime also asserts the field is omitted for an offer that names no exchange, since a request-acceptance item requires a recipient. The Go verifier's guards get negatives: an acceptance replayed under a request with a different requester or idempotency key is refused, a non-EdDSA algorithm is refused, and the Signer face round-trips and refuses a non-Ed25519 signer before asking it to sign. Removing the envelope-binding block now fails the suite instead of passing silently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STq1uLaq6mVSKAn73xQnwC
… projections AgentRequestAcceptancePayload.items is capped at 256 (repeated.max_items, the same ceiling a discovery query's uris list carries). The Go helper enforces the same bound itself before its item walk and JCS rendering, and decodes and size-checks the Ed25519 signature before canonicalization — a verifier may run with wire validation off, and the canonical rendering of an unbounded caller-controlled list is the expensive step a caller whose signature cannot possibly verify must not be able to buy. A test pins the helper's bound to the wire rule so the two cannot drift, and an ordering probe pairs an over-cap payload with a wrong-size signature to prove the cheap check runs first. VerifyRequestAcceptanceProjection now refuses an empty subrequest outright: for an Exchange the signed set never names, the projection is also empty, zero compared equal to zero, and the helper reported a verified projection for a request addressed to nobody. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STq1uLaq6mVSKAn73xQnwC
…fication VerifyRequestAcceptanceProjection filtered the signed set and validated forwarded offers with raw string equality, while the SDK's Exchange identity rule (CheckAudience) folds case and treats an explicit :443 as the omitted HTTPS-default port. With a signed set holding one.example and one.example:443, a relay could drop the differently spelled item and still pass, and an honest complete forward was refused. Both comparisons now go through CheckAudience. The projection exchange must be a bare domain; a value in any other shape names nobody and never matches, so malformed values fail closed. Port 80 stays a distinct identity. Tests: an honest mixed-spelling forward verifies under either accepted spelling of the verifier's identity; dropping any equivalent item, or forwarding only the raw-equal subset, is refused; port-80 and malformed values are refused. Both new tests fail if the comparison reverts to raw equality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STq1uLaq6mVSKAn73xQnwC
…and order set verification before idempotency The request-acceptance contract said a Broker forwards the envelope unchanged while projecting a mixed-Exchange request, but the documented RFC 9421 model only covered byte-for-byte forwarding, where the agent's signature spans the body through Content-Digest. Projecting the body invalidates that signature, and nothing said who authenticates a projected subrequest or how an Exchange resolves the acceptance verification key. The model is now written down in the proto comment, the authentication page, and the Broker overview. A projected subrequest is a new HTTP request its sender authors and RFC 9421-signs - a Broker, or the agent itself when it splits its own set. The agent's authorization travels in the body as the two detached Ed25519 signatures, which is why they exist. The Exchange resolves the acceptance verification key from the WBA directory of the requester domain the signed payload names, which must equal the request's requester.domain; when the requester signed the arriving request, that is the already-resolved request-signing key. Delegation holder binding still matches the wire signer, so a Broker may project a delegated request only when the agent delegated to the Broker's key. Fan-out stays on the existing Resolve plus one ExecuteTransaction per Exchange; no new RPC. The threat model gains T-BRK-1: item-level removal, append, reorder, and valid-subset-first mutation of the request set during fan-out, countered by the request acceptance and explicitly not by the hop stack, which proves nothing about a body the Broker authored. The Exchange step lists now verify a present request acceptance and its exact projection before any idempotency lookup, matching the proto requirement - idempotency state is never created or served for a request whose set claim has not been proven. Optional-field behavior for older clients is stated consistently everywhere. Doc conformance is clean and the site builds with all internal links valid. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STq1uLaq6mVSKAn73xQnwC
…bsite proto/CHANGELOG.md records the additive TransactionRequest.agent_request_acceptance wire change, but the website changelog had no matching Unreleased entry despite the rule that meaningful proto changes are mirrored there. The new entry covers the complete ordered request-set proof, the Broker projection purpose, the optional field's wire compatibility, and the 256-item work bound, and states that the RFC 9421 forwarding stack does not provide the item-level property because a projected subrequest is a new request its sender signs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STq1uLaq6mVSKAn73xQnwC
The canonical-signing section said two protobuf-message payloads are signed, that the acceptance payload is the one place Python and TypeScript hand-build canonical JSON, and listed two accessor triples. AgentRequestAcceptance is a third signed payload and a second hand-built acceptance object in both ports, down to each entry of its nested items list, with the omission invariant pinned by the shared request-acceptance vectors. The accessor list now carries CanonicalRequestAcceptanceBytes, jcs_request_acceptance_payload, and requestAcceptancePayload beside the existing pairs. The recipient-addressing section now distinguishes AgentRequestAcceptanceItem.exchange - a signed projection index that lets a recipient of a projected subrequest derive its own projection - from the redundant top-level TransactionRequest audience field that section rejects. The projection check itself polices the copy, so the top-level-versus-items mismatch objection does not apply. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STq1uLaq6mVSKAn73xQnwC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.