fix(billing): test-plan-aware tier mapping + PAYMENT_TEST_MODE_ENABLED kill-switch#271
Merged
Merged
Conversation
…D kill-switch
Two fixes for the test-cohort Razorpay checkout path (the with-UI test-card
payment E2E the CEO asked for):
1. planIDToTier / planIDRecognised now recognise the rzp_test_* plan IDs.
A TEST-mode subscription.activated/charged webhook carries the TEST plan_id;
previously it matched no live RAZORPAY_PLAN_ID_* and fell back to the safe
fallback tier ("hobby") + emitted a bogus billing.charge_undeliverable — so
the full UI card→webhook→Pro chain could NEVER actually reach Pro. Test plans
exist only in Razorpay test mode, so they can't collide with a live plan_id.
2. PAYMENT_TEST_MODE_ENABLED — explicit kill-switch (default FALSE / fail-CLOSED)
gating the whole test-cohort path on TOP of the rzp_test_* secrets. Required
by testModeConfigured() (checkout routing) AND the webhook try-both verify.
Separates the on/off decision (this flag) from the secret values (which stay
in instant-secrets), so an operator can kill test-mode routing instantly
without rotating keys, and a leftover test plan_id can never silently touch a
live customer's billing.
Tests: test-plan tier mapping (+ recognised), kill-switch inert proofs for both
the checkout (403 synthetic_test_cohort when flag off) and webhook (test secret
ignored when flag off) legs; existing cohort tests updated for the new flag.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ST_* to allKeys allKeys() (env host-state clearer) was missing the RAZORPAY_TEST_* vars and the new PAYMENT_TEST_MODE_ENABLED flag, so a leaked host env could bleed into config tests. Add them + a TestLoad_PaymentTestModeEnabled mirroring the other *_ENABLED flag tests (100%-patch coverage for the new parse branch). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Why
Wiring the real with-UI Razorpay test-card payment E2E (free cohort → dashboard Upgrade → test hosted-checkout → card → Pro active) surfaced two gaps that would have made the full chain silently fail or be unsafe.
What
Test-plan-aware tier mapping.
planIDToTier/planIDRecognisedonly knew the liveRAZORPAY_PLAN_ID_*. A TEST-modesubscription.activated/chargedwebhook carries the test plan_id → matched nothing → fell back to the safe fallback tier (hobby) and emitted a bogusbilling.charge_undeliverable. So a test-cohort pro upgrade could never reachproand the spec'spollTierIsProwould always soft-skip. Now theRazorpayTestPlanID{Pro,HobbyPlus,Hobby}IDs map to their canonical tiers (test plans exist only in test mode → no collision with live plan_ids).PAYMENT_TEST_MODE_ENABLEDkill-switch (default FALSE / fail-CLOSED). Gates the whole test-cohort path on top of the secrets — required bytestModeConfigured()(checkout routing) and the webhook try-both verify. The on/off decision lives in the flag; the secret values stay ininstant-secrets. An operator can kill test-mode routing instantly without rotating keys, and a leftover test plan_id can never silently touch a live customer's billing. test mode for CI, live for prod.Safety
synthetic_test_cohort403 (never the live path).is_test_cohort→ fail CLOSED to live.Tests
TestPlanIDToTier_MapsTestPlanIDsToCanonicalTier(+planIDRecognised).TestCohortCheckout_InertWhenFlagOff(403) +TestWebhook_TestSecretIgnoredWhenFlagOff(400).TestTestModeConfigured_InertWhenUnsetextended with the flag dimension; existing cohort/webhook tests updated for the flag.🤖 Generated with Claude Code