Skip to main content

boatramp_node/
error.rs

1//! Assembly errors surfaced by the node-library helpers (moved out of the
2//! binary's `serve::Error`, which absorbs them via `#[from]`). Scoped to the
3//! handler/SQL assembly today; grows as more of `assemble()` moves here.
4
5/// A node-assembly error. Variants are feature-gated to the assembly path that
6/// produces them, matching the crate's forwarded features.
7#[derive(Debug, thiserror::Error)]
8pub enum Error {
9    /// The operator-supplied guest-egress extra-CA file (`BOATRAMP_GUEST_EGRESS_EXTRA_CA_FILE`,
10    /// permitted by the `allow_guest_egress_extra_ca` posture) could not be read or held no valid
11    /// PEM certificate. Fail-closed: a configured-but-broken CA is a hard error, never a silent
12    /// no-trust.
13    #[error("guest egress extra CA ({0})")]
14    GuestEgressCa(String),
15    /// A token root **private** key (hex) failed to parse, or an external signer
16    /// (KMS/HSM/Vault) failed to build / resolve its public key.
17    #[error("invalid auth root private key: {0}")]
18    AuthPrivKey(String),
19    /// A token root **public** key (hex) failed to parse.
20    #[error("invalid auth root public key: {0}")]
21    AuthPubKey(String),
22    /// Refusing to bind a non-loopback address with control-plane auth disabled.
23    /// Set auth keys, bind a loopback address, or — for local dev —
24    /// relax `allow_unauthenticated_public_bind` in `[security]` (the `dev` profile).
25    #[error(
26        "refusing to bind {addr} with control-plane auth disabled: an \
27         unauthenticated control plane must not be exposed to a non-loopback \
28         address. Configure auth keys, bind a loopback address, or set the `dev` \
29         security profile / `allow_unauthenticated_public_bind` for local dev"
30    )]
31    UnauthenticatedPublicBind { addr: std::net::SocketAddr },
32
33    /// A handler `sql` binding named an env var that is not set.
34    #[cfg(feature = "handlers")]
35    #[error("handlers SQL binding: env var {0} is not set")]
36    SqlEnvUnset(String),
37    /// A cluster sqld `url` was set without the required `admin_url`.
38    #[cfg(feature = "handlers")]
39    #[error("handlers SQL binding: `url` (cluster sqld) requires `admin_url`")]
40    SqlAdminUrlRequired,
41    /// An unrecognised `[handlers.bindings.sql].preview_mode`.
42    #[cfg(feature = "handlers")]
43    #[error("handlers SQL binding: unknown preview_mode {0:?} (expected empty | branch | shared)")]
44    UnknownPreviewMode(String),
45    /// Reading the `preview_init` SQL script failed.
46    #[cfg(feature = "handlers")]
47    #[error("handlers SQL binding: reading preview_init {path:?}: {source}")]
48    PreviewInitRead {
49        path: std::path::PathBuf,
50        #[source]
51        source: std::io::Error,
52    },
53    /// An external database named an unrecognised engine `kind`.
54    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
55    #[error(
56        "handlers SQL binding: external database {name:?} has unknown kind {kind:?} (expected postgres | mysql)"
57    )]
58    SqlExternalKind { name: String, kind: String },
59    /// An external database entry omitted the required `url_env`.
60    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
61    #[error("handlers SQL binding: external database {0:?} is missing `url_env`")]
62    SqlExternalUrlEnvMissing(String),
63    /// Building an external database backend (pool/URL parse) failed.
64    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
65    #[error("handlers SQL binding: external database {name:?}: {source}")]
66    SqlExternalConnect {
67        name: String,
68        #[source]
69        source: boatramp_core::sql::SqlError,
70    },
71    /// A managed compute-backed database (no `password_env`) was configured but no
72    /// `[secrets]` envelope is set — boatramp refuses to manage a credential it
73    /// cannot seal (it would otherwise store the DB password in cleartext).
74    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
75    #[error(
76        "handlers SQL binding: managed database {0:?} needs a `[secrets]` envelope to seal its \
77         generated credential — set `[secrets]` (envelope = \"local\" or \"vault\"), or supply \
78         `password_env` to bring your own"
79    )]
80    SqlManagedNeedsSecrets(String),
81    /// Generating/sealing/reading a managed compute-backed database credential failed.
82    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
83    #[error("handlers SQL binding: managed database {name:?}: {reason}")]
84    SqlManagedCredential { name: String, reason: String },
85    /// External databases were configured but this build has no external SQL
86    /// engine compiled in.
87    #[cfg(all(
88        feature = "handlers",
89        not(any(feature = "sql-postgres", feature = "sql-mysql"))
90    ))]
91    #[error(
92        "handlers SQL binding: external database {0:?} needs an external SQL engine — rebuild with --features sql-postgres and/or sql-mysql"
93    )]
94    SqlExternalUnavailable(String),
95
96    /// `--kv slatedb` selected but this build lacks SlateDB support.
97    #[cfg(not(feature = "slatedb"))]
98    #[error("this build has no slatedb support; rebuild with `--features slatedb`")]
99    NoSlatedbSupport,
100    /// `--kv cloudflare` selected but this build lacks Cloudflare KV support.
101    #[cfg(not(feature = "cloudflare-kv"))]
102    #[error("this build has no Cloudflare KV support; rebuild with `--features cloudflare-kv`")]
103    NoCloudflareKvSupport,
104    /// `--kv sql` selected but this build lacks the SQL KV backend.
105    #[cfg(not(feature = "sql"))]
106    #[error(
107        "this build has no SQL KV support; rebuild with `--features sql` (or any build that enables it, e.g. `handlers`)"
108    )]
109    NoSqlSupport,
110    /// The `--kv sql` backend was selected but its `[serve.kv.sql]` config (or `BOATRAMP_KV_SQL_*`
111    /// env) is missing/invalid: no config at all, a missing `path` for `kind = sqlite`, a
112    /// not-yet-wired engine (`postgres`/`mysql`), or an unknown `kind`.
113    #[cfg(feature = "sql")]
114    #[error("SQL KV backend: {0}")]
115    SqlKvConfig(String),
116    /// Opening the KV store (SlateDB / Cloudflare / SQL) failed.
117    #[cfg(any(feature = "slatedb", feature = "cloudflare-kv", feature = "sql"))]
118    #[error(transparent)]
119    Kv(#[from] boatramp_core::kv::KvError),
120
121    /// `--blobs fs` selected but this build lacks filesystem blob support.
122    #[cfg(not(feature = "fs"))]
123    #[error("this build has no filesystem blob support; rebuild with `--features fs`")]
124    NoFsSupport,
125    /// `--blobs s3` selected but this build lacks S3 support.
126    #[cfg(not(feature = "s3"))]
127    #[error("this build has no S3 support; rebuild with `--features s3`")]
128    NoS3Support,
129    /// `--blobs gcs` selected but this build lacks GCS support.
130    #[cfg(not(feature = "gcs"))]
131    #[error("this build has no GCS support; rebuild with `--features gcs`")]
132    NoGcsSupport,
133    /// `--blobs azure` selected but this build lacks Azure support.
134    #[cfg(not(feature = "azure"))]
135    #[error("this build has no Azure support; rebuild with `--features azure`")]
136    NoAzureSupport,
137    /// `--blobs s3` without `--s3-bucket`.
138    #[cfg(feature = "s3")]
139    #[error("--s3-bucket is required for --blobs s3")]
140    S3BucketRequired,
141    /// `--blobs gcs` was selected without a bucket.
142    #[cfg(feature = "gcs")]
143    #[error("--gcs-bucket is required for --blobs gcs")]
144    GcsBucketRequired,
145    /// Connecting the GCS backend failed (usually credential resolution).
146    #[cfg(feature = "gcs")]
147    #[error("GCS backend: {0}")]
148    GcsConnect(String),
149    /// `--blobs azure` was selected without an account/container.
150    #[cfg(feature = "azure")]
151    #[error("--azure-account and --azure-container are required for --blobs azure")]
152    AzureConfigRequired,
153    /// Connecting the Azure backend failed.
154    #[cfg(feature = "azure")]
155    #[error("Azure backend: {0}")]
156    AzureConnect(String),
157
158    /// Building the wasm handler engine failed.
159    #[cfg(feature = "handlers")]
160    #[error(transparent)]
161    Handler(#[from] boatramp_handlers::HandlerError),
162
163    /// Building the `[secrets]` envelope (local KEK / Vault) failed.
164    #[error("secrets envelope: {0}")]
165    Envelope(String),
166}
167
168/// Node-assembly result alias.
169pub type Result<T> = std::result::Result<T, Error>;