apiVersion: v2
name: bp-stalwart-tenant
# 0.1.2 (#915) — wire Keycloak OIDC SSO end-to-end so the per-tenant
# Stalwart authenticates webmail / IMAP / SMTP users against the SME's
# vcluster-local Keycloak realm (epic #915 DoD #2 — alice's mailbox
# logs in via her tenant Keycloak, NOT a shared otech-level IdP).
#
# What 0.1.1 had: the chart shipped values for `keycloak.realmURL`,
# `keycloak.clientID`, `keycloak.clientSecretName` AND a placeholder
# `[directory.keycloak]` block in the bootstrap config.toml. Three
# things broke the actual SSO contract on a fresh tenant:
#   a. the orchestrator's `smeTenantBPStalwart` template (catalyst-api/
#      sme_tenant_gitops.go) emitted ONLY `domain.primary` + `ingress`
#      values — never a `keycloak.*` block. Fresh tenants ran with the
#      chart's empty default `keycloak.realmURL: ""` so no OIDC
#      handshake was possible. Wordpress/openclaw both passed the
#      realmURL — Stalwart was left out.
#   b. the chart's TOML used the pre-0.16 Stalwart key layout
#      (`type = "oidc"`, `url = ...`, `client-id = ...`, kebab-case).
#      Stalwart 0.16+ moved directory definitions to the settings KV
#      store; the OIDC schema serdes camelCase
#      (`@type = "Oidc"`, `issuerUrl`, `claimUsername`, `claimName`,
#      `claimGroups`, `requireScopes`) — verified against the upstream
#      registry schema (crates/registry/src/schema/structs.rs). The
#      kebab-case TOML block was silently ignored.
#   c. the setupJob that registers the OIDC directory via the
#      `/api/settings` admin endpoint was disabled by default
#      (operator-opt-in) — so even when the values landed correctly
#      the actual Stalwart instance still had no OIDC directory at
#      runtime.
#
# 0.1.2 fixes:
#   1. orchestrator emits per-tenant `keycloak.realmURL` =
#      `https://keycloak.<sub>.<parent>/realms/sme-<sub>` + `clientID`
#      = `stalwart` + `clientSecretName` = `stalwart-oidc-client-secret`
#      + `oidcExternalSecret.remoteRef.key` =
#      `sovereign/<otech-fqdn>/stalwart/<tenant>/oidc`. Mirrors the
#      bp-wordpress-tenant + bp-openclaw shape so all three apps SSO
#      against the SAME tenant realm with their distinct client IDs
#      (#915 C1 registers all three clients in the realm).
#   2. config.toml emits `[oauth]` block + setup Job seeds the
#      directory entry into Stalwart's settings KV store via the
#      `/api/settings` admin endpoint with the canonical camelCase
#      keys (`directory.keycloak.@type = "Oidc"`, `issuerUrl`,
#      `claimUsername`, `claimName`, `claimGroups`, `requireScopes`).
#      The settings POST is idempotent (assert_empty=false) — re-runs
#      on Helm upgrade without breaking existing logins.
#   3. setupJob defaults to enabled (was off in 0.1.1 because the
#      canonical stalwart-cli image was unpublished). The Job re-uses
#      the upstream Stalwart container which already ships
#      `stalwart-cli` + `curl` — no new image needed.
#
# Per #817 Chart.yaml version MUST equal blueprint.yaml spec.version.
version: 0.1.2
appVersion: "0.16.3"
description: |
  Catalyst Blueprint scratch chart for a per-SME (per-vcluster) dedicated
  Stalwart mail server. Implements locked decision [Q3] of EPIC #795
  (SME-tenant turnkey experience) — every SME on a Sovereign gets its
  OWN Stalwart instance in its tenant namespace, with its OWN domain,
  OWN MTA reputation, and OWN queue. NOT a shared otech-level multi-
  domain Stalwart.

  Footprint trade-off (registered in #795): per-SME Stalwart multiplies
  mail-server resources by N tenants. The trade buys stronger isolation,
  per-customer DKIM/SPF/DMARC posture, and clean blast-radius separation
  on outbound IP reputation.

  Connects to:
    - bp-keycloak           (per-SME-vcluster Keycloak realm — OIDC SSO
                             for webmail and admin API)
    - bp-external-secrets   (admin password + JMAP/IMAP signing material;
                             remoteRef under
                             kv/sovereign/<sov>/stalwart/<tenant>/admin)
    - bp-cert-manager       (TLS for mail.<sme-domain> webmail Ingress
                             via cert-manager ClusterIssuer)
    - bp-powerdns           (free-subdomain mode: chart records DKIM/SPF/
                             DMARC required values in a ConfigMap; the
                             unified-rbac console UI surfaces them OR a
                             follow-up Job posts them to PowerDNS API)

  Customer surface: webmail UI at https://mail.<domain.primary>
  (Stalwart's built-in webadmin/JMAP); plus SMTP/IMAP via LoadBalancer.

  Per-tenant mailbox provisioning is event-driven (ADR-0003 §3): the
  unified-rbac service POSTs Stalwart's `/api/principal` admin API when
  the SME admin creates a new user. The chart ships an ExternalSecret
  binding the admin API token a follow-up controller mints during install.

  Stalwart expression-language gotcha (per stalwart_expression_syntax.md
  memory, 2026-04-14): equality matchers MUST use `==` not `=` — a
  single `=` is assignment and silently never matches. The bootstrap
  config.toml in templates/config-configmap.yaml audits clean for this.

  See platform/stalwart-tenant/README.md for DKIM/SPF/DMARC setup,
  free-subdomain vs BYO domain mode, and the SME admin runbook.
type: application
keywords: [catalyst, blueprint, stalwart, mail, smtp, imap, jmap, sme, multi-tenant, vcluster]
maintainers:
  - name: OpenOva Catalyst
    email: catalyst@openova.io

# Scratch chart — Stalwart upstream does not publish a first-party Helm
# chart (contabo-mkt apps/stalwart/* in openova-private is hand-rolled
# Kustomize, not a chart). The Catalyst overlay templates (StatefulSet,
# Services, Ingress, ConfigMap, NetworkPolicy, ExternalSecret consumers,
# mailbox-provision Job) are entirely in templates/ in this chart. The
# `sigstore/common` library subchart below is included ONLY to satisfy
# the platform-wide blueprint-release.yaml hollow-chart gate (issue #181)
# — every umbrella MUST declare at least one dependency. `common` is a
# tiny library chart (helper templates only, zero runtime resources) and
# contributes nothing to the rendered manifests of bp-stalwart-tenant.
dependencies:
  - name: common
    version: "0.1.3"
    repository: "https://sigstore.github.io/helm-charts"
