Security¶
Isolation model¶
Each tenant is provisioned as a dedicated Frappe site with its own database. This provides database-level isolation; no query can span tenants. The platform service does not access tenant databases directly. It uses the bench CLI for provisioning and the Frappe REST API for tenant data, each scoped to a single site.
The platform's own database holds only tenant metadata, such as slug, status, and billing records, and never ERP business data.
Controls in place¶
- Secrets encrypted at rest. Tenant administrator passwords and API secrets are encrypted before storage, using a key derived from the platform secret key. A database export alone cannot recover a usable credential.
- Restricted cross-origin access. The public endpoints accept requests only from an explicit list of allowed origins.
- Rate limiting. The public endpoints are rate limited per client address, which prevents sign-up abuse from triggering repeated site provisioning.
- Authenticated administrative access. Administrative endpoints require an API key, compared in constant time, and fail closed when no key is configured.
- Verified payment webhooks. Stripe callbacks are verified by signature and fail closed when a signing secret is configured; M-Pesa callbacks support an optional source-address allowlist.
- Response hardening. Security headers are applied to every response, and transport security is enforced in production.
- Safe provisioning. Provisioning arguments are shell-escaped and tenant slugs are validated against a strict pattern before use.
- Privileged operations guarded. Administrative application methods require the appropriate role.
Financial separation¶
Project managers cannot create purchase invoices or receipts; these are intentional restrictions. The M-Pesa import workflow creates draft journal entries, allowing a project manager to prepare them, while posting to the ledger requires the finance role at submission. Access to the M-Pesa import document should be limited to the roles intended to use it.
Outstanding items¶
- Set strong platform secret and API keys and a production origin list before onboarding live tenants.
- Add email verification to sign-up once transactional email is configured; this also prevents sign-up with another party's email address.
- Back the rate limiter with a shared store when running multiple workers.
- Implement the payment business logic behind the verified webhook signatures.