vibes-plug 2.11.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/.claude/rules/vibes-plug-core.md +5 -0
  2. package/.cursor/rules/vibes-plug-core.mdc +8 -3
  3. package/.cursorrules +9 -3
  4. package/AGENTS.md +25 -4
  5. package/CHANGELOG.md +151 -0
  6. package/CLAUDE.md +15 -8
  7. package/README.md +216 -641
  8. package/bin/vibes.mjs +1104 -0
  9. package/index.js +1 -1
  10. package/package.json +11 -3
  11. package/plugin.json +4 -3
  12. package/scripts/check-anti-slop.js +53 -0
  13. package/scripts/check-anti-slop.mjs +53 -0
  14. package/scripts/generate_swarm_gif.py +2 -2
  15. package/scripts/install.js +3 -1
  16. package/scripts/update_skills.js +1 -1
  17. package/scripts/update_skills.mjs +86 -0
  18. package/scripts/validate-skills.mjs +111 -0
  19. package/skills/accessibility-testing-expert/SKILL.md +117 -116
  20. package/skills/affective-computing-emotion-ai/SKILL.md +83 -0
  21. package/skills/agentic-coding-workflow-expert/SKILL.md +297 -0
  22. package/skills/agentic-memory-architect/SKILL.md +52 -0
  23. package/skills/agentic-micro-economy-architect/SKILL.md +92 -0
  24. package/skills/ai-llm-integration-expert/SKILL.md +330 -187
  25. package/skills/ai-media-generation-expert/SKILL.md +173 -172
  26. package/skills/ai-prompt-engineering-expert/SKILL.md +170 -50
  27. package/skills/ai-safety-governance-expert/SKILL.md +223 -0
  28. package/skills/angular-expert/SKILL.md +149 -148
  29. package/skills/anti-slop/SKILL.md +134 -0
  30. package/skills/api-design-expert/SKILL.md +4 -3
  31. package/skills/api-gateway-proxy-expert/SKILL.md +3 -2
  32. package/skills/app-analyzer-optimizer/SKILL.md +4 -3
  33. package/skills/apple-ecosystem-expert/SKILL.md +6 -5
  34. package/skills/astro-framework-expert/SKILL.md +201 -200
  35. package/skills/async-queue-temporal-expert/SKILL.md +218 -240
  36. package/skills/authentication-identity-expert/SKILL.md +79 -184
  37. package/skills/autonomous-red-teamer/SKILL.md +338 -203
  38. package/skills/autonomous-tdd-debugger/SKILL.md +6 -5
  39. package/skills/biome-linter-formatter-expert/SKILL.md +90 -89
  40. package/skills/blockchain-web3-expert/SKILL.md +116 -115
  41. package/skills/brainstorming/SKILL.md +392 -377
  42. package/skills/browser-automation-expert/SKILL.md +260 -222
  43. package/skills/bun-runtime-expert/SKILL.md +5 -4
  44. package/skills/chatbot-messaging-expert/SKILL.md +115 -114
  45. package/skills/ci-cd-devops-architect/SKILL.md +3 -2
  46. package/skills/cloud-hosting-expert/SKILL.md +5 -4
  47. package/skills/coderabbit/SKILL.md +5 -4
  48. package/skills/compliance-gdpr-privacy-expert/SKILL.md +3 -2
  49. package/skills/composable-mach-architect/SKILL.md +338 -0
  50. package/skills/cron-scheduler-expert/SKILL.md +5 -4
  51. package/skills/data-pipeline-etl-expert/SKILL.md +3 -2
  52. package/skills/data-telemetry-expert/SKILL.md +5 -4
  53. package/skills/data-visualization-expert/SKILL.md +155 -154
  54. package/skills/database-orm-expert/SKILL.md +102 -240
  55. package/skills/deep-research-analyst/SKILL.md +182 -0
  56. package/skills/dependency-upgrade-migrator/SKILL.md +11 -10
  57. package/skills/design-system-architect/SKILL.md +34 -3
  58. package/skills/desktop-electron-expert/SKILL.md +129 -128
  59. package/skills/documentation-site-expert/SKILL.md +60 -59
  60. package/skills/doku-mcp-server/SKILL.md +5 -4
  61. package/skills/doku-payment-gateway/SKILL.md +250 -232
  62. package/skills/domain-driven-design-expert/SKILL.md +3 -2
  63. package/skills/e2e-testing-expert/SKILL.md +5 -4
  64. package/skills/ecommerce-expert/SKILL.md +88 -87
  65. package/skills/email-notification-expert/SKILL.md +35 -7
  66. package/skills/ephemeral-generative-ui-architect/SKILL.md +88 -0
  67. package/skills/error-resilience-expert/SKILL.md +26 -4
  68. package/skills/event-driven-architect/SKILL.md +5 -4
  69. package/skills/feature-flag-analytics-expert/SKILL.md +3 -2
  70. package/skills/file-upload-media-expert/SKILL.md +5 -4
  71. package/skills/firebase-security-expert/SKILL.md +5 -4
  72. package/skills/form-validation-expert/SKILL.md +7 -6
  73. package/skills/frontier-ai-models-expert/SKILL.md +116 -0
  74. package/skills/fullstack-expert/SKILL.md +68 -144
  75. package/skills/gemini-agent-booster/SKILL.md +248 -172
  76. package/skills/geospatial-maps-expert/SKILL.md +81 -80
  77. package/skills/global-a11y-i18n-expert/SKILL.md +5 -4
  78. package/skills/glsl-shader-expert/SKILL.md +155 -71
  79. package/skills/go-programming-expert/SKILL.md +5 -4
  80. package/skills/graph-rag-knowledge-expert/SKILL.md +201 -159
  81. package/skills/graphql-apollo-expert/SKILL.md +5 -4
  82. package/skills/headless-cms-expert/SKILL.md +182 -181
  83. package/skills/hig/SKILL.md +5 -4
  84. package/skills/js-backend-expert/SKILL.md +219 -218
  85. package/skills/legacy-code-translator/SKILL.md +6 -5
  86. package/skills/llm-finops-router/SKILL.md +52 -0
  87. package/skills/local-slm-edge-ai-expert/SKILL.md +168 -167
  88. package/skills/logging-error-tracking-expert/SKILL.md +5 -4
  89. package/skills/mcp-server-architect/SKILL.md +316 -294
  90. package/skills/micro-frontend-architect/SKILL.md +5 -4
  91. package/skills/mobile-expo-expert/SKILL.md +5 -4
  92. package/skills/modern-css-native-expert/SKILL.md +190 -189
  93. package/skills/monorepo-architect/SKILL.md +5 -4
  94. package/skills/mpa-orchestrator/SKILL.md +41 -4
  95. package/skills/multi-agent-orchestration/SKILL.md +388 -254
  96. package/skills/mvc-expert/SKILL.md +5 -4
  97. package/skills/n8n-automation-expert/SKILL.md +90 -89
  98. package/skills/nextjs-app-router-expert/SKILL.md +3 -2
  99. package/skills/openapi-swagger-codegen-expert/SKILL.md +4 -3
  100. package/skills/payment-gateway-expert/SKILL.md +131 -128
  101. package/skills/pdf-document-generation-expert/SKILL.md +92 -91
  102. package/skills/performance-web-vitals/SKILL.md +5 -4
  103. package/skills/post-quantum-crypto-migrator/SKILL.md +3 -2
  104. package/skills/prd-architect/SKILL.md +85 -109
  105. package/skills/proactive-background-watcher/SKILL.md +5 -4
  106. package/skills/production-ready-hardener/SKILL.md +25 -27
  107. package/skills/pwa-offline-first-expert/SKILL.md +227 -185
  108. package/skills/pydantic-ai-expert/SKILL.md +162 -0
  109. package/skills/python-programming-expert/SKILL.md +5 -4
  110. package/skills/rate-limit-abuse-prevention/SKILL.md +5 -4
  111. package/skills/realtime-collaboration-expert/SKILL.md +3 -2
  112. package/skills/rich-text-editor-expert/SKILL.md +178 -177
  113. package/skills/rust-programming-expert/SKILL.md +5 -4
  114. package/skills/saas-architect/SKILL.md +155 -0
  115. package/skills/saas-billing/SKILL.md +394 -382
  116. package/skills/saas-multi-tenant/SKILL.md +7 -6
  117. package/skills/scalability-clean-code/SKILL.md +5 -4
  118. package/skills/search-engine-expert/SKILL.md +90 -89
  119. package/skills/self-healing-cloud-orchestrator/SKILL.md +3 -2
  120. package/skills/senior-frontend/SKILL.md +21 -18
  121. package/skills/senior-frontend/scripts/frontend_scaffolder.py +1 -1
  122. package/skills/seo/SKILL.md +4 -4
  123. package/skills/session-memory-manager/SKILL.md +129 -0
  124. package/skills/solidjs-expert/SKILL.md +81 -80
  125. package/skills/spa-orchestrator/SKILL.md +5 -4
  126. package/skills/sse-websocket-streaming-expert/SKILL.md +3 -2
  127. package/skills/state-management-expert/SKILL.md +5 -4
  128. package/skills/supabase-security-expert/SKILL.md +5 -4
  129. package/skills/svelte-sveltekit-expert/SKILL.md +92 -91
  130. package/skills/svg-animation-motion-expert/SKILL.md +3 -2
  131. package/skills/synthetic-data-finetuning-expert/SKILL.md +156 -0
  132. package/skills/tailwind-expert/SKILL.md +62 -5
  133. package/skills/tanstack-query-expert/SKILL.md +5 -4
  134. package/skills/tauri-expert/SKILL.md +5 -4
  135. package/skills/typescript-expert/SKILL.md +5 -4
  136. package/skills/ui-ux-pro-max/SKILL.md +7 -4
  137. package/skills/vector-db-rag-expert/SKILL.md +209 -208
  138. package/skills/vercel-ai-sdk-expert/SKILL.md +226 -0
  139. package/skills/voice-ai-realtime-agent/SKILL.md +243 -202
  140. package/skills/vue-frontend-expert/SKILL.md +5 -4
  141. package/skills/wasm-edge-computing-expert/SKILL.md +3 -2
  142. package/skills/web-3d-graphics-expert/SKILL.md +259 -82
  143. package/skills/web-game-engine-expert/SKILL.md +278 -50
  144. package/skills/web-scraper/SKILL.md +158 -157
  145. package/skills/website-design-cloner/SKILL.md +5 -4
  146. package/skills/webxr-ar-vr-expert/SKILL.md +105 -65
  147. package/skills/wordpress-headless-expert/SKILL.md +145 -144
  148. package/skills/zero-tech-debt-auditor/SKILL.md +115 -0
  149. package/skills/zero-to-prod-orchestrator/SKILL.md +281 -227
  150. package/skills/zero-trust-secret-vault/SKILL.md +3 -2
  151. package/BLUEPRINT.md +0 -309
  152. package/skills/ai-cost-token-optimizer/SKILL.md +0 -82
  153. package/skills/ai-evals-benchmark-expert/SKILL.md +0 -188
  154. package/skills/asisten-ramah/SKILL.md +0 -47
  155. package/skills/auto-doc-updater/SKILL.md +0 -220
  156. package/skills/autonomous-chaos-monkey/SKILL.md +0 -63
  157. package/skills/background-jobs-queue-expert/SKILL.md +0 -235
  158. package/skills/bootstrap-to-modern/SKILL.md +0 -94
  159. package/skills/database-migration-versioning-expert/SKILL.md +0 -90
  160. package/skills/edge-serverless-db-expert/SKILL.md +0 -99
  161. package/skills/mcp-client-orchestrator/SKILL.md +0 -76
  162. package/skills/mobile-push-notification-expert/SKILL.md +0 -71
  163. package/skills/monday-design-aesthetic/SKILL.md +0 -73
  164. package/skills/multiple-entry-points/SKILL.md +0 -91
  165. package/skills/project-context-mapper/SKILL.md +0 -85
  166. package/skills/saas-mvp-launcher/SKILL.md +0 -260
  167. package/skills/saas-transformer/SKILL.md +0 -500
  168. package/skills/saas-transformer/references/billing_integration_guide.md +0 -401
  169. package/skills/secure-fuzz-testing/SKILL.md +0 -207
  170. package/skills/self-evolving-memory-graph/SKILL.md +0 -91
  171. package/skills/session-context-loader/SKILL.md +0 -83
  172. package/skills/session-handoff-resume/SKILL.md +0 -164
  173. package/skills/skill-baru/SKILL.md +0 -178
  174. package/skills/supabase-migration/SKILL.md +0 -91
  175. package/skills/token-saver/SKILL.md +0 -119
  176. package/skills/ui-components-expert/SKILL.md +0 -166
  177. package/skills/vibe-code-gardener/SKILL.md +0 -181
  178. package/skills/visual-qa-vision-agent/SKILL.md +0 -71
  179. /package/skills/{saas-transformer → saas-architect}/references/feature_gating_patterns.md +0 -0
  180. /package/skills/{saas-transformer → saas-architect}/references/saas_transformation_checklist.md +0 -0
  181. /package/skills/{saas-transformer → saas-architect}/scripts/saas_transformation_scanner.py +0 -0
