d86e25662f
Vaultwarden treats defined-but-empty SMTP_HOST/SMTP_FROM as "set"; with upstream _enable_smtp defaulting true its validation errors out and the container crash-loops on every fresh deploy with app-email off (the default). Gate the SMTP group with _ENABLE_SMTP: compose default false (clean boot, mail off), flipped "true" by the app-email injection via smtp_mapping.extra. Proven on the pinned 1.33.2-alpine image (P1 repro exit 12 / P2 off boots / P3 on boots). REUSE.md: strict-image TRAP row. Sweep note: the other 5 smtp-mapped templates are campaign-boot-proven tolerant; no edits. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
52 lines
3.0 KiB
Markdown
52 lines
3.0 KiB
Markdown
# REPORT — vaultwarden F1 fix: `_ENABLE_SMTP` boot-gate (2026-07-06)
|
|
|
|
**Class:** implementation (campaign-finding fix; push = deploy).
|
|
**Baseline:** `main` @ `13eedb1` → (this commit). Provenance: felhom.eu
|
|
`documentation/audits/CAMPAIGN-nomercy-2026-07-06.md` finding **F1** (pilot-blocking: every fresh
|
|
vaultwarden deploy with app-email off — the default — crash-loops).
|
|
|
|
## Corrected root cause (the campaign report's hypothesis was wrong)
|
|
|
|
Not "shim sets SMTP_FROM without SMTP_HOST" — with app-email off the shim injects **nothing**. The
|
|
crasher: the template always defines `SMTP_HOST=${SMTP_HOST:-}` and `SMTP_FROM=${SMTP_FROM:-}`;
|
|
vaultwarden's `get_env_str_value` returns `Some("")` for a defined-empty var (**empty counts as
|
|
set**), and with `_enable_smtp` defaulting `true` upstream, its validation
|
|
`smtp_host.is_some() == smtp_from.is_empty()` → `true == true` → config error → exit → crash-loop.
|
|
The old template comment ("empty SMTP_HOST = mail stays disabled") was wrong for this image.
|
|
|
|
## Empirical probe (mandatory gate, run on 180 against the pinned image BEFORE editing)
|
|
|
|
| Probe | Env | Result |
|
|
|---|---|---|
|
|
| P1 (pre-fix shape) | `SMTP_HOST=` `SMTP_FROM=` (defined-empty) | **exit 12** — *"Both `SMTP_HOST` and `SMTP_FROM` need to be set for email support without `USE_SENDMAIL`"* (exact campaign error) — the image-level red-proof |
|
|
| P2 (fix, OFF) | + `_ENABLE_SMTP=false` | **boots** — "Rocket has launched", running |
|
|
| P3 (fix, ON) | `_ENABLE_SMTP=true` + host + from | **boots** — running (no SMTP connect at boot) |
|
|
|
|
(P2/P3 needed `I_REALLY_WANT_VOLATILE_STORAGE=true` to bypass the unrelated no-volume guard in the
|
|
bare `docker run`; P1 control re-run with it still crashes on the SMTP error, isolating the cause.)
|
|
Logs: DooPlex `~/campaign-nomercy-2026-07-05/evidence/PROBE-F1/`.
|
|
|
|
## Changes
|
|
|
|
- `templates/vaultwarden/docker-compose.yml` — `_ENABLE_SMTP=${_ENABLE_SMTP:-false}` added to the
|
|
SMTP group; the wrong comment replaced with the empty-counts-as-set TRAP note (+ config.json
|
|
admin-panel precedence note). Nothing else touched.
|
|
- `templates/vaultwarden/.felhom.yml` — `smtp_mapping.extra: _ENABLE_SMTP: "true"` (rides the
|
|
existing `smtpEnv` extra loop; zero controller change).
|
|
- `REUSE.md` — TRAP appended to the App-email row: strict images need the enable-flag pattern;
|
|
boot-prove fresh email-off deploys for every new smtp-mapped app.
|
|
- `CHANGELOG.md` — entry incl. the sweep note.
|
|
|
|
## Sweep note (documentation only, no edits)
|
|
|
|
calcom, gitea, mealie, nextcloud, rallly (and gitea's `GITEA__mailer__SMTP_ADDR=${...:-}`) are
|
|
**boot-proven tolerant** of defined-empty mail env — all ran healthy as fresh email-off deploys in
|
|
the campaign. Vaultwarden was the only strict image.
|
|
|
|
## Validation
|
|
|
|
- Probe gate P1/P2/P3 above (image level).
|
|
- Live pipeline validation (Scenario A fresh email-off deploy healthy; Scenario B toggle ON→OFF
|
|
regression) executed as part of the controller v0.101.0 deployment — see
|
|
felhom-controller/REPORT.md for the live evidence.
|