Security model
Secure HTTP, authentication, uploads, databases, plugins, and operational access.
Ridu’s central security rule is simple: authoring UI state is never authority. REST, GraphQL, the generated SDK, the admin, local operations, hooks, and durable tasks converge on server-owned schema, access, validation, transaction, and redaction contracts.
The table below separates Ridu’s controls from the security work owned by your application and infrastructure.
Trust boundaries
Ridu protects content and version history, credentials and sessions, private uploads, migration identity, task data, preview capabilities, and generated application contracts.
- An untrusted browser or API client reaches the Go HTTP server through deployment-owned TLS and optional trusted proxies.
- The server authenticates, authorizes, validates, runs hooks, and applies field redaction before one official store transaction observes or mutates content.
- The selected database and object storage are separate durable systems. Staged-object rollback, locks, last-reference scans, reconciliation, and matched backups bridge the fact that they cannot share one atomic commit.
- The Svelte admin and static admin plugins execute in the browser. They improve authoring but cannot grant server access.
- Go config, hooks, validators, task handlers, and backend plugins execute inside the trusted server process. Installing one is equivalent to installing application code; Ridu does not sandbox it.
Operators, application authors, and compiled plugins can control the process and its credentials. Treat authors, clients, compromised browser state, uploaded bytes, remote URLs, headers, filters, GraphQL documents, generated-client input, and stored application content as untrusted.
Framework and deployment responsibilities
| Surface | Ridu enforces | You must provide |
|---|---|---|
| REST and GraphQL | Body/query/token/member/depth bounds, stable errors, panic redaction, atomic access predicates, field redaction, optimistic conflicts, and bounded population/complexity. | Independent edge and abuse limits for public high-volume APIs, plus monitoring of rejection and error rates. |
| Sessions and credentials | Bounded bcrypt admission, generic auth failures, distributed login/recovery/verification throttles, rotation/revocation, HTTP-only secure/SameSite cookies, CSRF and origin checks. | Signing-secret protection, HTTPS, allowed origins, and application-specific password and identity policy. |
| Hosts and proxies | Explicit allowed hosts/origins, trusted-proxy CIDRs, CORS, CSP, security headers, and optional HSTS. | Only the public hosts you serve and immediate proxy networks; forwarding-header stripping; HSTS only behind permanent HTTPS. |
| Uploads | Size and MIME admission, name and path normalization, namespace ownership, image work bounds, SSRF-safe remote fetches, private delivery checks, object locks, rollback, and reconciliation. | Malware scanning/quarantine where required, a production storage backend, and matched database/object backups. |
| PostgreSQL | TLS required by default, bounded pools and waits, atomic predicates, row/advisory locks, immutable migration ledger, destructive/maintenance preflight, and manifest-aware readiness. | Least-privilege roles, verified TLS where possible, managed backup/PITR, restored-data rehearsals, and physical-drift checks with ridu migrate status. |
| SQLite | Pure-Go local-file store, WAL and foreign-key enforcement, bounded waits, atomic predicates, immutable migration ledger, reversible lifecycle atomicity, and manifest/physical readiness. | One host, a local filesystem, small/local workloads, WAL-safe backup/recovery drills, and no shared network filesystem or horizontally replicated topology. |
| MongoDB | Verified TLS by default, writable replica-set admission, bounded pools/lease waits, exact immutable ledger/index readiness, atomic predicates, credential redaction, and crash-safe resume. | The supported version, topology, and platform; SCRAM-SHA-256; CA and hostname verification; least-privilege operational credentials; and matched drills. |
| Durable tasks | Compiled handler registry, strict typed input, leases, heartbeat fencing, retry/backoff, concurrency keys, cancellation, retention bounds, and graceful drain. | Idempotent external effects and monitoring of retries and terminal failures. |
| Admin and plugins | Embedded CSP-compatible admin, exact manifest/plugin pairing, server-owned permission checks, and origin/source/channel-bound preview messaging. | Dependency review; treat frontend and compiled plugins as shipped trusted code; never expose dev servers publicly. |
| Supply chain | Version compatibility checks and generated-contract drift detection. | Pin and review dependencies; protect the repository, registry, secrets, and deployment identity. |
Configure the HTTP boundary
Generated applications expose the relevant policy through HandlerOptions:
ridu.WithHandlerOptions(ridu.HandlerOptions{
AdminAssets: adminassets.FS(),
SecureCookies: true,
AllowedOrigins: []string{"https://admin.example.com"},
AllowedHosts: []string{"cms.example.com"},
TrustedProxyCIDRs: []string{"10.0.0.0/8"},
MaxBodyBytes: 8 << 20, // 8 × 2²⁰ = 8,388,608 bytes (8 MiB)
RequestTimeout: 20 * time.Second,
StrictTransportSecurity: "max-age=31536000; includeSubDomains",
})List trusted proxies narrowly. Forwarding headers are accepted only from configured networks; an over-broad CIDR lets an untrusted hop influence scheme or client-address decisions. Enable HSTS only when HTTPS is permanent for its complete declared scope.
The browser SDK includes credentials by default. Keep origins exact, cookies secure in production, and custom request headers explicitly allowed. Follow CORS for same-origin rules, generated-project configuration, preflights, and proxy diagnosis; see Authentication for session and account flows.
Authorization is server work
Admin visibility, disabled buttons, generated TypeScript types, object keys, and signed URLs are not authorization. Collection and field rules run inside the operation engine, and filtered decisions remain part of the atomic store query for reads, updates, and deletes.
An authenticated principal is the pair {auth collection, document ID}. Do not assume document IDs
are globally unique across auth collections. REST, GraphQL, local calls, hooks, preview, locks,
uploads, scheduled work, and audit events preserve both values. A nil actor is anonymous, not an
administrator.
Private upload delivery checks collection access before returning bytes. Treat an object key or signed URL as a capability and avoid logging it casually, but never use possession as the content access policy.
Bounded work
Ridu rejects expensive or ambiguous work before it becomes an unbounded database or serialization problem. Important framework ceilings include:
| Bound | Current ceiling | Why it exists |
|---|---|---|
| Relationship and upload occurrences in one document mutation | 512 | Bounds recursively nested reference maps and store admission across effective locales. |
| Validation issues returned for one operation | 128 | Keeps adversarial invalid input from creating an unbounded response. |
| Recursive population depth | 5 | Prevents unrestricted graph traversal. |
| Materialized related-document nodes in one populated response | 4,096 | Charges complete subtrees so dense cycles cannot grow exponentially below the depth ceiling. |
| Durable task input or output | 1 MiB each | Keeps database-backed work records bounded; large data belongs in object storage. |
Application schemas and edge infrastructure may impose tighter limits. Public deployments still need tenant-, user-, route-, and abuse-aware rate policy: Ridu’s distributed auth-operation throttling is not a universal API quota.
Migrations, readiness, and recovery
Production startup never mutates schema. Apply only committed migration artifacts
with the release’s exact binary. For any artifact requiring --allow-maintenance, stop all old
processes and workers and keep them stopped through completion and retries.
For MongoDB, keep the running application credential scoped to one application database and use
that or a selected database operator for plan, status, and up. Use separate least-privilege,
short-lived credentials for verification and backups. Keep every URL out of
generated files, image layers, logs, shell history, and process arguments; never grant cluster-wide
administration to the long-running application merely to simplify operations.
/healthz reports whether the process is alive. /readyz aggregates bounded checks for the migration
ledger/manifest, database, and upload dependency; MongoDB readiness also verifies the exact
Ridu-managed index plan. ridu migrate status remains the explicit operator report for immutable
history, durable step progress, and managed database state; readiness does not replace it.
Remove an instance from traffic before graceful drain.
Back up the selected database and object storage as one recovery point. Restoring only the database can leave missing objects; restoring only objects can expose stale or orphaned bytes. Test every backup with an isolated restore.
MongoDB’s supported cutover order is drain, command-scoped verification with the operational URL,
a matched database/upload snapshot, up with the selected application/operator URL, post-up
status, then application start with the app URL. This workflow covers a database-scoped logical
dump/restore plus uploads, not point-in-time recovery or an unsupported managed provider.
Residual risks and non-features
These boundaries require an application or infrastructure design:
- Auth operations are throttled, but general distributed API quotas are not built in.
- Audit callbacks are structured but are not a framework-owned tamper-aware durable audit log.
- After-commit callbacks can enqueue tasks, but no atomic database outbox closes the narrow crash window between the content commit and callback dispatch.
- Preview capabilities are process-local; multi-replica preview currently needs process affinity.
- Malware quarantine, resumable/direct uploads, and sandboxing of untrusted plugins are not provided.
- Prometheus and OpenTelemetry adapters are application-owned; Ridu exposes observations and readiness without requiring a vendor SDK.
Use reconciliation or an application-owned transactional outbox when an external effect cannot tolerate the after-commit window. Treat every plugin as reviewed application code, even when its configuration comes from a manifest.
Start with Prevent abuse before exposing the application publicly. See Access control, Uploads, Durable tasks, Production, and Releases and compatibility for the contracts around this model.