Verify api keys with the ping-then-payments probe in the credentials validator - #142
Merged
Conversation
…validator Quickpay answers 401 on /ping both for an invalid api key and for a valid key whose api user lacks the /ping permission (verified live), so the form-save validator rejected perfectly valid configurations for locked-down api users. The doctor command's two-step probe is extracted to Quickpay\ApiKeyVerifier (ping, falling back to a one-item /payments read - a permission every integration needs) and both consumers now share it: the validator raises a violation only when the probe reports an explicit 401/403, and the doctor keeps its distinct ok/fail/warn messages. Closes #141
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 2.x #142 +/- ##
============================================
+ Coverage 95.12% 95.14% +0.01%
- Complexity 272 273 +1
============================================
Files 28 29 +1
Lines 985 988 +3
============================================
+ Hits 937 940 +3
Misses 48 48 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
verify() returned false for a key that had just passed verification - the bool answered "does the api user have the /ping permission", not "is the key valid", and the method name hid that. It now returns an ApiKeyVerification enum whose two cases both read as verified (ViaPing / ViaPayments), with the rejected and unanswered outcomes staying exceptions as before.
loevgaard
force-pushed
the
fix-credentials-validator
branch
from
August 24, 2026 10:56
dfd55a9 to
23df5be
Compare
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.
Closes #141.
The bug
Quickpay answers 401 on
GET /pingboth for an invalid api key and for a valid key whose api user lacks the/pingpermission — verified live: the test account's working key (payments, links, captures all fine) gets 401 on/pingand 200 on/payments.QuickpayCredentialsValidatortreated any 401/403 from the ping as "Quickpay rejects the key", so a merchant with a locked-down api user could not save a perfectly valid payment method through the admin form.The fix
The doctor command's two-step probe (from #140) is extracted to
Quickpay\ApiKeyVerifier(+ interface and alias, per the repo convention): ping first, and on 401/403 fall back to a one-item/paymentsread — a permission every integration needs anyway. Both consumers share it:QuickpayCredentialsValidatorraises a violation only when the probe reports an explicit 401/403 (i.e./paymentsalso rejects the key); everything else keeps failing open, so neither a locked-down api user nor an unreachable Quickpay blocks saving.DoctorCommandkeeps its distinct messages ("accepted", "accepted via /payments — the api user lacks the /ping permission, which is harmless", rejected, unanswered) keyed off the verifier's result/exceptions.The verifier's contract encodes the outcome in types: returns whether the
/pingpermission exists, throwsUnauthorizedException/ForbiddenExceptionfor a rejected key, and lets anything else propagate as "nothing proven either way" — which is exactly the distinction both consumers already made.Tests
ApiKeyVerifierTestdrives the probe through the real SDK client (queued-response PSR-18 double): ping-ok, fallback-ok, rejected on both endpoints, unanswered ping, unanswered fallback.README (form-save paragraph) and CLAUDE.md updated to describe the shared probe.