466d7991

By: Michael Lynch <git@mtlynch.io>

Reject invalid startup configuration before side effects

Application and importer configuration was spread across global flags, raw environment lookups, build-tagged helpers, and late startup code. Invalid ports, URLs, SMTP settings, or proxy values could be discovered only after directories were created, clients initialized, or SQLite opened; any nonempty BEHIND_PROXY value also enabled trusted forwarding behavior, including false-like strings.

Litestream v0.5.14 in file cmd/litestream/main.go constructs a typed Config from defaults, overlays external values, validates field and cross-field constraints, and only then starts operational components. Adopt that parse-then-validate boundary while keeping this application's configuration much smaller and immutable.

Add startupconfig plans for the app and importer, inject environment lookup for deterministic tests, and parse all command inputs before resource initialization. Strictly validate ports, booleans, time zones, media mode, S3 and public URLs, SMTP settings, sender addresses, and production HTTPS requirements. Build-tagged login policies retain the existing development and production behavior, and Fly now supplies the canonical BEHIND_PROXY=true value. S3 configuration owns typed URL validation without exposing credentials in errors.

The implementation had to preserve build-tag symmetry and secret bytes while eliminating process-global reads. Development must not require production SMTP values, production must validate them before opening SQLite, and passwords or keys must not be trimmed, formatted, or logged. Litestream-specific credentials remain Litestream's responsibility; this app validates only the LITESTREAM_BUCKET presence signal that selects SQLite pragmas rather than duplicating litestream.yml policy.

No external blockers were encountered. Production and development focused tests, the full Go checks, and every flake target passed before the amendment.

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 27s 14s 14s 42s 27s
Eval 50s 1m43s 1m43s 2m34s 7s
Build 2m10s 5m31s 3m24s 5m35s 1m08s
Suite 27s 7m29s 5m07s 5m35s 1m43s

Timeline

0s40s1m1m20s1m40s2m2m20s4m4m20s4m40s5m5m20s