feat(billing): migrate stripe SDK to 15.6.1 with basil-era contract fixes (C1-C7 phase 1) - #230
Conversation
…ixes Sync both manifests to stripe==15.6.1 (root was 8.4.0, backend 10.12.0). - R1: read current_period_start/end from Subscription.items.data[0] (moved off Subscription by API 2025-03-31.basil in SDK v12), with defensive fallback to the subscription root for older shapes. - R2: resolve client_secret via _resolve_client_secret(), expanding latest_invoice + latest_invoice.payments so it works against both pre-basil (invoice.payment_intent) and basil+ (InvoicePayment) shapes. - R3/C6: pin stripe.max_network_retries = 0 (SDK v11+ default of 2 with 5s timeout could block the event loop ~15s per call; documented in code). - Add contract tests documenting both API shapes (5 tests; 87 total green). Supersedes #166; covers #227 (backend) and #228 (root) dependabot bumps. Phase 1 of reports/opencode/qafw-stripe-migration-plan-2026-08-27.md: Stripe webhook endpoint API version untouched.
PR Check Results✅ Code Formatting: Passed |
|
| Severity | Count |
|---|---|
| 🔴 CRITICAL | 0 |
| 🟠 HIGH | 46 |
| Total | 46 |
Scans performed:
- 📁 Filesystem (vulnerabilities, secrets, misconfigurations)
- 🐳 Backend Docker image
- 🐳 Frontend Docker image
- 🏗️ IaC misconfiguration detection
📋 View detailed SARIF reports
Download artifacts from this workflow run for full SARIF reports.
Results are also available in the GitHub Security tab.
Trivy v0.71.0 | aquasecurity/trivy
🔧 Backend Preview DeploymentApp Coolify: qa-framework-backend-pr-230 ( Preview interna (sin FQDN público hasta decisión de proxy — card 52a85645). |
🎨 Frontend Preview DeploymentApp Coolify: qa-framework-frontend-pr-230 ( Preview interna (sin FQDN público hasta decisión de proxy — card 52a85645). |
|
CI verde: 37 checks pass, 0 fail (Performance/Cleanup skip esperados). Supersede explícito de #166; cubre #227 y #228 — cerraré esas dos como superseded al merge de este PR (o dependabot las cerrará solo). Evidencia completa en workspace: reports/opencode/qafw-stripe-migration-exec-2026-09-07.md. Pendientes GATED: sandbox/staging con claves test-mode (la única key del entorno es sk_live_). |
…p-level classes SDK >= 11 removed the stripe.error package; except-clause evaluation raised ModuleNotFoundError, masking real Stripe failures (webhook -> 500 instead of 400). - stripe_service.py / billing_routes.py: stripe.error.StripeError -> stripe.StripeError, stripe.error.SignatureVerificationError -> stripe.SignatureVerificationError - tests: same migration in test_stripe_service.py and test_stripe_e2e.py - regression tests: real StripeError caught by service error path; webhook invalid signature returns 400 (not 500); missing signature header 400 - fix stale comment claiming error handling was covered pre-fix
PR Check Results✅ Code Formatting: Passed |
|
Iteración 2 — BLOCKER Fix: SDK ≥11 eliminó el paquete
Evidencia:
Warnings no-bloqueantes intactos (F1 → card 33c35e34; epoch-fallback y R1-coverage documentados en card). |
🧹 Preview CleanupPR #230 - Merged ✅ Preview apps eliminadas de Coolify (verificado via API): backend + frontend. Resources freed at 2026-09-08T11:15:04.965Z |
Supersedes #166. Covers the dependabot bumps #227 (dashboard/backend) and #228 (root) in a single PR so both manifests stay synchronized.
Plan
Implements phase 1 of
reports/opencode/qafw-stripe-migration-plan-2026-08-27.md(card 81f06b74, execution card 7c37a29f). Joker GO registered on the card (Re: msg 32370, 07-sep).Conditions (plan §5)
current_period_start/endread fromSubscription.items.data[0]with defensive fallback (create_subscription)._resolve_client_secret()supporting both pre-basil (invoice.payment_intent) and basil+ (invoice.payments.data[i].payment) shapes; contract tests document both. Sandbox/staging demo tracked on card 7c37a29f (test-mode keys GATED).requirements.txtanddashboard/backend/requirements.txtboth atstripe==15.6.1.git revert+ redeploy; rehearsal on staging pending (card).stripe.max_network_retries = 0pinned with rationale comment (v11+ default of 2 retries × 5s could block the event loop ~15s/call).asyncio.to_threadfollow-up noted, out of scope.Tests