Skip to content

web: settable SMTP relay config (operator UI) with a ProfferedSmtpPassword wire twin #638

Description

@mdorman

Problem

SMTP relay configuration (smtp.host, port, tls_mode, username,
password, sender) is currently settable only via the CLI / site-config KV
store (storage/src/smtp.rs::load_smtp_config). There is no web admin UI to view
or change it, so an operator must use the CLI to configure outbound email.

Direction

Add a web admin surface (behind operator auth) to view and set the SMTP relay
config, with a #[server] fn that writes the KV keys.

The credential needs the ADR-0063 inbound-secret treatment — it crosses the
#[server] wire from client → server:

  • Introduce ProfferedSmtpPassword (#[str_newtype(secret, serde)]) — the
    serde-capable inbound twin of the server-only SmtpPassword (types: secret SmtpPassword newtype for the SMTP relay credential #586), mirroring
    ProfferedPassword/Password. Share the non-empty validator between the two
    (a validate_smtp_password_shape free fn) so the wire type and domain type
    cannot drift.
  • impl TryFrom<ProfferedSmtpPassword> for SmtpPassword.
  • The set-SMTP-config #[server] fn takes ProfferedSmtpPassword in a parameter
    position; the proffered-secret xtask gate then pins it (verify the gate bites).
  • Client-side validation per ADR-0065 (typed wire arg + client validation).
  • Decide the read path: never return the stored password to the client (write-only
    field; show "set/unset" rather than the value), preserving the secret's
    no-Display/no-serialize-out invariant.

Acceptance

  • Operator web UI can set the SMTP relay config, including the password as a
    write-only field (never rendered/returned to the client).
  • ProfferedSmtpPassword inbound twin + shared validator + TryFrom into
    SmtpPassword; the proffered-secret gate covers the new #[server] param.
  • Client-side validation of the SMTP fields (ADR-0065).
  • cargo xtask validate clean.

Related

Blocked-by #586 (the server-only SmtpPassword domain type). Family: #410
(Password/ProfferedPassword split), #500 (proffered-secret wire gate),
ADR-0063 (secret exception), ADR-0065 (typed wire arg + client validation).
Security-adjacent (credential handling): full review.

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions