Skip to content

fix: implement JCS cart-to-payment mandate binding per RFC 8785#251

Closed
chopmob-cloud wants to merge 58 commits intogoogle-agentic-commerce:mainfrom
chopmob-cloud:fix/jcs-cart-payment-binding-v2
Closed

fix: implement JCS cart-to-payment mandate binding per RFC 8785#251
chopmob-cloud wants to merge 58 commits intogoogle-agentic-commerce:mainfrom
chopmob-cloud:fix/jcs-cart-payment-binding-v2

Conversation

@chopmob-cloud
Copy link
Copy Markdown

@chopmob-cloud chopmob-cloud commented Apr 29, 2026

Summary

Closes the CartMandate ↔ PaymentMandate binding gap raised in #211.

The core problem: without a cryptographic link from CartMandate to PaymentMandate, a malicious or misconfigured agent can substitute a different cart after the user has expressed intent. The fix uses RFC 8785 (JSON Canonicalization Scheme) to produce a deterministic hash that is consistent across Python, Go, and TypeScript implementations.

Spec (docs/ap2/specification.md)

New normative section Cart-to-Payment Mandate Binding under §Payment Mandate with three requirements:

  1. PaymentMandateContents MUST include cart_mandate_id and cart_mandate_hash = hex(sha256(JCS(CartMandate))).
  2. JCS serialisation MUST exclude null/None optional fields so Python and Go (omitempty) produce identical canonical bytes.
  3. Verifiers (CP, Merchant, MPP) MUST recompute the hash and MUST reject on mismatch before releasing credentials or initiating payment.

Types (code/sdk/python/ap2/models/mandate.py)

Added two Optional fields to PaymentMandateContents:

  • cart_mandate_id — reference to the bound CartMandate.
  • cart_mandate_hashhex(sha256(JCS(CartMandate))).

Both are Optional for backward compatibility; new mandates SHOULD populate both.

Sample validation (code/samples/python/src/common/validation.py)

New helper module containing:

  • validate_payment_mandate_signature() — placeholder for sd-jwt-vc key-binding.
  • validate_cart_mandate_hash() — recomputes and compares the JCS hash. Uses model_dump(exclude_none=True) for cross-language consistency (matches Go omitempty); raises ValueError on mismatch; skips with a warning if cart_mandate_hash is absent (backward-compatible rollout).

Dependency (code/samples/python/pyproject.toml)

Added rfc8785>=0.1.2.


Note: This replaces the previously closed PR #241. All high-priority Gemini feedback from that review has been incorporated upfront: model_dump(exclude_none=True) for cross-language hash consistency, f-strings throughout, and import path updated from ap2.types.mandateap2.models.mandate.

Test plan

  • validate_cart_mandate_hash() returns without error when hash matches.
  • validate_cart_mandate_hash() raises ValueError when the hash does not match.
  • validate_cart_mandate_hash() logs a warning and returns cleanly when cart_mandate_hash is None (backward compat).
  • PaymentMandateContents with both new fields round-trips through Pydantic serialisation without error.

holtskinner and others added 30 commits May 30, 2025 15:37
This commit introduces the foundational elements of the protocol, including core data structures and documentation.
Co-authored-by: Holt Skinner <holtskinner@google.com>
Release-As: 0.1.0
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
- Add Site Author
- Add `site_dir` -> Possibly to fix `CNAME` overwriting issue
- Add Life of a Transaction to Nav
* [Doc]: fixing typos in various files

* [Doc]: reverting function name change for now

* Fix spelling error `_log_request_instructions`

---------

