feat(mail): allow both sending domains for the email.bitborg.se move #379

Sammanfogat
supernaut sammanfogade 1 incheckning från feat/mail-domain-step1 in i main 2026-08-05 13:54:05 +00:00
Ägare

Step 1 of 3 in moving the outbound sending domain to email.bitborg.se.

Why this is a sequence and not an edit

The portal refuses to send when its hardcoded EMAIL_FROM is absent from the allowlist infra supplies. So the allowlist must widen before the portal's sender moves, and narrow again after:

1. apply   EMAIL_ALLOWED_SENDER_DOMAINS = mail.gitborg.se,email.bitborg.se   <- this PR
           mail_sending_domain unchanged -> nothing else moves, mail keeps working
2. deploy  bitborg-web with EMAIL_FROM = no-reply@email.bitborg.se   -> allowed by step 1
3. apply   mail_sending_domain = email.bitborg.se (carries forgejo_mailer_from,
           alert_email_from, monitoring_probe_mail_from) and narrow the allowlist

That guard exists because this exact move broke portal mail once already, on email.gitborg.se → mail.gitborg.se: infra moved, the portal did not, and every portal mail was rejected while the apply reported success.

senderAllowed() in bitborg-web has always split on commas, so the portal side was already plural — only this repo passed a single value. Hence a new mail_allowed_sender_domains list, with the three-step procedure recorded beside it so the next domain move is a checklist rather than a rediscovery.

⚠️ Steps 1 and 3 belong close together. A permanently widened allowlist re-opens the hole the guard closes.

Also here: two stale fallbacks removed

alert_email_from and monitoring_probe_mail_from carried | default('mail.gitborg.se'), defended as letting the roles render standalone. But a fallback to a stale literal is precisely the leave-behind the derivation exists to prevent — it trades a loud failure for silently sending as a retired domain, which is the #113 failure mode. mail_sending_domain is declared in group_vars/all/, so it applies to every host here and the standalone case does not arise.

Confirmed dead code by the dry-run: the monitoring host reports changed=0, i.e. alert_email_from renders identically with the default gone.

DNS

DKIM and DMARC for email.bitborg.se are already published — a distinct Sweego CNAME token resolving to the same key, so the domain is registered on the same account. Neither subdomain carries an SPF TXT, which matches the working old domain. No dashboard work and no vault edit in this move.

Applied and verified

  • Dry-run across both hosts: failed=0, one changed task on prod (web : Install the bitborg-web container Quadlet unit), none on monitoring.
  • The running container reports EMAIL_ALLOWED_SENDER_DOMAINS=mail.gitborg.se,email.bitborg.se.
  • www.bitborg.se serves 200 after the restart.
Step 1 of 3 in moving the outbound sending domain to `email.bitborg.se`. ## Why this is a sequence and not an edit The portal refuses to send when its hardcoded `EMAIL_FROM` is absent from the allowlist infra supplies. So the allowlist must widen **before** the portal's sender moves, and narrow again **after**: ```text 1. apply EMAIL_ALLOWED_SENDER_DOMAINS = mail.gitborg.se,email.bitborg.se <- this PR mail_sending_domain unchanged -> nothing else moves, mail keeps working 2. deploy bitborg-web with EMAIL_FROM = no-reply@email.bitborg.se -> allowed by step 1 3. apply mail_sending_domain = email.bitborg.se (carries forgejo_mailer_from, alert_email_from, monitoring_probe_mail_from) and narrow the allowlist ``` That guard exists because this exact move broke portal mail once already, on `email.gitborg.se` → `mail.gitborg.se`: infra moved, the portal did not, and every portal mail was rejected while the apply reported success. `senderAllowed()` in bitborg-web has always split on commas, so the portal side was already plural — **only this repo passed a single value.** Hence a new `mail_allowed_sender_domains` list, with the three-step procedure recorded beside it so the next domain move is a checklist rather than a rediscovery. ⚠️ **Steps 1 and 3 belong close together.** A permanently widened allowlist re-opens the hole the guard closes. ## Also here: two stale fallbacks removed `alert_email_from` and `monitoring_probe_mail_from` carried `| default('mail.gitborg.se')`, defended as letting the roles render standalone. But a fallback to a *stale literal* is precisely the leave-behind the derivation exists to prevent — it trades a loud failure for silently sending as a retired domain, which is the #113 failure mode. `mail_sending_domain` is declared in `group_vars/all/`, so it applies to every host here and the standalone case does not arise. Confirmed dead code by the dry-run: **the monitoring host reports `changed=0`**, i.e. `alert_email_from` renders identically with the default gone. ## DNS DKIM and DMARC for `email.bitborg.se` are already published — a distinct Sweego CNAME token resolving to the same key, so the domain is registered on the same account. Neither subdomain carries an SPF TXT, which matches the working old domain. No dashboard work and no vault edit in this move. ## Applied and verified - Dry-run across both hosts: `failed=0`, one changed task on prod (`web : Install the bitborg-web container Quadlet unit`), none on monitoring. - The running container reports `EMAIL_ALLOWED_SENDER_DOMAINS=mail.gitborg.se,email.bitborg.se`. - `www.bitborg.se` serves `200` after the restart.
supernaut lade till 1 incheckning 2026-08-05 13:50:21 +00:00
feat(mail): allow both sending domains for the email.bitborg.se move
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m36s
946d9b4268
Step 1 of 3. The portal refuses to send when its hardcoded EMAIL_FROM is absent from the
allowlist infra supplies, so a sending-domain move is a sequence, not an edit: the
allowlist has to widen BEFORE the portal's sender moves, and narrow again after. That
guard exists because this exact move broke portal mail once before, on
email.gitborg.se -> mail.gitborg.se: infra moved, the portal did not, and every portal
mail was rejected while the apply reported success.

`senderAllowed()` in bitborg-web has always split on commas, so the portal side was
already plural — only this repo passed a single value. Hence a new
`mail_allowed_sender_domains` list rather than an edit in place, with the three-step
procedure recorded beside it so the next domain move is a checklist rather than a
rediscovery.

`mail_sending_domain` is deliberately UNCHANGED here, so nothing else moves and mail keeps
working: forgejo_mailer_from, alert_email_from and monitoring_probe_mail_from all still
derive from the old domain. They move together in step 3, when this list narrows back to
one entry.

Also drops the `| default('mail.gitborg.se')` fallbacks on alert_email_from and
monitoring_probe_mail_from. They were defended as letting the roles render standalone, but
a fallback to a stale literal is precisely the leave-behind the derivation exists to
prevent — it trades a loud failure for silently sending as a retired domain, which is the
#113 failure mode. `mail_sending_domain` is declared in group_vars/all/, so it applies to
every host here and the standalone case does not arise. Confirmed dead code by the
dry-run: the monitoring host reports changed=0.

DKIM and DMARC for email.bitborg.se are already published (a distinct Sweego CNAME token
resolving to the same key, so the domain is registered on the same account) and the
credentials are unchanged, so there is no dashboard work and no vault edit in this move.

Applied and verified: the running container reports
EMAIL_ALLOWED_SENDER_DOMAINS=mail.gitborg.se,email.bitborg.se, the portal serves 200, and
the dry-run beforehand was one changed task on prod and none on monitoring.
supernaut sammanfogade incheckning 084776bff1 till main 2026-08-05 13:54:05 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-infra!379
Ingen beskrivning angiven.