fix: give Doctor the host configuration the runtime receives
CI / verify (pull_request) Successful in 42s
CI / infrastructure-smoke (pull_request) Successful in 14s
CI / migration-smoke (pull_request) Successful in 1m24s

`pnpm doctor` and `startApi` each read their own subset of the same
environment variables, and the subsets had drifted. Doctor never read
`S3_*` or module secrets at all, so a correctly configured installation
was told its object storage was "not configured" and every module
requiring a bucket or a secret was reported blocked -- while the runtime,
from the identical environment, bound those buckets and ran the modules.

Both executables now map the environment through one
`loadHostConfiguration(env)` in Core, which takes the environment as an
argument and never reads `process.env` itself. Validation stays with the
existing per-domain validators, so each caller keeps its own failure
behaviour: startup refuses a rejected value, Doctor reports it as a
sanitized code.

Doctor's storage option becomes raw input like its mail option, so a
half-configured provider is reported as a blocking configuration failure
instead of throwing before a report exists. The outbound-email check --
computed, counted toward the result, but absent from every rendered
section -- is now printed, and the rendered set is asserted against a
real report so a future check cannot go missing the same way.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
ekklesia
2026-08-24 19:15:49 -05:00
co-authored by Claude Opus 5
parent a835215eb8
commit 2b4f0afb72
23 changed files with 1411 additions and 209 deletions
+5 -3
View File
@@ -1361,9 +1361,11 @@ rotation and client-certificate authentication.
The same policy is resolved identically by every executable that opens a connection — `apps/api`,
`pnpm migrations:plan`, `pnpm migrations:apply`, the platform-owner bootstrap CLI, and
`pnpm doctor`'s own connection — through one shared environment reader
(`core/src/cli/database-transport-environment.ts`), so `process.env` stays out of Core's reusable
constructors. `apps/api` validates it in `createApiRuntimeConfig`, *before* any pool, Better Auth
`pnpm doctor`'s own connection — because they all map the environment through the one shared host
configuration loader (`core/src/host/configuration.ts`, reached by the small migration commands via
`core/src/cli/database-transport-environment.ts`). The loader takes the environment **as an
argument**, so `process.env` stays out of Core's reusable constructors and only executables read
it. `apps/api` validates it in `createApiRuntimeConfig`, *before* any pool, Better Auth
instance, module runtime, or listener exists. `pnpm doctor` reports it as `database.transport` in
its PostgreSQL section: a verified production policy passes, and an unsafe or invalid one is a
blocking `NOT READY` failure — never a warning — naming only the effective mode, never the URL,