All documentation

Reviews & Audits

Module 15 Community Edition Guarantee Review

Scope: verify Module 15's additions (billing/monetization, usage/quotas, marketplace security, API platform hardening, integrations, AI cost control, privacy/telemetry, i18n/accessibility, onboarding/demo, health/error-handling/support, release engineering, feature flags) hold the platform's standing guarantee — no mandatory paid service, a self-hosted deployment fully functional with zero external accounts, external/paid services always opt-in. Static review; no live cluster stood up (same limitation every prior guarantee review in this directory discloses).

Result: guarantee holds. No violations found.

Findings

1. BILLING_PROVIDER defaults to none. env.validation.ts: z.enum(['none', 'stripe', 'manual']).default('none'). BillingService/SubscriptionService still create a real Subscription row per organization even with no provider configured — pinned to PlanTier.FREE, whose Plan.limits (packages/shared/src/plan-defaults.ts) are UNLIMITED on every metered resource by seed default. No Stripe account, no API key, and no external network call is required to use any core feature (recon, vuln scanning, AI chat, reports, workflows, plugins) on the default configuration.

2. StripeWebhookController/StripePaymentProvider are additive, not required. Registered unconditionally as a controller (harmless — it just 503s if STRIPE_WEBHOOK_SECRET is unset), but nothing else in the request path depends on Stripe being configured. BILLING_PROVIDER=none means PaymentProviderFactory never even constructs a StripePaymentProvider instance.

3. No M15 route uses @RequiresEdition('enterprise'). Searched every new controller (billing/, feature-flags/, support/, the new observability additions) — the only Enterprise-gated routes in the entire codebase remain the pre-existing Module 14 tenant-management ones (enterprise/controllers/organizations.controller.ts and friends), which this module didn't touch. Billing, quotas, feature flags, and support are all reachable identically regardless of PENTESTHUB_EDITION.

4. QuotaService's enforcement is opt-in by construction. A quota only ever blocks an action if a QuotaPolicy row exists at some scope, or the org's Plan.limits entry for that resource is non-null. A self-hosted deployment on the default FREE plan and default (empty) QuotaPolicy table sees resolveLimit() return { softLimit: null, hardLimit: null } for everything, which QuotaService.check() maps directly to allowed: true with no database write and no throttling.

5. FeatureFlagsService's editionRules.minEdition: "enterprise" is per-flag, opt-in, and defaults to absent. FeatureFlag.editionRules is nullable; a flag with no editionRules evaluates purely on defaultEnabled/overrides, never on edition. No seed data or migration in this module creates a flag that gates a core feature behind minEdition: "enterprise" — the mechanism exists for a deployment operator to use, but Module 15 itself doesn't use it against anything.

6. Marketplace security additions apply uniformly, not as a paid gate. Publisher verification, checksums, and permission-declaration enforcement (task #333/#334) are integrity/trust controls that apply the same way regardless of PlanTier or PENTESTHUB_EDITION — a self-hosted Community deployment gets the same signature/checksum verification as a hosted Enterprise one; nothing about marketplace security itself requires a paid plan.

7. MAIL_PROVIDER defaults to DevMailService (writes to .mail-outbox/ — Module 1, unchanged), so the new Support ticket flow and Stripe confirmation-email-adjacent paths work with zero mail infrastructure configured; MAIL_PROVIDER=smtp (task #338) is opt-in and accepts any SMTP relay, free or paid, self-hosted or not.

8. RELEASE_CHANNEL and the CHANGELOG.md/versioning work (task #356) have no runtime cost or gating implication — purely descriptive metadata.

9. SUPPORT_INBOX_EMAIL defaults to a placeholder address (support@pentesthub.ai) rather than requiring configuration — the ticket-intake endpoint still functions (writes the row, attempts to email, logs a failure via the existing "channel failures never break the write" posture if mail isn't configured) even on a deployment that never sets this variable.

Conclusion

Every Module 15 subsystem reviewed defaults to free/local/self-hosted behavior, treats every paid-adjacent integration (Stripe, SMTP) as strictly opt-in with graceful degradation when unconfigured, and introduces no new Enterprise-only gate on core functionality. The guarantee holds.