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("handlers SQL binding: external database {name:?} has unknown kind {kind:?} (expected postgres | mysql)")]
56    SqlExternalKind { name: String, kind: String },
57    /// An external database entry omitted the required `url_env`.
58    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
59    #[error("handlers SQL binding: external database {0:?} is missing `url_env`")]
60    SqlExternalUrlEnvMissing(String),
61    /// Building an external database backend (pool/URL parse) failed.
62    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
63    #[error("handlers SQL binding: external database {name:?}: {source}")]
64    SqlExternalConnect {
65        name: String,
66        #[source]
67        source: boatramp_core::sql::SqlError,
68    },
69    /// A managed compute-backed database (no `password_env`) was configured but no
70    /// `[secrets]` envelope is set — boatramp refuses to manage a credential it
71    /// cannot seal (it would otherwise store the DB password in cleartext).
72    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
73    #[error(
74        "handlers SQL binding: managed database {0:?} needs a `[secrets]` envelope to seal its \
75         generated credential — set `[secrets]` (envelope = \"local\" or \"vault\"), or supply \
76         `password_env` to bring your own"
77    )]
78    SqlManagedNeedsSecrets(String),
79    /// Generating/sealing/reading a managed compute-backed database credential failed.
80    #[cfg(any(feature = "sql-postgres", feature = "sql-mysql"))]
81    #[error("handlers SQL binding: managed database {name:?}: {reason}")]
82    SqlManagedCredential { name: String, reason: String },
83    /// External databases were configured but this build has no external SQL
84    /// engine compiled in.
85    #[cfg(all(
86        feature = "handlers",
87        not(any(feature = "sql-postgres", feature = "sql-mysql"))
88    ))]
89    #[error("handlers SQL binding: external database {0:?} needs an external SQL engine — rebuild with --features sql-postgres and/or sql-mysql")]
90    SqlExternalUnavailable(String),
91
92    /// `--kv slatedb` selected but this build lacks SlateDB support.
93    #[cfg(not(feature = "slatedb"))]
94    #[error("this build has no slatedb support; rebuild with `--features slatedb`")]
95    NoSlatedbSupport,
96    /// `--kv cloudflare` selected but this build lacks Cloudflare KV support.
97    #[cfg(not(feature = "cloudflare-kv"))]
98    #[error("this build has no Cloudflare KV support; rebuild with `--features cloudflare-kv`")]
99    NoCloudflareKvSupport,
100    /// Opening the KV store (SlateDB / Cloudflare) failed.
101    #[cfg(any(feature = "slatedb", feature = "cloudflare-kv"))]
102    #[error(transparent)]
103    Kv(#[from] boatramp_core::kv::KvError),
104
105    /// `--blobs fs` selected but this build lacks filesystem blob support.
106    #[cfg(not(feature = "fs"))]
107    #[error("this build has no filesystem blob support; rebuild with `--features fs`")]
108    NoFsSupport,
109    /// `--blobs s3` selected but this build lacks S3 support.
110    #[cfg(not(feature = "s3"))]
111    #[error("this build has no S3 support; rebuild with `--features s3`")]
112    NoS3Support,
113    /// `--blobs gcs` selected but this build lacks GCS support.
114    #[cfg(not(feature = "gcs"))]
115    #[error("this build has no GCS support; rebuild with `--features gcs`")]
116    NoGcsSupport,
117    /// `--blobs azure` selected but this build lacks Azure support.
118    #[cfg(not(feature = "azure"))]
119    #[error("this build has no Azure support; rebuild with `--features azure`")]
120    NoAzureSupport,
121    /// `--blobs s3` without `--s3-bucket`.
122    #[cfg(feature = "s3")]
123    #[error("--s3-bucket is required for --blobs s3")]
124    S3BucketRequired,
125    /// `--blobs gcs` was selected without a bucket.
126    #[cfg(feature = "gcs")]
127    #[error("--gcs-bucket is required for --blobs gcs")]
128    GcsBucketRequired,
129    /// Connecting the GCS backend failed (usually credential resolution).
130    #[cfg(feature = "gcs")]
131    #[error("GCS backend: {0}")]
132    GcsConnect(String),
133    /// `--blobs azure` was selected without an account/container.
134    #[cfg(feature = "azure")]
135    #[error("--azure-account and --azure-container are required for --blobs azure")]
136    AzureConfigRequired,
137    /// Connecting the Azure backend failed.
138    #[cfg(feature = "azure")]
139    #[error("Azure backend: {0}")]
140    AzureConnect(String),
141
142    /// Building the wasm handler engine failed.
143    #[cfg(feature = "handlers")]
144    #[error(transparent)]
145    Handler(#[from] boatramp_handlers::HandlerError),
146
147    /// Building the `[secrets]` envelope (local KEK / Vault) failed.
148    #[error("secrets envelope: {0}")]
149    Envelope(String),
150}
151
152/// Node-assembly result alias.
153pub type Result<T> = std::result::Result<T, Error>;