Validate Helm Charts / Detect changed charts (pull_request) Successful in 5s
Validate Helm Charts / Resource quantities (pull_request) Successful in 17s
Validate Helm Charts / Selector match (pull_request) Successful in 16s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 14s
Validate Helm Charts / Build stalwart (pull_request) Successful in 8s
Validate Helm Charts / Trivy config stalwart (pull_request) Successful in 22s
Install-test / Install-test stalwart (pull_request) Successful in 1m44s
Validate Helm Charts / Install-test (pull_request) Successful in 1m44s
The policy route for mta-sts.<domain> belonged to another repository
(jk-cluster-config) while pointing at this chart's own Service. It moves
here as mtaSts.hosts, a list, so several domains - subdomains included -
are maintainable in one place and in whichever routing mode is active.
THE LIST IS THE SWITCH. No mtaSts.enabled: "enabled with an empty list"
would be a state with no meaning that the chart would then have to catch.
The schema rejects the key outright, so the rule is enforced rather than
documented. Default [] renders nothing in either mode - the defaults and
the unchanged CI fixture both produce a byte-identical helm template
against origin/main.
Entry form {host, tlsSecretName, clusterIssuer?}. The two TLS fields are
read ONLY in Ingress mode; in Gateway mode TLS sits on the listener, so
requiring them there would demand a value that does nothing.
THE PATH IS HARDWIRED. RFC 8461 fixes /.well-known/mta-sts.txt, rendered
with pathType Exact (type: Exact in the route). A values key for a
protocol-mandated path can only ever be set wrong, and wrong is invisible
from this side. Exact also matters in itself: a prefix on these hostnames
would publish the mail server's whole management surface under them.
ONE INGRESS PER CLUSTER ISSUER, NOT ONE OBJECT - and the plan's own three
requirements forced that. cert-manager reads the two fields at different
scopes: cluster-issuer is an ANNOTATION (object-scoped, and absent means
nothing is issued for that object at all), while secretName is
tls-entry-scoped and yields one Certificate per entry. So an object cannot
both request a certificate and leave another host's secret alone, which is
what an empty per-entry issuer has to mean. Measured in jk-cluster:
ingress-shim names the Certificate AFTER THE SECRET and owns it from the
Ingress, so a shared secret must sit in exactly one object (hence grouping
the tls list by secret, reusing rss-bridge.tlsGroups' shape) and a secret
may not span two issuer groups (hence the abort). Objects are named by
issuer, not by index: an index is only free where the object holds no
certificate, which is the precondition homeassistant's route naming states
for itself.
Gateway mode renders ONE HTTPRoute with every hostname - nothing differs
per host there - attached to the same Gateway(s) as the WebUI route.
WHAT THE CHART CANNOT PROMISE, AND THEREFORE NAMES: it registers a route,
it does not create a domain. The domains live in Stalwart's data store, so
an entry whose domain is missing there answers 404 at a correctly routed
endpoint with every object green - and MTA-STS failures are silent on the
SENDER's side, which delivers in the clear and logs nothing here. Same for
the _mta-sts.<domain> TXT record and the policy's content. The subdomain
trap is documented too: mta-sts.sub.<domain> is one label below
*.<domain>, so a parent wildcard certificate does not cover it.
Not folded into certificate.extraDnsNames deliberately - that would hang
the MAIL certificate on this list, letting a bad policy entry take STARTTLS
and IMAPS with it.
Minor, additive, empty default: 1.2.0+upv0.16.25 -> 1.3.0+upv0.16.25.
CI: ci/httproute/stalwart.yaml enters all three shapes of the entry form
(with issuer, without, and a subdomain), taking the HTTPRoute render test
from 56 assertions over 21 charts to 58 over 21 - stalwart from 2 to 4.
The Ingress half cannot be covered there, since an overlay's whole job is
to switch the mode off, so ci/stalwart/test-values.yaml carries two
entries and the install-test has a real API server accept them.
Fixes #123
98 lines
5.3 KiB
YAML
98 lines
5.3 KiB
YAML
# Render-only overlay for ci/run-httproute-match-test.sh, applied LAST.
|
|
#
|
|
# Its one job is to put this chart into Gateway mode, because the convention
|
|
# ships with httpRoute.enabled: false and the test would otherwise be green
|
|
# over nothing. A chart that has an overlay here and still renders no
|
|
# HTTPRoute FAILS the test - that is the whole point of the file existing.
|
|
#
|
|
# An overlay and not a change to ci/stalwart/test-values.yaml: the install-test
|
|
# runs exactly ONE configuration per chart, and this chart's fixture brings up
|
|
# the node groups against a throwaway Postgres. Trading its Ingress for a CRD
|
|
# schema check that cyberchef's fixture already performs against the real
|
|
# Gateway-API CRDs would be a bad swap. The install keeps the Ingress; the
|
|
# route is held here, at render level, which is where its silent failure modes
|
|
# live.
|
|
#
|
|
# ingress.enabled: false is not optional here - ingress.enabled is this chart's
|
|
# HTTP routing switch and defaults to TRUE, so without this line the chart
|
|
# aborts its own render with both modes on.
|
|
#
|
|
# WHAT THIS OVERLAY COVERS:
|
|
#
|
|
# - ingress.domain comes from the fixture, so the route renders with its
|
|
# hostname from that single source of truth. httpRoute.hostnames stays
|
|
# empty on purpose: the fallback is the path every installation will
|
|
# actually use.
|
|
# - ingress.nodeGroup comes from the fixture too, so the route is checked to
|
|
# point at THAT GROUP'S http Service and no other. This chart is the one in
|
|
# group 3 where the backend is group-scoped, and the ONE-route-not-one-
|
|
# per-group property is exactly what would be easy to get wrong on a copy.
|
|
# - the backendRef is checked against the per-group http Service of the same
|
|
# render, by PORT NUMBER (ports.http.containerPort) rather than by the name
|
|
# "http" the Ingress uses, because backendRefs takes a PortNumber. Note
|
|
# that this chart's NodePort Services publish a DIFFERENT number
|
|
# (ports.<name>.nodePort) than the container binds, so naming the wrong one
|
|
# here would be a plausible mistake - this overlay is what catches it.
|
|
#
|
|
# No URLRewrite filter is rendered by this chart in either mode, so the #118
|
|
# prefix/redirect assurance has no precondition to meet here.
|
|
#
|
|
# NOT covered here, and none of it can be:
|
|
#
|
|
# - that the hostname answers. No Gateway controller runs in CI and no route
|
|
# reaches "Accepted: True".
|
|
# - THE CORS CONFIGURATION, which is the thing this chart actually loses in
|
|
# this mode and the one that breaks the bulwark webmail. It lives in the
|
|
# operator's ingress.annotations, the chart has no values for it, and the
|
|
# Gateway API's own CORS filter is Extended-support with observed
|
|
# implementation variance - all of which is documented in values.yaml and
|
|
# printed by NOTES.txt. Documentation is not something a test can assert.
|
|
# - that SMTP/IMAP still work. They never went through the Ingress and do not
|
|
# go through the route; the mail Certificate that serves them keeps being
|
|
# rendered in this mode, which is this chart's distinguishing feature in
|
|
# the sweep, and no render test looks at whether it was left alone.
|
|
# - THE MTA-STS ROUTE (Gitea #123), which is the second HTTPRoute this chart
|
|
# renders. Its backendRef is held against the same per-group http Service
|
|
# by the same port number, so the one place information travels from the
|
|
# Service object into a route template is checked twice rather than once.
|
|
# What the list below is shaped for is the three cases the entry form has:
|
|
# an entry WITH a clusterIssuer, an entry WITHOUT one, and a host on a
|
|
# SUBDOMAIN - the last because mta-sts.sub.<domain> is one label deeper
|
|
# than *.<domain> and a parent wildcard does not cover it.
|
|
#
|
|
# Both TLS fields are INERT IN THIS MODE: TLS sits on the Gateway's
|
|
# listener and this chart renders no certificate for an HTTP hostname
|
|
# here. They are set anyway, and that is the assertion - the render has to
|
|
# ACCEPT them in Gateway mode without requiring them, because the mirror
|
|
# image (tlsSecretName required in Ingress mode) is what makes them
|
|
# mode-specific rather than optional-everywhere.
|
|
#
|
|
# The Ingress half of this feature is NOT exercised here - this overlay's
|
|
# whole job is to switch the mode off. It is exercised by
|
|
# ci/stalwart/test-values.yaml instead, which installs in Ingress mode and
|
|
# therefore has the MTA-STS Ingress objects accepted by a real API server.
|
|
ingress:
|
|
enabled: false
|
|
httpRoute:
|
|
enabled: true
|
|
parentRefs:
|
|
- name: public
|
|
namespace: gateway
|
|
sectionName: https
|
|
mtaSts:
|
|
hosts:
|
|
- host: mta-sts.ci.example.com
|
|
tlsSecretName: tls-mta-sts-ci-example-com-ingress
|
|
clusterIssuer: ci-selfsigned
|
|
# One label deeper: its own secret, because the parent's wildcard would not
|
|
# reach it. In this mode that is the Gateway listener's problem, which is
|
|
# exactly why the entry is here and why the values are inert.
|
|
- host: mta-sts.sub.ci.example.com
|
|
tlsSecretName: tls-mta-sts-sub-ci-example-com-ingress
|
|
clusterIssuer: ci-selfsigned
|
|
# No clusterIssuer: "the certificate comes from somewhere else". Nothing in
|
|
# this mode reads it either way; the point is that the render accepts the
|
|
# entry without it.
|
|
- host: mta-sts.other.ci.example
|
|
tlsSecretName: tls-some-existing-wildcard-ingress
|