@@ -1,401 +0,0 @@
1
- # Billing & Payment Gateway Integration Guide
2
-
3
- A comprehensive guide to setting up subscription billing, payment gateways, and Merchant of Record (MoR) systems. This guide covers Stripe, Midtrans, PayPal, Paddle, and FastSpring, detailing database structures and webhook verification in a multi-tenant SaaS application.
4
-
5
- ---
6
-
7
- ## 1. Gateway Type: Payment Gateway vs. Merchant of Record (MoR)
8
-
9
- Before choosing a billing system, it is vital to understand the two main categories of billing platforms:
10
-
11
- | Feature | Payment Gateway (Stripe, Midtrans, PayPal) | Merchant of Record (Paddle, FastSpring) |
12
- |---|---|---|
13
- | **Definition** | Processes payments but places legal/financial responsibilities on you. | Acts as the reseller of your software; handles transactions and compliance. |
14
- | **Sales Tax / VAT** | You must calculate, collect, and file taxes globally (using tools like Stripe Tax). | Automatically handles global taxes, compliance, and invoicing. |
15
- | **Chargeback Liability**| You manage chargeback disputes directly. | The MoR platform handles chargeback disputes. |
16
- | **Integration Complexity**| Highly customizable APIs, but requires more backend logic for compliance. | Simple to configure; checkout UI is managed by the MoR. |
17
-
18
- ---
19
-
20
- ## 2. Generic Multi-Gateway Database Schema
21
-
22
- To support multiple payment gateways, use a generic subscription schema.
23
-
24
- ### Prisma Schema (`prisma/schema.prisma`)
25
- ```prisma
26
- model Subscription {
27
- id String @id @default(cuid())
28
- workspaceId String @unique
29
- workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
30
- gateway String // "stripe", "midtrans", "paypal", "paddle", "fastspring"
31
- gatewayCustomerId String? @unique
32
- gatewaySubscriptionId String? @unique
33
- gatewayPriceId String?
34
- status String // "active", "trialing", "past_due", "canceled", "unpaid"
35
- currentPeriodEnd DateTime
36
- cancelAtPeriodEnd Boolean @default(false)
37
- createdAt DateTime @default(now())
38
- updatedAt DateTime @updatedAt
39
- }
40
- ```
41
-
42
- ### Drizzle ORM Schema (`lib/db/schema.ts`)
43
- ```typescript
44
- import { pgTable, text, timestamp, boolean } from 'drizzle-orm/pg-core';
45
-
46
- export const subscriptions = pgTable('subscriptions', {
47
- id: text('id').primaryKey(),
48
- workspaceId: text('workspace_id').notNull().unique(),
49
- gateway: text('gateway').notNull(), // "stripe", "midtrans", "paypal", "paddle", "fastspring"
50
- gatewayCustomerId: text('gateway_customer_id').unique(),
51
- gatewaySubscriptionId: text('gateway_subscription_id').unique(),
52
- gatewayPriceId: text('gateway_price_id'),
53
- status: text('status').notNull(),
54
- currentPeriodEnd: timestamp('current_period_end').notNull(),
55
- cancelAtPeriodEnd: boolean('cancel_at_period_end').default(false).notNull(),
56
- createdAt: timestamp('created_at').defaultNow().notNull(),
57
- updatedAt: timestamp('updated_at').defaultNow().notNull(),
58
- });
59
- ```
60
-
61
- ---
62
-
63
- ## 3. Webhook Implementations
64
-
65
- Webhooks are crucial to keep your SaaS database in sync with payment updates. Below are the implementation templates for Next.js 15 (App Router).
66
-
67
- ### A. Stripe Integration
68
- Processes subscriptions and invoices. Verified via the Stripe SDK.
69
-
70
- ```typescript
71
- import { NextResponse } from 'next/server';
72
- import Stripe from 'stripe';
73
- import { db } from '@/lib/db';
74
- import { subscriptions } from '@/lib/db/schema';
75
- import { eq } from 'drizzle-orm';
76
-
77
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2025-01-01' as any });
78
-
79
- export async function POST(req: Request) {
80
- const body = await req.text();
81
- const signature = req.headers.get('Stripe-Signature')!;
82
-
83
- let event: Stripe.Event;
84
- try {
85
- event = stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!);
86
- } catch (err: any) {
87
- return NextResponse.json({ error: `Signature verification failed: ${err.message}` }, { status: 400 });
88
- }
89
-
90
- switch (event.type) {
91
- case 'checkout.session.completed': {
92
- const session = event.data.object as Stripe.Checkout.Session;
93
- const workspaceId = session.metadata?.workspaceId;
94
- if (!workspaceId) break;
95
-
96
- const subscription = await stripe.subscriptions.retrieve(session.subscription as string);
97
- await db.insert(subscriptions).values({
98
- id: subscription.id,
99
- workspaceId,
100
- gateway: 'stripe',
101
- gatewayCustomerId: session.customer as string,
102
- gatewaySubscriptionId: subscription.id,
103
- gatewayPriceId: subscription.items.data[0].price.id,
104
- status: subscription.status,
105
- currentPeriodEnd: new Date(subscription.current_period_end * 1000),
106
- });
107
- break;
108
- }
109
- case 'invoice.payment_succeeded': {
110
- const invoice = event.data.object as Stripe.Invoice;
111
- if (!invoice.subscription) break;
112
- const subscription = await stripe.subscriptions.retrieve(invoice.subscription as string);
113
- await db.update(subscriptions)
114
- .set({
115
- status: subscription.status,
116
- currentPeriodEnd: new Date(subscription.current_period_end * 1000),
117
- })
118
- .where(eq(subscriptions.gatewaySubscriptionId, subscription.id));
119
- break;
120
- }
121
- case 'customer.subscription.deleted': {
122
- const subscription = event.data.object as Stripe.Subscription;
123
- await db.update(subscriptions)
124
- .set({ status: 'canceled' })
125
- .where(eq(subscriptions.gatewaySubscriptionId, subscription.id));
126
- break;
127
- }
128
- }
129
- return NextResponse.json({ received: true });
130
- }
131
- ```
132
-
133
- ### B. Midtrans Integration
134
- Southeast Asia's popular payment gateway. Verified via SHA512 signature key matching.
135
-
136
- ```typescript
137
- import { NextResponse } from 'next/server';
138
- import crypto from 'crypto';
139
- import { db } from '@/lib/db';
140
- import { subscriptions } from '@/lib/db/schema';
141
- import { eq } from 'drizzle-orm';
142
-
143
- export async function POST(req: Request) {
144
- const body = await req.json();
145
- const { order_id, status_code, gross_amount, signature_key, transaction_status, fraud_status } = body;
146
-
147
- // Verify signature key: sha512(order_id + status_code + gross_amount + server_key)
148
- const serverKey = process.env.MIDTRANS_SERVER_KEY!;
149
- const hashed = crypto
150
- .createHash('sha512')
151
- .update(order_id + status_code + gross_amount + serverKey)
152
- .digest('hex');
153
-
154
- if (hashed !== signature_key) {
155
- return NextResponse.json({ error: 'Invalid Midtrans signature' }, { status: 400 });
156
- }
157
-
158
- // Update subscription/payment state based on transaction_status
159
- if (transaction_status === 'capture' || transaction_status === 'settlement') {
160
- if (fraud_status === 'challenge') {
161
- await db.update(subscriptions).set({ status: 'unpaid' }).where(eq(subscriptions.id, order_id));
162
- } else {
163
- await db.update(subscriptions)
164
- .set({ status: 'active', currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) })
165
- .where(eq(subscriptions.id, order_id));
166
- }
167
- } else if (['cancel', 'deny', 'expire'].includes(transaction_status)) {
168
- await db.update(subscriptions).set({ status: 'canceled' }).where(eq(subscriptions.id, order_id));
169
- } else if (transaction_status === 'pending') {
170
- await db.update(subscriptions).set({ status: 'unpaid' }).where(eq(subscriptions.id, order_id));
171
- }
172
-
173
- return NextResponse.json({ success: true });
174
- }
175
- ```
176
-
177
- ### C. PayPal Integration
178
- Global subscription billing. Verified via PayPal API request validation.
179
-
180
- ```typescript
181
- import { NextResponse } from 'next/server';
182
- import { db } from '@/lib/db';
183
- import { subscriptions } from '@/lib/db/schema';
184
- import { eq } from 'drizzle-orm';
185
-
186
- async function verifyPayPalSignature(headers: Headers, rawBody: string, webhookId: string) {
187
- // Call PayPal API to verify signature authenticity
188
- const endpoint = process.env.PAYPAL_MODE === 'live'
189
- ? 'https://api-m.paypal.com'
190
- : 'https://api-m.sandbox.paypal.com';
191
-
192
- const authHeader = headers.get('authorization');
193
- if (!authHeader) return false;
194
-
195
- const response = await fetch(`${endpoint}/v1/notifications/verify-webhook-signature`, {
196
- method: 'POST',
197
- headers: {
198
- 'Content-Type': 'application/json',
199
- 'Authorization': authHeader,
200
- },
201
- body: JSON.stringify({
202
- auth_algo: headers.get('paypal-auth-algo'),
203
- cert_url: headers.get('paypal-cert-url'),
204
- transmission_id: headers.get('paypal-transmission-id'),
205
- transmission_sig: headers.get('paypal-transmission-sig'),
206
- transmission_time: headers.get('paypal-transmission-time'),
207
- webhook_id: webhookId,
208
- webhook_event: JSON.parse(rawBody),
209
- }),
210
- });
211
-
212
- const verification = await response.json();
213
- return verification.verification_status === 'SUCCESS';
214
- }
215
-
216
- export async function POST(req: Request) {
217
- const rawBody = await req.text();
218
- const webhookId = process.env.PAYPAL_WEBHOOK_ID!;
219
-
220
- const isValid = await verifyPayPalSignature(req.headers, rawBody, webhookId);
221
- if (!isValid) {
222
- return NextResponse.json({ error: 'PayPal signature invalid' }, { status: 400 });
223
- }
224
-
225
- const event = JSON.parse(rawBody);
226
-
227
- switch (event.event_type) {
228
- case 'BILLING.SUBSCRIPTION.CREATED': {
229
- const sub = event.resource;
230
- const workspaceId = sub.custom_id; // Pass workspace ID in custom_id
231
- if (!workspaceId) break;
232
-
233
- await db.insert(subscriptions).values({
234
- id: sub.id,
235
- workspaceId,
236
- gateway: 'paypal',
237
- gatewayCustomerId: sub.subscriber.payer_id,
238
- gatewaySubscriptionId: sub.id,
239
- gatewayPriceId: sub.plan_id,
240
- status: 'active',
241
- currentPeriodEnd: new Date(sub.billing_info.next_billing_time),
242
- });
243
- break;
244
- }
245
- case 'BILLING.SUBSCRIPTION.CANCELLED': {
246
- const sub = event.resource;
247
- await db.update(subscriptions)
248
- .set({ status: 'canceled' })
249
- .where(eq(subscriptions.gatewaySubscriptionId, sub.id));
250
- break;
251
- }
252
- }
253
-
254
- return NextResponse.json({ received: true });
255
- }
256
- ```
257
-
258
- ### D. Paddle Integration (Paddle Billing v2)
259
- Merchant of Record. Verified locally using an HMAC-SHA256 signature key verification.
260
-
261
- ```typescript
262
- import { NextResponse } from 'next/server';
263
- import crypto from 'crypto';
264
- import { db } from '@/lib/db';
265
- import { subscriptions } from '@/lib/db/schema';
266
- import { eq } from 'drizzle-orm';
267
-
268
- function verifyPaddleSignature(body: string, signatureHeader: string, secret: string): boolean {
269
- const parts = signatureHeader.split(';');
270
- const tsPart = parts.find(p => p.startsWith('ts='));
271
- const h1Part = parts.find(p => p.startsWith('h1='));
272
- if (!tsPart || !h1Part) return false;
273
-
274
- const ts = tsPart.split('=')[1];
275
- const h1 = h1Part.split('=')[1];
276
-
277
- const payload = `${ts}:${body}`;
278
- const computedHash = crypto.createHmac('sha256', secret).update(payload).digest('hex');
279
- return computedHash === h1;
280
- }
281
-
282
- export async function POST(req: Request) {
283
- const rawBody = await req.text();
284
- const signature = req.headers.get('Paddle-Signature')!;
285
- const secret = process.env.PADDLE_WEBHOOK_SECRET!;
286
-
287
- if (!verifyPaddleSignature(rawBody, signature, secret)) {
288
- return NextResponse.json({ error: 'Invalid Paddle signature' }, { status: 400 });
289
- }
290
-
291
- const event = JSON.parse(rawBody);
292
- const eventType = event.event_type;
293
- const data = event.data;
294
-
295
- switch (eventType) {
296
- case 'subscription.created':
297
- case 'subscription.updated': {
298
- const workspaceId = data.custom_data?.workspaceId;
299
- if (!workspaceId) break;
300
-
301
- await db.insert(subscriptions).values({
302
- id: data.id,
303
- workspaceId,
304
- gateway: 'paddle',
305
- gatewayCustomerId: data.customer_id,
306
- gatewaySubscriptionId: data.id,
307
- gatewayPriceId: data.items[0].price.id,
308
- status: data.status, // active, trialing, paused
309
- currentPeriodEnd: new Date(data.current_billing_period.ends_at),
310
- }).onConflictDoUpdate({
311
- target: subscriptions.workspaceId,
312
- set: {
313
- status: data.status,
314
- currentPeriodEnd: new Date(data.current_billing_period.ends_at),
315
- gatewayPriceId: data.items[0].price.id,
316
- }
317
- });
318
- break;
319
- }
320
- case 'subscription.canceled': {
321
- await db.update(subscriptions)
322
- .set({ status: 'canceled' })
323
- .where(eq(subscriptions.gatewaySubscriptionId, data.id));
324
- break;
325
- }
326
- }
327
-
328
- return NextResponse.json({ received: true });
329
- }
330
- ```
331
-
332
- ### E. FastSpring Integration
333
- Merchant of Record. Verified via an HMAC-SHA256 signature key verification.
334
-
335
- ```typescript
336
- import { NextResponse } from 'next/server';
337
- import crypto from 'crypto';
338
- import { db } from '@/lib/db';
339
- import { subscriptions } from '@/lib/db/schema';
340
- import { eq } from 'drizzle-orm';
341
-
342
- function verifyFastSpringSignature(body: string, signature: string, secretKey: string): boolean {
343
- const hash = crypto.createHmac('sha256', secretKey).update(body).digest('base64');
344
- return hash === signature;
345
- }
346
-
347
- export async function POST(req: Request) {
348
- const rawBody = await req.text();
349
- const signature = req.headers.get('X-FS-Signature')!;
350
- const secretKey = process.env.FASTSPRING_SHARED_SECRET!;
351
-
352
- if (!verifyFastSpringSignature(rawBody, signature, secretKey)) {
353
- return NextResponse.json({ error: 'Invalid FastSpring signature' }, { status: 400 });
354
- }
355
-
356
- const payload = JSON.parse(rawBody);
357
-
358
- for (const event of payload.events) {
359
- switch (event.type) {
360
- case 'subscription.activated': {
361
- const sub = event.data;
362
- const workspaceId = sub.tags?.workspaceId;
363
- if (!workspaceId) break;
364
-
365
- await db.insert(subscriptions).values({
366
- id: sub.id,
367
- workspaceId,
368
- gateway: 'fastspring',
369
- gatewayCustomerId: sub.account,
370
- gatewaySubscriptionId: sub.id,
371
- gatewayPriceId: sub.product,
372
- status: 'active',
373
- currentPeriodEnd: new Date(sub.nextSession),
374
- });
375
- break;
376
- }
377
- case 'subscription.canceled': {
378
- const sub = event.data;
379
- await db.update(subscriptions)
380
- .set({ status: 'canceled' })
381
- .where(eq(subscriptions.gatewaySubscriptionId, sub.id));
382
- break;
383
- }
384
- }
385
- }
386
-
387
- return NextResponse.json({ received: true });
388
- }
389
- ```
390
-
391
- ---
392
-
393
- ## 4. Best Practices for Webhook Handlers
394
-
395
- 1. **Webhook Idempotency**: Payment gateways can redeliver webhooks. Always store a list of processed event IDs in your database to prevent duplicate actions:
396
- ```typescript
397
- const processed = await db.query.processedEvents.findFirst({ where: eq(processedEvents.id, eventId) });
398
- if (processed) return NextResponse.json({ received: true });
399
- ```
400
- 2. **Handle Async Work Gracefully**: Send a fast response (`200 OK`) back to the gateway first, then process any heavy logic asynchronously (or via queue systems like BullMQ) if necessary, to avoid gateway timeouts.
401
- 3. **Database Locks**: Run your update queries inside clean transactions to avoid concurrency anomalies.
@@ -1,207 +0,0 @@
1
- ---
2
- name: secure-fuzz-testing
3
- description: "Expert-level skill for writing and integrating coverage-guided fuzz tests in Python, Rust, and Go for secure code validation in English and Indonesian."
4
- author: "Roedy Rustam"
5
- ---
6
-
7
- # Secure Fuzz Testing
8
-
9
- [English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
10
-
11
- ---
12
-
13
- <a name="english"></a>
14
- ## English
15
-
16
- ### Orchestration & Integration
17
- Connects and orchestrates with relevant domain skills like `brainstorming`, `zero-to-prod-orchestrator`, and `project-context-mapper` to ensure cohesive execution.
18
-
19
- ### Description
20
- Expert-level guidance for writing, running, and integrating coverage-guided fuzz tests (fuzzing) to identify security vulnerabilities, memory leaks, and input-validation issues in software applications. This skill covers writing fuzz targets in **Python**, **Rust**, and **Go**, configuring compilers with sanitizers (ASan, MSan, UBSan), and setting up automated CI/CD security pipelines.
21
-
22
- ### Trigger Conditions
23
- - Use when designing or reviewing data parsers, serialization/deserialization logic, or file formats.
24
- - Use when writing libraries that process untrusted network input or binary data streams.
25
- - Use when integrating automated security testing into a DevSecOps pipeline (CI/CD).
26
- - Use when troubleshooting complex memory bugs, edge-case crashes, or unhandled exceptions.
27
-
28
- ### Writing Fuzz Targets
29
- Coverage-guided fuzzers need a target function that accepts a stream of bytes and processes it.
30
-
31
- #### 1. Python Fuzzing (Atheris)
32
- `Atheris` is a coverage-guided fuzzer for Python. It can fuzz Python code and native extensions:
33
- ```python
34
- import sys
35
- import atheris
36
-
37
- with atheris.instrument_imports():
38
- import our_parser # Import target module inside instrument_imports
39
-
40
- def TestOneInput(data):
41
- if len(data) < 4:
42
- return
43
- try:
44
- # Decode and parse the byte data
45
- text = data.decode("utf-8", errors="ignore")
46
- our_parser.parse_config(text)
47
- except our_parser.ParseException:
48
- # Expected exceptions should be caught to avoid false positives
49
- pass
50
-
51
- atheris.Setup(sys.argv, TestOneInput)
52
- atheris.Fuzz()
53
- ```
54
-
55
- #### 2. Rust Fuzzing (cargo-fuzz & libFuzzer)
56
- Rust has first-class fuzzing support via `cargo-fuzz` which wraps `libFuzzer`:
57
- ```rust
58
- #![no_main]
59
- use libfuzzer_sys::fuzz_target;
60
-
61
- fuzz_target!(|data: &[u8]| {
62
- if let Ok(input_str) = std::str::from_utf8(data) {
63
- let _ = our_crate::parse_config(input_str);
64
- }
65
- });
66
- ```
67
- - **Run Fuzzer**: Execute `cargo +nightly fuzz run <target_name>`.
68
-
69
- #### 3. Go Fuzzing (Native Go Fuzz)
70
- Go supports native fuzzing in its standard library (`testing` package):
71
- ```go
72
- package main
73
-
74
- import (
75
- "testing"
76
- "ourmodule/parser"
77
- )
78
-
79
- func FuzzParseConfig(f *testing.F) {
80
- // Add seed corpus for initial coverage guidance
81
- f.Add([]byte("config_key = value"))
82
-
83
- f.Fuzz(func(t *testing.T, data []byte) {
84
- _, err := parser.ParseConfig(data)
85
- if err != nil {
86
- t.Skip() // Skip expected/graceful errors
87
- }
88
- })
89
- }
90
- ```
91
- - **Run Fuzzer**: Run `go test -fuzz=FuzzParseConfig -fuzztime=10m`.
92
-
93
- ### Diagnostics & Sanitizers
94
- Use compiler instrumentation flags to expose hidden bugs:
95
- - **AddressSanitizer (ASan)**: Detects out-of-bounds access, use-after-free, and memory leaks.
96
- - **UndefinedBehaviorSanitizer (UBSan)**: Detects integer overflows, alignment issues, and division by zero.
97
- - **ThreadSanitizer (TSan)**: Finds data races in multithreaded environments.
98
-
99
- ### DevSecOps & CI Integration
100
- - **OSS-Fuzz**: For open-source projects, integrate with Google's OSS-Fuzz for continuous fuzzing infrastructure.
101
- - **GitHub Actions**: Run fuzz targets on pull requests with short run times (`fuzztime=5m`) to catch regression errors without blocking pipelines.
102
-
103
- ---
104
-
105
- ### Troubleshooting & Common Gotchas
106
- - **False Positives**: Ensure expected API errors and clean validation errors do not cause the fuzzer to abort. Catch expected exceptions or use `t.Skip()` where appropriate.
107
- - **State Pollution**: Fuzz targets must be stateless. Avoid sharing mutable global states between iterations.
108
- - **Infinite Loops**: Guard against code that hangs. Configure timeouts (`-timeout=25` in libFuzzer) to automatically crash long-running executions.
109
-
110
- ---
111
-
112
- <a name="bahasa-indonesia"></a>
113
- ## Bahasa Indonesia
114
-
115
- ### Integrasi Orkestrasi
116
- Terhubung dan mengorkestrasi skill domain yang relevan seperti `brainstorming`, `zero-to-prod-orchestrator`, dan `project-context-mapper` untuk memastikan eksekusi yang kohesif.
117
-
118
- ### Deskripsi
119
- Panduan tingkat ahli untuk menulis, menjalankan, dan mengintegrasikan pengujian berbasis cakupan (*coverage-guided fuzzing*) untuk mengidentifikasi celah keamanan, kebocoran memori, dan kesalahan validasi input dalam aplikasi perangkat lunak. Skill ini mencakup penulisan target fuzzing dalam bahasa **Python**, **Rust**, dan **Go**, konfigurasi compiler dengan sanitizer (ASan, MSan, UBSan), serta penyiapan pipa otomatisasi keamanan CI/CD.
120
-
121
- ### Kondisi Pemicu
122
- - Gunakan saat merancang atau memeriksa parser data, logika serialisasi/deserialisasi, atau pemroses format berkas.
123
- - Gunakan saat menulis pustaka (*library*) yang memproses input jaringan yang tidak tepercaya atau aliran data biner.
124
- - Gunakan saat mengintegrasikan pengujian keamanan otomatis ke dalam alur kerja DevSecOps (CI/CD).
125
- - Gunakan saat mendiagnosis bug memori yang kompleks, crash pada kasus ekstrem (*edge-cases*), atau *exception* yang tidak ditangani.
126
-
127
- ### Penulisan Target Fuzzing
128
- Fuzzer berbasis cakupan memerlukan fungsi target yang menerima aliran byte untuk kemudian diproses secara dinamis.
129
-
130
- #### 1. Fuzzing Python (Atheris)
131
- `Atheris` adalah fuzzer berbasis cakupan untuk kode Python dan ekstensi native (C/C++):
132
- ```python
133
- import sys
134
- import atheris
135
-
136
- with atheris.instrument_imports():
137
- import our_parser # Impor modul target di dalam instrument_imports
138
-
139
- def TestOneInput(data):
140
- if len(data) < 4:
141
- return
142
- try:
143
- # Dekode data byte menjadi teks
144
- text = data.decode("utf-8", errors="ignore")
145
- our_parser.parse_config(text)
146
- except our_parser.ParseException:
147
- # Tangkap exception yang diharapkan agar tidak dianggap crash palsu
148
- pass
149
-
150
- atheris.Setup(sys.argv, TestOneInput)
151
- atheris.Fuzz()
152
- ```
153
-
154
- #### 2. Fuzzing Rust (cargo-fuzz & libFuzzer)
155
- Rust memiliki dukungan fuzzing kelas satu melalui utilitas `cargo-fuzz` yang menggunakan pustaka `libFuzzer`:
156
- ```rust
157
- #![no_main]
158
- use libfuzzer_sys::fuzz_target;
159
-
160
- fuzz_target!(|data: &[u8]| {
161
- if let Ok(input_str) = std::str::from_utf8(data) {
162
- let _ = our_crate::parse_config(input_str);
163
- }
164
- });
165
- ```
166
- - **Jalankan Fuzzer**: Eksekusi perintah `cargo +nightly fuzz run <nama_target>`.
167
-
168
- #### 3. Fuzzing Go (Native Go Fuzz)
169
- Go mendukung pengujian fuzzing secara native dalam pustaka standarnya (`testing` package):
170
- ```go
171
- package main
172
-
173
- import (
174
- "testing"
175
- "ourmodule/parser"
176
- )
177
-
178
- func FuzzParseConfig(f *testing.F) {
179
- // Tambahkan seed corpus awal sebagai panduan awal cakupan fuzzer
180
- f.Add([]byte("config_key = value"))
181
-
182
- f.Fuzz(func(t *testing.T, data []byte) {
183
- _, err := parser.ParseConfig(data)
184
- if err != nil {
185
- t.Skip() // Lewati error yang memang diharapkan (ditangani dengan aman)
186
- }
187
- })
188
- }
189
- ```
190
- - **Jalankan Fuzzer**: Eksekusi perintah `go test -fuzz=FuzzParseConfig -fuzztime=10m`.
191
-
192
- ### Diagnosis & Sanitizer
193
- Gunakan tanda instrumentasi kompiler untuk mendeteksi bug tersembunyi secara dini:
194
- - **AddressSanitizer (ASan)**: Mendeteksi akses memori di luar batas (*out-of-bounds*), penggunaan setelah dibebaskan (*use-after-free*), dan kebocoran memori (*memory leak*).
195
- - **UndefinedBehaviorSanitizer (UBSan)**: Mendeteksi overflow integer, masalah penyelarasan memori (*alignment*), dan pembagian dengan nol.
196
- - **ThreadSanitizer (TSan)**: Menemukan perebutan data (*data race*) pada eksekusi multithread.
197
-
198
- ### Integrasi DevSecOps & CI
199
- - **OSS-Fuzz**: Untuk proyek open-source, integrasikan dengan platform OSS-Fuzz dari Google untuk pemantauan berkelanjutan.
200
- - **GitHub Actions**: Jalankan target fuzzing pada pull request dengan batasan waktu yang singkat (`fuzztime=5m`) untuk menangkap regresi kode tanpa menghambat alur build.
201
-
202
- ---
203
-
204
- ### Pemecahan Masalah & Kesalahan Umum
205
- - **Crash Palsu (False Positives)**: Pastikan error API yang ditangani dengan aman tidak membuat fuzzer berhenti. Tangkap exception tersebut atau gunakan `t.Skip()` pada Go.
206
- - **Polusi State (State Pollution)**: Pastikan target fuzzing bersifat stateless. Jangan biarkan state global mutable dibagikan antar iterasi pengujian.
207
- - **Loop Tak Terbatas**: Waspadai kode yang mengalami hang. Konfigurasikan batas waktu (`-timeout=25` pada libFuzzer) agar eksekusi yang macet secara otomatis dilaporkan sebagai crash.