[dev] [claudfuen] feat/pentest-subscription-billing#2220
[dev] [claudfuen] feat/pentest-subscription-billing#2220github-actions[bot] wants to merge 7 commits intomainfrom
Conversation
Icons (AppShellWrapper — rail): - Compliance: CertificateCheck → Badge (certification badge) - Trust: CloudAuditing → Globe (public/global trust center) - Security: Security → ManageProtection (protection management) Icons (AppSidebar — compliance sidebar): - Auditor View: TaskComplete → DocumentSigned (auditors sign off) - Controls: Security → SettingsAdjust (adjustable params, no dupe) - Documents: Catalog → FolderDetails (folder of docs) - People: Group → UserMultiple (standard multi-user) - Risks: Warning → Scale (weighing risk) - Vendors: ShoppingBag → Partnership (business partners) - Questionnaire: Document → DocumentTasks (task-filled form) - Integrations: Integration → Connect (connecting systems) - Cloud Tests: Chemistry → TestTool (test tooling) Overview: - Replace <DraggableCards> with a plain 2-column grid - Delete DraggableCards.tsx, SortableCard.tsx, useCardOrder.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The id returned by the create API is the provider run ID stored in providerRunId, not the internal ptr... primary key. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ntest-subscription-billing
Show a locked marketing state when the org has no active pentest subscription. Includes a reusable ModuleGate component in @comp/ui with dark chrome-frame preview, and an animated pen-test demo that cycles through agents and reveals findings with severity badges. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR SummaryHigh Risk Overview Billing flow is hardened and moved earlier in the run lifecycle. Server actions now require org admin/owner (not just membership), block duplicate active subscriptions, add Billing page and Stripe webhook coverage are expanded. The billing page is reworked into a subscriptions table (active/cancelled/past_due states, usage/renewal, manage/fix payment CTAs) with an expanded pentest usage section; Stripe pentest webhook now has comprehensive tests for checkout completion and subscription update/delete events. Data/API contract tweaks. Written by Cursor Bugbot for commit 1b06c7a. This will update automatically on new commits. Configure here. |
...pp/src/app/(app)/[orgId]/security/penetration-tests/components/pentest-preview-animation.tsx
Show resolved
Hide resolved
- Add preauthorize billing check before run creation (prevents unbilled runs) - Add dynamic pricing from Stripe (subscription + overage prices) - Add usage tracking in pentest page header and create dialog - Add overage confirmation dialog when included runs are exhausted - Add billing page with subscription table, usage details, and payment method - Add role-based auth (admin/owner only) for billing server actions - Add duplicate subscription guard in subscribeToPentestPlan - Add webhook unit tests (10 cases covering all event types) - Fix period boundary queries (lte → lt) to prevent double-counting - Fix payment method lookup to check subscription PM before customer PM - Fix PaymentIntent config (off_session instead of conflicting options) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
apps/app/src/app/(app)/[orgId]/security/penetration-tests/hooks/use-penetration-tests.ts
Show resolved
Hide resolved
apps/app/src/app/(app)/[orgId]/security/penetration-tests/actions/billing.ts
Outdated
Show resolved
Hide resolved
- Fix animation interval spawning duplicate reset timers (added pausing flag) - Use stable nonce ref to prevent duplicate overage charges on retry - Remove dead getPentestUsage function and PentestUsage interface Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| }); | ||
| if (existingSub?.status === 'active') { | ||
| throw new Error('Organization already has an active pentest subscription.'); | ||
| } |
There was a problem hiding this comment.
Duplicate Stripe subscription possible for past-due status
High Severity
The duplicate-subscription guard in subscribeToPentestPlan only blocks active status, but past_due subscriptions are not blocked. The pentest page checks hasActiveSubscription (only true for active), so a past_due subscriber sees the "Get started" button which calls subscribeToPentestPlan. This creates a brand-new Stripe subscription while the old past_due one still exists. The DB record is overwritten via upsert, so the old subscription becomes untracked — the customer gets billed twice by Stripe with no way to cancel the orphaned subscription through the app.
Additional Locations (1)
| const authResult = await preauthorizePentestRun(organizationId, nonceRef.current); | ||
| if (!authResult.authorized) { | ||
| throw new Error(authResult.error ?? 'Billing authorization failed.'); | ||
| } |
There was a problem hiding this comment.
Pre-creation billing check introduces overage race condition
Medium Severity
Moving billing authorization before run creation introduces a TOCTOU race. Two concurrent requests can both call preauthorizePentestRun, both see the same runsThisPeriod count below the included limit, and both get authorized: true without overage. Both then create runs, exceeding the included limit without any overage charge. The previous post-creation check didn't have this issue because the run already existed in the DB when the count was performed.


Summary
Environment Variables
Three new env vars are required for pentest billing to function. All are optional — the app won't crash without them, but billing features will return descriptive errors.
STRIPE_PENTEST_SUBSCRIPTION_PRICE_IDprice_1T6vZa...STRIPE_PENTEST_OVERAGE_PRICE_IDprice_1T6va1...STRIPE_PENTEST_WEBHOOK_SECRET/api/webhooks/stripe-pentestendpointwhsec_...Stripe setup
STRIPE_PENTEST_SUBSCRIPTION_PRICE_IDSTRIPE_PENTEST_OVERAGE_PRICE_ID<app-url>/api/webhooks/stripe-pentestlistening for:customer.subscription.updatedcustomer.subscription.deletedinvoice.payment_failedSTRIPE_PENTEST_WEBHOOK_SECRETTest plan
🤖 Generated with Claude Code