pub struct ExternalDatabaseConfig {Show 16 fields
pub kind: String,
pub url_env: String,
pub read_url_env: Option<String>,
pub compute: Option<String>,
pub database: Option<String>,
pub user: Option<String>,
pub password_env: Option<String>,
pub pool_max: Option<u32>,
pub read_only: bool,
pub allow_preview: bool,
pub connect_timeout_secs: Option<u64>,
pub image: Option<String>,
pub volume_size_mib: Option<u32>,
pub tenant: TenantIsolation,
pub tenant_scope: TenantScope,
pub rls_session: bool,
}Expand description
One external SQL database for the handler sql binding. Its source is one
of two mutually-exclusive forms:
url_env— a bring-your-own database: the connection URL is a secret, named indirectly by an env var (never written in the config file).compute— a database boatramp runs as a compute workload: boatramp derives the connection from the workload’s live endpoint (host:port) plus thedatabase/user/password_envhere, so there is no URL to hand-map and it follows the workload across restarts (PLAN-managed-compute-sql).
Fields§
§kind: StringEngine: postgres (aliases postgresql/pg) or mysql (alias
mariadb).
url_env: StringName of the env var holding the connection URL (e.g.
postgres://user:pw@host/db). Required unless compute is set.
read_url_env: Option<String>Optional env var holding a read-replica connection URL. When set,
open-read-only transactions route there; writes stay on url_env.
compute: Option<String>The name of a compute workload (a Postgres/MySQL server boatramp runs)
to source this database from, instead of url_env. boatramp resolves the
workload’s live endpoint and builds the connection. Mutually exclusive with
url_env.
database: Option<String>The database name inside the compute-backed server (non-secret).
user: Option<String>The connecting user for the compute-backed server (non-secret).
password_env: Option<String>Env var holding the password for user on the compute-backed server.
Omit to let boatramp fully manage the credential (PLAN-managed-compute-sql
Phase 2): it generates a strong password once, seals it with the [secrets]
envelope, injects it into the DB workload’s server-init env at launch, and
connects the handler with it — the operator sets no DB secret at all. Set it
only to bring your own password for the compute-backed server.
pool_max: Option<u32>Maximum pooled connections (default 8).
read_only: boolOpen every transaction READ ONLY (the engine rejects writes) — for a
database functions should only read.
allow_preview: boolPermit preview deployments to reach this database. Default false: a
preview is refused, so it can never touch the operator’s live external DB.
connect_timeout_secs: Option<u64>Connection/acquire timeout in seconds (default 10).
image: Option<String>The stock OCI image for a managed co-located database (compute set, no
password_env). When omitted, boatramp auto-registers the workload from the
engine’s default image (pgvector/pgvector:pg16 for postgres, mysql:8.0
for mysql). Ignored for a bring-your-own (url_env) database.
volume_size_mib: Option<u32>The persistent data-volume size in MiB for a managed co-located database (default 10240 = 10 GiB). Ignored for a bring-your-own database.
tenant: TenantIsolationIsolation mechanism for a compute-backed managed database (2×2 axis 1).
single (default) — a dedicated database server (its own container) per
tenant; shared — one server hosting a permission-separated database + role
per tenant. Ignored for a bring-your-own (url_env) database.
tenant_scope: TenantScopeTenant grain for a compute-backed managed database (2×2 axis 2). project
(default) — a tenant is a project; site — a tenant is a site. A tenant may
hold several databases (one per binding that names it); it gets one login role
and sealed credential per (tenant, server), granted on all its own databases
and none of another tenant’s. The reserved default project uses the plain
configured name, so a single-tenant install is just one ordinary database.
rls_session: boolOpt-in (default false): inject the request’s boatramp.project /
boatramp.site into the SQL session at each transaction start (Postgres
set_config GUC, MySQL session var), so hand-written native RLS policies
can key on them per-request. The GraphQL data connector’s row-level policy is
claim-sourced and needs nothing here; this is for hand-rolled RLS on the plain
sql.open path (Postgres — the engine with native row-level security).
§Trust model — read before relying on this for isolation
rls_session provides the request’s tenant to the SQL session for an app’s
RLS to key on. It is not a general hostile-guest boundary:
- The reserved keys (
boatramp.*/@boatramp_*) are protected from guest override — a handler statement that tries toset_config('boatramp.…', …)/SET boatramp.…/SET @boatramp_…(orRESET/DISCARDthem) is refused, so a guest cannot spoof its injected tenant. - But the real tenant-isolation boundary is the per-tenant database +
role (
tenant = single/shared), which a compromised handler cannot cross regardless of what it does in-session.rls_sessionis a convenience for app-authored RLS within a tenant’s own database, layered on top of that boundary — not a substitute for it. - For untrusted data, prefer claim-sourced enforcement (the GraphQL data connector’s row-level policy), which derives the tenant from the verified request, not from anything the handler’s SQL can influence.
Implementations§
Source§impl ExternalDatabaseConfig
impl ExternalDatabaseConfig
Sourcepub fn validate(&self, name: &str) -> Result<(), String>
pub fn validate(&self, name: &str) -> Result<(), String>
Validate the source is well-formed: exactly one of url_env /
compute, and a compute-backed database has the connection details
boatramp can’t infer (database + user). password_env is optional —
omit it to let boatramp manage the credential (Phase 2). name is the
binding name, for the error message.
Sourcepub fn is_managed_credential(&self) -> bool
pub fn is_managed_credential(&self) -> bool
Whether this compute-backed database uses a boatramp-managed credential
(Phase 2): compute is set and no password_env was supplied.
Trait Implementations§
Source§impl Clone for ExternalDatabaseConfig
impl Clone for ExternalDatabaseConfig
Source§fn clone(&self) -> ExternalDatabaseConfig
fn clone(&self) -> ExternalDatabaseConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ExternalDatabaseConfig
impl Debug for ExternalDatabaseConfig
Source§impl Default for ExternalDatabaseConfig
impl Default for ExternalDatabaseConfig
Source§fn default() -> ExternalDatabaseConfig
fn default() -> ExternalDatabaseConfig
Source§impl<'de> Deserialize<'de> for ExternalDatabaseConfigwhere
ExternalDatabaseConfig: Default,
impl<'de> Deserialize<'de> for ExternalDatabaseConfigwhere
ExternalDatabaseConfig: Default,
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for ExternalDatabaseConfig
impl RefUnwindSafe for ExternalDatabaseConfig
impl Send for ExternalDatabaseConfig
impl Sync for ExternalDatabaseConfig
impl Unpin for ExternalDatabaseConfig
impl UnsafeUnpin for ExternalDatabaseConfig
impl UnwindSafe for ExternalDatabaseConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more