Skip to content

Add a doctor command verifying the gateway configuration end to end - #140

Merged
loevgaard merged 2 commits into
2.xfrom
doctor-command
Aug 24, 2026
Merged

Add a doctor command verifying the gateway configuration end to end#140
loevgaard merged 2 commits into
2.xfrom
doctor-command

Conversation

@loevgaard

Copy link
Copy Markdown
Member

Closes #131.

$ bin/console setono:sylius-quickpay:doctor --live

 ✔ The notify endpoint for operations made outside the store is registered at "/payment/quickpay/notify"

Gateway "quickpay_credit_card"
------------------------------
 ✔ The api key is accepted by Quickpay (verified via /payments — the api user lacks the /ping permission, which is harmless)
 ✔ The private key signs and verifies callbacks (only a real callback proves it matches the account)
 ✔ No agreement id configured — Quickpay uses the account's default Payment Window agreement
 ✔ The order prefix "qp_" is within Quickpay's length limit
 ✔ The api user may create payment links (PUT /payments/:id/link)
 ! Test payment 613270448 (order id "qp_dr815884") remains on the account — it never carries money

 [OK] All checks passed.

(actual output of the live verification run against the real Quickpay API)

Checks

Per configured Quickpay gateway:

  • Api keyping(), falling back to a one-item /payments read. The fallback exists because of a live discovery: Quickpay answers 401 on /ping both for an invalid key and for a valid key whose api user lacks the /ping permission (the real test account does exactly this — its key 401s on /ping and 200s on /payments). A 401/403 on both is reported as a rejected key with the API-user-vs-Payment-Window hint.
  • Private key — HMAC checksum self-test through the SDK's CallbackValidator (sign + verify roundtrip); the output is honest that only a real callback proves the key matches the account.
  • Agreement idGET /agreements/{id} when configured; missing agreement fails, a missing /agreements permission only warns (fail open). Unconfigured reports the account-default behavior.
  • Order prefix — the 11-character limit, plus a cross-gateway warning when two gateways share a prefix (the "order_id already exists" collision).
  • Notify route — registered at all, catching a missed routes import (installation step 4).

--live additionally creates a money-less test payment and attempts the payment link PUT the checkout depends on — surfacing the classic Not authorized to PUT /payments/:id/link permission case before a customer does. The link is cleaned up best effort; the leftover test payment is disclosed in the output.

Exit code is non-zero when any check fails (CI/cron-friendly); warnings don't fail, matching the plugin's fail-open posture.

Out of scope

The issue's optional callback-loop check is deliberately not included: without a real card transaction Quickpay sends no callback, so any synthetic "loop" would only prove routing, not verification — and the routing half is covered by the route check plus the reconcile command operationally. Can be revisited if you disagree.

The /ping discovery also means QuickpayCredentialsValidator (form save) can reject a valid key whose api user lacks the /ping permission — filed separately as a follow-up.

Tests

13 command tests. The SDK endpoint classes are final, so multi-request flows (the --live probe, the /ping fallback) run the real SDK client against a new FIFO QueuedResponsesHttpClient test double; single-call checks use ClientInterface prophecies. Both modes verified live against the real Quickpay API.

setono:sylius-quickpay:doctor machine-checks what the README's Troubleshooting
section documents, per configured Quickpay gateway:

- api key: ping, falling back to a /payments read because Quickpay answers 401
  on /ping both for an invalid key and for a valid key whose api user lacks the
  /ping permission (verified live against the API)
- private key: HMAC checksum self-test through the SDK's CallbackValidator
- agreement id: existence on the account when configured (failing open when
  the api user lacks the /agreements permission)
- order prefix: length limit, plus a cross-gateway warning when two gateways
  share a prefix
- notify route registration (the routes import installation step)

--live additionally creates a money-less test payment and attempts the payment
link PUT the checkout depends on, surfacing the "Not authorized to PUT
/payments/:id/link" permission case before a customer does; the created link is
cleaned up best effort and the leftover test payment is disclosed.

Exits non-zero when any check fails; warnings do not fail, matching the
plugin's fail-open posture. Verified live against the Quickpay API, both modes.

Closes #131
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.12%. Comparing base (3caa0ff) to head (c61c9c4).

Additional details and impacted files
@@             Coverage Diff              @@
##                2.x     #140      +/-   ##
============================================
+ Coverage     94.27%   95.12%   +0.84%     
- Complexity      226      272      +46     
============================================
  Files            27       28       +1     
  Lines           839      985     +146     
============================================
+ Hits            791      937     +146     
  Misses           48       48              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Also drops the private key self-test's failure branch: a sign-then-verify
roundtrip with the same key cannot report false, so the branch was unreachable
- the self-test's failure mode is an exception.
@loevgaard
loevgaard merged commit ea88648 into 2.x Aug 24, 2026
30 checks passed
@loevgaard
loevgaard deleted the doctor-command branch August 24, 2026 10:48
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.

Add a setono:sylius-quickpay:doctor command that verifies the gateway configuration end to end

1 participant