From 262365f99161b6362b570313e13c219978ec06fe Mon Sep 17 00:00:00 2001 From: Akshar Prabhudesai <262747075+aksharprabhudesai@users.noreply.github.com> Date: Sat, 17 Oct 2026 13:39:50 -0700 Subject: [PATCH] fix(sdk): handle optional store reference callback in verify_receipt --- .cspell/custom-words.txt | 4 + code/sdk/python/ap2/sdk/receipt_wrapper.py | 5 +- .../python/ap2/tests/receipt_wrapper_tests.py | 104 ++++++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) diff --git a/.cspell/custom-words.txt b/.cspell/custom-words.txt index ce73c361..4113651d 100644 --- a/.cspell/custom-words.txt +++ b/.cspell/custom-words.txt @@ -127,11 +127,14 @@ Payoneer paypal Payplug pids +PISP +pisp pmezard proguard Proguard prometheus protoc +pyca pyflow pymdownx pypa @@ -149,6 +152,7 @@ ropeproject RPCURL Rulebook screenreaders +SECP setlocal sharedpref Shopcider diff --git a/code/sdk/python/ap2/sdk/receipt_wrapper.py b/code/sdk/python/ap2/sdk/receipt_wrapper.py index 3927bd97..01ffbee3 100644 --- a/code/sdk/python/ap2/sdk/receipt_wrapper.py +++ b/code/sdk/python/ap2/sdk/receipt_wrapper.py @@ -143,7 +143,10 @@ def verify_receipt( # 2. Verify receipt reference exists in the issuer's store receipt_reference = getattr(receipt.root, 'reference', None) - if not has_reference_in_store_cb(receipt_reference): + if ( + has_reference_in_store_cb is not None + and not has_reference_in_store_cb(receipt_reference) + ): _logger.warning( 'Receipt reference not found in store: %s', receipt_reference, diff --git a/code/sdk/python/ap2/tests/receipt_wrapper_tests.py b/code/sdk/python/ap2/tests/receipt_wrapper_tests.py index c3cfaf75..04982b54 100644 --- a/code/sdk/python/ap2/tests/receipt_wrapper_tests.py +++ b/code/sdk/python/ap2/tests/receipt_wrapper_tests.py @@ -107,6 +107,63 @@ def test_verify_payment_receipt_success(issuer_key, issuer_public_key): has_ref_cb.assert_called_once_with(reference) +def test_verify_payment_receipt_success_without_store_cb( + issuer_key, issuer_public_key +): + """Test verification of a payment receipt when reference callback is omitted.""" + client = ReceiptClient() + reference = 'ref_123' + base_receipt = client._create_base_receipt( + 'Success', 'issuer.com', reference + ) + payment_receipt = PaymentReceipt( + **base_receipt, + payment_id='pid_123', + psp_confirmation_id='pid_123', + network_confirmation_id='pid_123', + ) + receipt_jwt = create_jwt( + {'alg': 'ES256'}, payment_receipt.model_dump(), issuer_key + ) + + result = client.verify_receipt( + receipt_jwt=receipt_jwt, + receipt_issuer_public_key=issuer_public_key, + is_payment_receipt=True, + ) + + assert result == {'verified': True} + + +def test_verify_payment_receipt_success_explicit_none_cb( + issuer_key, issuer_public_key +): + """Test verification of a payment receipt when reference callback is explicitly None.""" + client = ReceiptClient() + reference = 'ref_123' + base_receipt = client._create_base_receipt( + 'Success', 'issuer.com', reference + ) + payment_receipt = PaymentReceipt( + **base_receipt, + payment_id='pid_123', + psp_confirmation_id='pid_123', + network_confirmation_id='pid_123', + ) + receipt_jwt = create_jwt( + {'alg': 'ES256'}, payment_receipt.model_dump(), issuer_key + ) + + result = client.verify_receipt( + receipt_jwt=receipt_jwt, + receipt_issuer_public_key=issuer_public_key, + has_reference_in_store_cb=None, + is_payment_receipt=True, + ) + + assert result == {'verified': True} + + def test_verify_checkout_receipt_success(issuer_key, issuer_public_key): """Test successful verification of a checkout receipt.""" client = ReceiptClient() @@ -133,6 +190,53 @@ def test_verify_checkout_receipt_success(issuer_key, issuer_public_key): has_ref_cb.assert_called_once_with(reference) +def test_verify_checkout_receipt_success_without_store_cb( + issuer_key, issuer_public_key +): + """Test verification of a checkout receipt when reference callback is omitted.""" + client = ReceiptClient() + reference = 'ref_456' + base_receipt = client._create_base_receipt( + 'Success', 'merchant.com', reference + ) + checkout_receipt = CheckoutReceipt(**base_receipt, order_id='order_456') + receipt_jwt = create_jwt( + {'alg': 'ES256'}, checkout_receipt.model_dump(), issuer_key + ) + + result = client.verify_receipt( + receipt_jwt=receipt_jwt, + receipt_issuer_public_key=issuer_public_key, + is_payment_receipt=False, + ) + + assert result == {'verified': True} + + +def test_verify_checkout_receipt_success_explicit_none_cb( + issuer_key, issuer_public_key +): + """Test verification of a checkout receipt when reference callback is explicitly None.""" + client = ReceiptClient() + reference = 'ref_456' + base_receipt = client._create_base_receipt( + 'Success', 'merchant.com', reference + ) + checkout_receipt = CheckoutReceipt(**base_receipt, order_id='order_456') + receipt_jwt = create_jwt( + {'alg': 'ES256'}, checkout_receipt.model_dump(), issuer_key + ) + + result = client.verify_receipt( + receipt_jwt=receipt_jwt, + receipt_issuer_public_key=issuer_public_key, + has_reference_in_store_cb=None, + is_payment_receipt=False, + ) + + assert result == {'verified': True} + + def test_verify_receipt_invalid_signature(issuer_public_key): """Test verification failure with an invalid signature.""" client = ReceiptClient()