Skip to content

fix(sdk): match allowed payment instruments by (type, id), not id alone#301

Open
chopmob-cloud wants to merge 3 commits into
google-agentic-commerce:mainfrom
chopmob-cloud:fix/299-allowed-instrument-type-id-match
Open

fix(sdk): match allowed payment instruments by (type, id), not id alone#301
chopmob-cloud wants to merge 3 commits into
google-agentic-commerce:mainfrom
chopmob-cloud:fix/299-allowed-instrument-type-id-match

Conversation

@chopmob-cloud

@chopmob-cloud chopmob-cloud commented Jul 17, 2026

Copy link
Copy Markdown

Summary

Addresses the allowed-instrument matching defect reported in #299 (item 2): the Python evaluator matches an allowed PaymentInstrument on id alone.

AllowedPaymentInstrumentEvaluator.evaluate compared only allowed.id == instrument.id (constraints.py#L246-L251). Because PaymentInstrument.id uniqueness is not defined across types, a closed instrument of a different type satisfied the constraint.

Failure scenario

Allowed set: [{id: "pi-1", type: "card"}]. A closed mandate carrying {id: "pi-1", type: "bank"} passed the constraint under id-only matching. Where type selects the payment profile (or ids are scoped by type / credential provider), a different profile than the one the user authorized could satisfy the allowed_payment_instrument constraint, and at minimum inconsistent signed instrument metadata is accepted.

Fix

Require both type and id to match, and include type in the violation message so a mismatch is diagnosable:

if any(
    allowed.type == instrument.type and allowed.id == instrument.id
    for allowed in self.constraint.allowed
):
    return []

Tests

code/sdk/python/ap2/tests/constraints_tests.py:

  • test_payment_allowed_payment_instrument_same_id_different_type_rejected : same id, different type is a violation.
  • test_payment_allowed_payment_instrument_type_and_id_match : an allowed (type, id) still passes.

The two existing allowed-instrument tests are unchanged and still pass.

Validated with pip install . in a clean python:3.12-slim container: constraints_tests.py 49 passed.

Scope

This PR is intentionally limited to the matching semantics. The other two items in #299 are handled separately:

AllowedPaymentInstrumentEvaluator matched an allowed instrument on id
only, so a closed instrument of a different type (for example
{id: "pi-1", type: "bank"}) satisfied an allowed {id: "pi-1",
type: "card"}. Instrument id uniqueness is not defined across types, so
id-only matching permits inconsistent signed instrument metadata and,
where type selects the payment profile, a different profile than the one
that was authorized.

Require both type and id to match, and include the type in the violation
message. Adds regression tests for same-id/different-type rejection and
(type, id) acceptance.

Part of google-agentic-commerce#299.
@chopmob-cloud
chopmob-cloud requested a review from a team as a code owner July 17, 2026 12:19

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

Copy link
Copy Markdown
Contributor

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 updates the payment instrument evaluation logic to match on both type and id instead of only id, preventing potential instrument-type confusion across different types sharing the same ID. It also updates the error message to include both type and ID, and adds corresponding unit tests to verify this behavior. There are no review comments, so I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

The spellcheck action checks entire changed files. Touching
constraints.py / constraints_tests.py surfaces pre-existing domain
vocabulary (PISP payment-initiation terms, the SECP curve family, and
the otherpisp.com test fixture) that was never in the custom
dictionary. Register the exact case forms so the spellcheck gate passes.
The Lint Code Base job runs super-linter with VALIDATE_ALL_CODEBASE
false, but the Biome linter ignores FILTER_REGEX_EXCLUDE and lints the
whole code/web-client demo app, so a PR touching only the Python SDK
still fails on pre-existing web-client diagnostics unrelated to the
change. Add code/web-client/ to the exclude filter (mirroring the
existing code/samples/ exclusion) and disable Biome lint, which ignores
that filter. Matches the CI fix already on PR google-agentic-commerce#300.
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.

1 participant