Co-authored-by: Holt Skinner <holtskinner@google.com>
…tic-commerce#40)

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…gentic-commerce#50)

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…als (google-agentic-commerce#20)

# Description

s/Verifiable Credential/verifiable digital credential
s/VC/VDC

Fixes google-agentic-commerce#18  🦕

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
# Description

- Align MPP acronym with glossary.

Signed-off-by: Hyung-Kyu Choi <hyungkyu.choi@gmail.com>
…oogle-agentic-commerce#48)

- Add optional Vertex AI authentication via `GOOGLE_GENAI_USE_VERTEXAI`
environment variable
- Update `run.sh` to check for either `GOOGLE_API_KEY` or
`GOOGLE_GENAI_USE_VERTEXAI=true`
- Fix `PaymentDetailsModifier` schema type from `Optional[Any]` to
`Optional[dict[str, Any]]` for Vertex AI compatibility
- Update `README.md`

This enables users to authenticate using either:
1. `GOOGLE_API_KEY` (existing method)
2. `GOOGLE_GENAI_USE_VERTEXAI=true` with `GOOGLE_CLOUD_PROJECT` and
`GOOGLE_CLOUD_LOCATION` (new Vertex AI method)

Fixes google-agentic-commerce#47 🦕

---------

Co-authored-by: Holt Skinner <13262395+holtskinner@users.noreply.github.com>
Co-authored-by: Holt Skinner <holtskinner@google.com>
…le-agentic-commerce#29)

Implements logging for the X-A2A-Extensions header when present in
incoming requests. This improves debugging visibility for A2A protocol
extension usage.

Resolves TODO in server.py:132

Fixes google-agentic-commerce#28

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Holt Skinner <13262395+holtskinner@users.noreply.github.com>
…ios (google-agentic-commerce#80)

### Summary
Adds a short "Install uv" section to the README pre-requisites section
so newcomers don’t hit `uv: command not found`, for a better developer
experience.

### Why
Scenario run scripts depend on uv but the README doesn’t mention it yet.
This update avoids onboarding friction.

---------

Co-authored-by: Holt Skinner <13262395+holtskinner@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
jorellis and others added 19 commits October 30, 2025 10:09
> [!TIP]
> Better reviewed commit-by-commit.

# Description

Implements a standalone `go` sample.

- [x] Follow the [`CONTRIBUTING`
Guide](https://github.com/google-agentic-commerce/AP2?tab=contributing-ov-file#how-to-contribute).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- [x] Ensure the tests and linter pass
- [x] Appropriate docs were updated (if necessary)

Closes google-agentic-commerce#71  🦕
Define v.01 PaymentReceipt schema and demonstrate its creation and flow
between agents.

This brings the sample code in alignment with section 7.1 of the
[specification](https://github.com/google-agentic-commerce/AP2/blob/main/docs/specification.md).
Correct sorting and add endorsing partners who
should have already been included.
…ples (google-agentic-commerce#121)

This PR introduces support for the x402 payment method within the Python
human-in-the-loop agent scenarios. It enables the simulation of
x402-compatible transactions across the Merchant, Shopping, and Payment
Processor agents.

Key Changes:
- Documentation: Added a detailed README.md for the x402 scenario,
including setup and execution instructions.
- Scripting: Updated run.sh to accept a --payment-method argument
(defaulting to CARD).

- Merchant Agent:
- Updated catalog_agent.py to generate CartMandate artifacts with x402
specific PaymentMethodData when enabled.
  - Updated tools.py to route x402 payments to the correct processor.

- Payment Processor Agent:
  - Enhanced tools.py to handle PAYMENT_METHOD environment variable.
- Implemented logic to process x402 payment mandates, skipping the OTP
challenge and credential provider lookup where appropriate (using
mock/dummy clients).
  - Added logic to generate x402-specific payment receipts.

- Shopping Agent:
- Updated tools.py to co nstruct PaymentMandates with the correct
method_name and details for x402.
- Updated payment_method_collector/tools.py to mock x402 payment
payloads when the payment method is set to x402.
  
- Credentials Provider Agent:
  - Added a mock "x402_wallet" to the `account_manager.py`.
- Updated tools.py to recognize https://www.x402.org/ as a supported
method.

---------

Co-authored-by: Jordan Ellis <jordanellis@google.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…gle-agentic-commerce#138)

This commit adds an article discussing how UCP and AP2 protocols relate
to one another.

---------

Co-authored-by: Holt Skinner <13262395+holtskinner@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
)

Kite AI is an AI payment system on blockchain. Their team has been
contributing to the AP2 spec as well as the A2A-x402 extension.
# Description

Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make
sure it goes smoothly:

- [x] Follow the [`CONTRIBUTING`
Guide](https://github.com/google-agentic-commerce/AP2?tab=contributing-ov-file#how-to-contribute).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- [x] Ensure the tests and linter pass
- [x] Appropriate docs were updated (if necessary)

adding a link of UCP with ap2.

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: GarethCOliver <GarethCOliver@users.noreply.github.com>
# Description

Release v.2 spec, create HNP samples & python SDK, update existing  DPC example & HP examples.

Co-authored-by: @GarethCOliver
Co-authored-by: @natalie-ngan
Co-authored-by: @prateekdudeja19-g
Co-authored-by: @kmcduffie
Co-authored-by: @reema7
Co-authored-by: @jorellis
Co-authored-by: @joshlund-goog
Co-authored-by: @mdoeseckle
# Description

update the title of the video on the main README
…merce#240)

Clarified contribution guidelines regarding the core specification and
focus on samples and SDK.

# Description

Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make
sure it goes smoothly:

- [ ] Follow the [`CONTRIBUTING`
Guide](https://github.com/google-agentic-commerce/AP2?tab=contributing-ov-file#how-to-contribute).
- [ ] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- [ ] Ensure the tests and linter pass
- [ ] Appropriate docs were updated (if necessary)

Fixes #<issue_number_goes_here> 🦕
# Description

Update the CHANGELOG.md
Addresses the CartMandate <> PaymentMandate binding gap raised in google-agentic-commerce#211.

## Spec (docs/ap2/specification.md)

Added section "Cart-to-Payment Mandate Binding" under Payment Mandate
with three normative requirements:

1. PaymentMandateContents MUST include cart_mandate_id and
   cart_mandate_hash = hex(sha256(JCS(CartMandate))) per RFC 8785.
   JCS eliminates cross-language float-serialisation ambiguity
   (Python: 120.0, Go: 120 — different bytes without canonicalisation).
2. cart_mandate_hash MUST be computed with null/None optional fields
   excluded so Python and Go (omitempty) produce the same canonical form.
3. Verifiers MUST recompute the hash and MUST reject on mismatch before
   releasing credentials or initiating payment.

## Types (code/sdk/python/ap2/models/mandate.py)

Added two Optional fields to PaymentMandateContents:
- cart_mandate_id — reference to the bound CartMandate.
- cart_mandate_hash — sha256(RFC 8785 canonical form of CartMandate).

Both Optional for backward compatibility; new mandates SHOULD populate both.

## Sample validation (code/samples/python/src/common/validation.py)

New helper module with:
- validate_payment_mandate_signature() — placeholder for sd-jwt-vc
  key-binding verification (unchanged from prior design).
- validate_cart_mandate_hash() — recomputes and compares the JCS hash.
  Uses model_dump(exclude_none=True) so None-valued optional fields are
  omitted, matching Go omitempty and ensuring cross-language consistency
  (high-priority Gemini feedback on the earlier closed PR google-agentic-commerce#241).
  Uses f-strings throughout (low-priority Gemini feedback).

## Dependency (code/samples/python/pyproject.toml)

Added rfc8785>=0.1.2 for RFC 8785 JSON canonicalisation.
@chopmob-cloud chopmob-cloud requested a review from a team as a code owner April 29, 2026 20:18
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Apr 29, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the cart-to-payment mandate binding as specified in AP2 section 4.1.3.1. It introduces the rfc8785 dependency, updates the PaymentMandateContents model to include cart_mandate_id and cart_mandate_hash fields, adds validation logic in a new utility module, and updates the specification documentation. I have no feedback to provide.

Addresses cspell and markdownlint failures in CI:

- validation.py: serialised→serialized, behaviour→behavior,
  authorised→authorized (cspell uses American English dictionary)
- specification.md: same spelling fixes + serialisation→serialization,
  canonicalisation→canonicalization, authorises→authorizes
- specification.md: fix pre-existing MD030 violations (3 spaces after
  list markers → 1 space) exposed by touching the file
- .cspell/custom-words.txt: add fastmcp, omitempty, rfc8785
  (pre-existing package name and Go struct tag used in pyproject.toml
  and the new validation comments)
@chopmob-cloud
Copy link
Copy Markdown
Author

I have read and signed the Google CLA. @googlebot please re-check.

[Agent Authorization Framework][agent_authorization.md] used a
reference-style label with no corresponding link definition, triggering
markdownlint MD052. Convert to an equivalent inline link.

Pre-existing issue exposed by touching the file.
@chopmob-cloud
Copy link
Copy Markdown
Author

Reopening this work as #253 — the branch on this PR was inadvertently broken during a local history-cleanup pass and GitHub auto-closed it. The replacement carries the identical code, cherry-picked clean onto current main. Apologies for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.