feat(rss-bridge): Gateway-API as an alternative to the Ingress (last chart)
Validate Helm Charts / Detect changed charts (pull_request) Successful in 4s
Validate Helm Charts / Resource quantities (pull_request) Successful in 17s
Validate Helm Charts / Selector match (pull_request) Successful in 14s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 15s
Validate Helm Charts / Build rss-bridge (pull_request) Successful in 8s
Validate Helm Charts / Trivy config rss-bridge (pull_request) Successful in 24s
Install-test / Install-test rss-bridge (pull_request) Successful in 1m10s
Validate Helm Charts / Install-test (pull_request) Successful in 1m10s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 4s
Validate Helm Charts / Resource quantities (pull_request) Successful in 17s
Validate Helm Charts / Selector match (pull_request) Successful in 14s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 15s
Validate Helm Charts / Build rss-bridge (pull_request) Successful in 8s
Validate Helm Charts / Trivy config rss-bridge (pull_request) Successful in 24s
Install-test / Install-test rss-bridge (pull_request) Successful in 1m10s
Validate Helm Charts / Install-test (pull_request) Successful in 1m10s
rss-bridge was the twenty-second and last chart of the Gateway-API sweep: 22 charts carried an Ingress template, 21 an HTTPRoute template, and the difference was exactly this one. It had been held back as frozen by #51 - a runner defect, not a property of the chart - and that freeze is lifted. One HTTPRoute carrying ALL THREE hostnames, because nothing differs per host: every name serves the same Service at "/", measured on the live Ingress. spec.hostnames is a list, so one object is the whole answer and a second would repeat one rule. (Unlike homeassistant, whose paths differ per host, or matrix-synapse, whose two routes want different backends.) httpRoute.hostnames is its own MANDATORY value, which is a third shape for this repository and follows from the values rather than from taste. Most charts fall back to ingress.domain; freesailarr and homeassistant reject a hostnames key outright, because a chart-global list could not say which app or host entry it belonged to. This chart has no ingress.domain either, but its names are unambiguous - and the ingress.hosts list it would otherwise reuse carries per-host tlsSecretName values that address nothing once TLS sits on the Gateway's listener. Reusing it would drag a structure whose other half is meaningless into the new mode. rss-bridge.tlsGroups is therefore INERT in Gateway mode, and that is named as a simplification rather than quietly translated: the helper exists only to group hosts by TLS secret name, and there is nothing left to group. The required() on ingress.hosts needed no change to become conditional - it already sits inside the Ingress template behind ingress.enabled - so what is new is that values.yaml and the schema now say so. The ingress.enabled-derived-value screen that caught sure, freesailarr and ytdlp-web-player was run here and came back CLEAN: outside the Ingress template the only readers of an ingress value are NOTES.txt, which knows its own mode, and tlsGroups, called only from behind the switch. The app takes no base URL in its environment, so no "published" helper is needed. First chart of the sweep whose Gateway branch has NO loss to explain, and it was measured rather than assumed (read-only kubectl against the live object): the running Ingress carries the cert-manager annotation plus Helm and Rancher/Fleet bookkeeping, and not one nginx.ingress.kubernetes.io annotation. The group-3 screen came back empty, so NOTES.txt says so positively instead of copying a loss paragraph from another chart. Also corrects the last occurrence in the repository of the outdated sentence "charts in this repo deliberately have no dependencies" (rss-bridge/templates/_helpers.tpl) - dependencies are admissible but expensive since #214, and ytdlp-web-player, stalwart and paperless-ngx use subcharts. The reason the helper is duplicated is unchanged, only its content: sharing it would mean a library chart, a second artefact to publish, version and pull for about one change a year. Minor, not major: additive, defaults unchanged, and relaxing a required is not a tightening. Proven with an EMPTY helm template diff against origin/main for the defaults (229 lines, byte-identical); the Gateway mode with its overlay renders the HTTPRoute in place of the Ingress and nothing else changes. appVersion untouched - 2026-09-30 is the newest date tag the registry has, everything newer is sha-* and latest. ci/run-httproute-match-test.sh goes from 56 assertions over 21 charts to 58 over 22. The overlay at ci/httproute/rss-bridge.yaml has to SUPPLY hostnames, the second in the repository that does (homeassistant's was the first, for a different reason), because this chart has no fallback. NOT PROVEN, and stated in the PR as well: that traffic flows. No Gateway controller runs in CI and no HTTPRoute reaches "Accepted: True" there. For this chart there is additionally NO successful install-test at all - it fails on the Gitea runner in either mode (#51, reproduced on two images while the same chart and image run healthy in the cluster). The chart is deliberately NOT added to ci/excluded-charts.txt: an exclusion would silence the signal, and the day the runner is fixed the test goes green by itself. So the only red contexts expected here are "Install-test / Install-test rss-bridge" and the collective "Validate Helm Charts / Install-test". Fixes #114 Fixes #40
This commit is contained in:
8 files changed
+466
-14
No files matched your search
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/RSS-Bridge/rss-bridge/master/static/logo
|
||||
|
||||
type: application
|
||||
|
||||
version: 2.0.0+up2026.09.30
|
||||
version: 2.1.0+up2026.09.30
|
||||
appVersion: "2026-09-30"
|
||||
|
||||
maintainers:
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{{- $httpRoute := .Values.httpRoute | default dict -}}
|
||||
{{- $hostnames := $httpRoute.hostnames | default list -}}
|
||||
RSS-Bridge {{ .Chart.AppVersion }} was installed as release "{{ .Release.Name }}".
|
||||
|
||||
{{ if .Values.ingress.enabled -}}
|
||||
ACCESS - INGRESS MODE (ingress.enabled: true, httpRoute.enabled: false)
|
||||
|
||||
Reachable at:
|
||||
{{ range $entry := .Values.ingress.hosts }} https://{{ $entry.host }}
|
||||
{{ end }}
|
||||
@@ -8,12 +12,82 @@ Each host serves the same instance. Certificates are issued by the
|
||||
cert-manager cluster issuer "{{ .Values.ingress.clusterIssuer }}" into these secrets:
|
||||
{{ range $secret := (fromYaml (include "rss-bridge.tlsGroups" (dict "hosts" .Values.ingress.hosts "root" $))).order }} {{ $secret }}
|
||||
{{ end }}
|
||||
Hosts sharing a secret name share one certificate with several SANs; hosts with
|
||||
distinct names get one certificate each. That grouping is what keeps the three
|
||||
grown certificates of this installation on their existing secret names.
|
||||
{{- else if $httpRoute.enabled -}}
|
||||
ACCESS - GATEWAY MODE (httpRoute.enabled: true, ingress.enabled: false)
|
||||
|
||||
Reachable at:
|
||||
{{ range $hostnames }} https://{{ . }}
|
||||
{{ end }}
|
||||
All of these names are served by ONE HTTPRoute ({{ .Release.Name }}-{{ .Chart.Name }}-httproute), because
|
||||
nothing differs between them: one rule, PathPrefix "/", one backend. Adding or
|
||||
removing a name is an edit to httpRoute.hostnames and nothing else.
|
||||
|
||||
This release renders that route and NOTHING else of the routing path - no
|
||||
Gateway, no class, no Certificate. Three things therefore belong to the cluster
|
||||
and not to this chart, and if any of them is missing the hostnames above simply
|
||||
do not answer:
|
||||
|
||||
1. The Gateway-API CRDs. Without them this install would have failed, so
|
||||
they are present - nothing to check.
|
||||
2. The Gateway named in httpRoute.parentRefs
|
||||
{{- range $httpRoute.parentRefs }}
|
||||
{{ .name }}{{ if .namespace }} in namespace {{ .namespace }}{{ end }}{{ if .sectionName }}, listener {{ .sectionName }}{{ end }}
|
||||
{{- end }}
|
||||
must exist AND its listener must allow routes from this namespace
|
||||
({{ .Release.Namespace }}) in allowedRoutes. A rejected attachment is
|
||||
visible only in the route's status:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} get httproute {{ .Release.Name }}-{{ .Chart.Name }}-httproute -o yaml
|
||||
|
||||
Read status.parents[].conditions - "Accepted: True" and
|
||||
"ResolvedRefs: True" is what a working attachment looks like. An empty
|
||||
status means no controller has looked at the route at all.
|
||||
3. A TLS certificate for every hostname above, on the Gateway's listener.
|
||||
ingress.clusterIssuer is NOT used in this mode and is not required - the
|
||||
chart renders no Certificate here, so none of the tls-* secrets listed by
|
||||
the Ingress mode exists and there is nothing for cert-manager to do on
|
||||
behalf of this release.
|
||||
|
||||
NOTHING THIS CHART DID IN INGRESS MODE IS LOST HERE
|
||||
|
||||
Worth stating plainly, because it is not the usual case in this repository:
|
||||
most charts switched to the Gateway API give something up, since
|
||||
ingress.annotations has no counterpart in this API and an operator's
|
||||
annotation often carried real behaviour. This chart's live Ingress was measured
|
||||
before the switch and carries no nginx.ingress.kubernetes.io annotation at all -
|
||||
no body-size limit, no buffer sizes, no CORS, no rewrite, no auth. So there is
|
||||
no compensation to re-create at the Gateway and no behaviour to miss.
|
||||
|
||||
Two things do become inert, and neither is a loss:
|
||||
|
||||
* ingress.annotations - gone in this mode, as everywhere. Empty here.
|
||||
* The TLS secret grouping (rss-bridge.tlsGroups, and the per-host
|
||||
ingress.hosts[].tlsSecretName it reads) - with the certificate on the
|
||||
listener there is nothing left to group. This is the chart's most
|
||||
intricate Ingress-mode machinery and it simply has no job here.
|
||||
|
||||
What is NOT demonstrated: that traffic actually flows. No Gateway controller
|
||||
runs in this chart's CI, so no HTTPRoute of it has ever reached
|
||||
"Accepted: True" there, and this chart has no successful install-test at all
|
||||
(Gitea #51 - a runner defect, unrelated to this mode). Check the route status
|
||||
above after the first install rather than assuming it attached.
|
||||
{{- else -}}
|
||||
The Ingress is disabled (ingress.enabled=false). Reach the instance with:
|
||||
ACCESS - NEITHER INGRESS NOR HTTPROUTE
|
||||
|
||||
ingress.enabled and httpRoute.enabled are both false, so this release has no
|
||||
Ingress, no HTTPRoute and no certificate; ingress.hosts, ingress.clusterIssuer
|
||||
and httpRoute.hostnames are not needed. Reach the instance with:
|
||||
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ .Release.Name }}-{{ .Chart.Name }}-service 8080:80
|
||||
|
||||
and open http://localhost:8080
|
||||
|
||||
To publish it instead, set either ingress.enabled=true with ingress.hosts and
|
||||
ingress.clusterIssuer, or httpRoute.enabled=true with httpRoute.hostnames and
|
||||
httpRoute.parentRefs.
|
||||
{{- end }}
|
||||
|
||||
Enabled bridges ({{ len .Values.whitelist }} entr{{ if eq (len .Values.whitelist) 1 }}y{{ else }}ies{{ end }} in whitelist.txt):
|
||||
|
||||
@@ -15,9 +15,10 @@ Rules (variant B, see issue #19):
|
||||
- a missing cpu limit is NOT set at all (the kubelet then treats CPU as
|
||||
unlimited; CPU is compressible, so this cannot kill the workload).
|
||||
|
||||
NOTE: charts in this repo deliberately have no dependencies, so this helper is
|
||||
duplicated into every chart's templates/_helpers.tpl with the chart's name as
|
||||
define prefix. template-chart holds the reference implementation.
|
||||
NOTE: this helper is duplicated into every chart's templates/_helpers.tpl with
|
||||
the chart's name as define prefix, because sharing it would mean a library
|
||||
chart, and a dependency is admissible but expensive (README, guideline 14) -
|
||||
this chart takes none. template-chart holds the reference implementation.
|
||||
*/}}
|
||||
{{- define "rss-bridge.resources" -}}
|
||||
{{- $resources := . | default dict -}}
|
||||
@@ -316,6 +317,21 @@ names keep one certificate each, which is what the existing installation needs
|
||||
|
||||
First-appearance order rather than sorted order, so the rendered tls list can
|
||||
be compared line by line against the manifest the chart replaces.
|
||||
|
||||
INGRESS MODE ONLY - THIS HELPER IS INERT IN GATEWAY MODE (Gitea #114)
|
||||
|
||||
Its entire purpose is to group hosts by TLS secret name, and in Gateway mode
|
||||
there is no TLS in this chart to group: the certificate sits on the Gateway's
|
||||
listener and belongs to the platform. Both of its callers - the Ingress
|
||||
template and the Ingress branch of NOTES.txt - live behind ingress.enabled,
|
||||
which Gateway mode forces to false, so it is simply never invoked there.
|
||||
|
||||
Named rather than left to be noticed, because it is the most intricate part of
|
||||
this chart's Ingress and its absence from the Gateway path is a SIMPLIFICATION,
|
||||
not an omission. The corollary is that ingress.hosts[].tlsSecretName has no
|
||||
meaning in Gateway mode, which is why httpRoute.hostnames is a plain list of
|
||||
strings instead of a reuse of ingress.hosts - see the header of
|
||||
rss-bridge.httproute.yaml.
|
||||
*/}}
|
||||
{{- define "rss-bridge.tlsGroups" -}}
|
||||
{{- $root := .root -}}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
{{/*
|
||||
The Gateway-API alternative to rss-bridge.ingress.yaml (Gitea #114), and the
|
||||
LAST chart of that sweep: 22 charts carried an Ingress template and 21 an
|
||||
HTTPRoute template, and the difference was this one. It was held back because
|
||||
its install-test fails on the Gitea runner (#51), not for anything about its
|
||||
shape.
|
||||
|
||||
WHAT THIS RENDERS, AND WHAT IT DELIBERATELY DOES NOT
|
||||
|
||||
Only an HTTPRoute with parentRefs. No Gateway, no gatewayClassName, no
|
||||
Certificate, and no implementation-specific policy object (nginx-gateway-
|
||||
fabric's ClientSettingsPolicy, Envoy Gateway's ClientTrafficPolicy or whatever
|
||||
the next one calls it). That subset is the part which looks IDENTICAL on
|
||||
nginx-gateway-fabric, Cilium, Envoy Gateway and Istio - keeping to it is what
|
||||
lets the cluster's implementation be chosen, or changed, without touching this
|
||||
chart again. A policy object here would bind the chart to one implementation
|
||||
and to a CRD whose presence it cannot check.
|
||||
|
||||
So the class and the certificate move from this chart to the PLATFORM: they sit
|
||||
on the Gateway and its listeners, which belong in cluster-config, not here.
|
||||
|
||||
ONE OBJECT FOR ALL THREE HOSTNAMES, BECAUSE NOTHING DIFFERS PER HOST
|
||||
|
||||
spec.hostnames is a LIST and its rules apply to every hostname of the object.
|
||||
That is a problem for a chart whose paths differ per host, and this chart is
|
||||
the opposite case: every hostname serves the SAME Service at "/" - measured on
|
||||
the live Ingress, which carries three host rules with byte-identical path and
|
||||
backend. So one object with three hostnames, not three objects.
|
||||
|
||||
Contrast, because both shapes exist in this repository and the difference is
|
||||
not style: homeassistant renders one route PER host entry (its paths differ per
|
||||
host), matrix-synapse renders two (homeserver and delegation want different
|
||||
paths and different backends), and the keycloak realms of Gitea #122 would need
|
||||
one each (app-root differs per host). Here a second object would carry the same
|
||||
rule twice.
|
||||
|
||||
WHY httpRoute.hostnames IS ITS OWN VALUE AND DOES NOT REUSE ingress.hosts
|
||||
|
||||
The other charts of the sweep fall into two camps, and this chart is in
|
||||
neither. Where a chart has ingress.domain - a single public name - empty
|
||||
hostnames falls back to it, so there is one source of truth (cyberchef).
|
||||
Where a chart has no ingress.domain, httpRoute has no hostnames key at all and
|
||||
the names come from the values that already hold them, because a chart-global
|
||||
list could not say which app or which host entry it belonged to (freesailarr,
|
||||
homeassistant).
|
||||
|
||||
This chart has no ingress.domain either, but its hostnames are unambiguous:
|
||||
one Service, one path, so a chart-global list means exactly one thing. What
|
||||
makes reuse of ingress.hosts wrong here is the other half of those entries -
|
||||
each carries an OPTIONAL tlsSecretName, which exists only to keep three grown
|
||||
certificates alive on their existing secret names (see the deviation note in
|
||||
values.yaml). In Gateway mode TLS sits on the Gateway's listener, so those
|
||||
names address nothing. Reusing the list would carry a structure whose second
|
||||
field is meaningless into the new mode and invite somebody to set it there.
|
||||
|
||||
Hence: httpRoute.hostnames is a plain list of strings and is MANDATORY in this
|
||||
mode. There is no ingress.domain to fall back to, and an empty list would
|
||||
render a route matching every request that reaches its listener - on a shared
|
||||
Gateway that means answering for hostnames belonging to other releases.
|
||||
|
||||
AND THEREFORE rss-bridge.tlsGroups IS INERT IN THIS MODE
|
||||
|
||||
That helper exists for one purpose: group hosts by TLS secret name so that
|
||||
hosts sharing a name share one certificate with several SANs. With the
|
||||
certificate on the listener there is nothing left for it to group. It is read
|
||||
by the Ingress template and by NOTES.txt's Ingress branch, both behind
|
||||
ingress.enabled, so this mode simply never calls it. That is a SIMPLIFICATION
|
||||
and is named as one rather than quietly translated: the most intricate part of
|
||||
this chart's Ingress has no counterpart here because it has no job here.
|
||||
|
||||
NOTHING IS LOST WITH THE ANNOTATIONS, AND THAT IS MEASURED, NOT ASSUMED
|
||||
|
||||
Group 3 of the sweep screened the LIVE Ingress objects, not just the charts,
|
||||
because an operator's annotation can fill a gap the chart never sets and this
|
||||
mode drops ingress.annotations - four of its six charts carried exactly such an
|
||||
annotation. The same screen was run here against the running object
|
||||
(2026-10-13, read-only kubectl): it carries the cert-manager cluster-issuer
|
||||
annotation plus Helm and Rancher/Fleet bookkeeping, and NOT ONE
|
||||
nginx.ingress.kubernetes.io annotation. So this is the first chart of the sweep
|
||||
whose Gateway branch in NOTES.txt has no loss to explain. ingress.annotations
|
||||
is still inert in this mode - whatever a future installation puts there is
|
||||
gone - but there is nothing there today to lose.
|
||||
|
||||
WHY A VALUE AND NOT AUTO-DETECTION
|
||||
|
||||
.Capabilities.APIVersions is unreliable at template time (it answers from the
|
||||
cluster helm happens to be pointed at, and not at all for `helm template`),
|
||||
while an HTTPRoute without the Gateway-API CRDs fails at INSTALL time. A chart
|
||||
that guessed would therefore sometimes render an object the cluster rejects and
|
||||
sometimes silently render nothing. So the mode is a value.
|
||||
*/}}
|
||||
{{- /*
|
||||
Null-safe like every other block this chart dereferences (#99): an override
|
||||
written without children - "httpRoute:" with the keys below it deleted - is
|
||||
YAML null, and `.Values.httpRoute.enabled` would abort the render with a nil
|
||||
pointer. An empty block means "chart defaults apply", and all three defaults
|
||||
here are empty or false, so the whole block collapses to "no HTTPRoute".
|
||||
*/ -}}
|
||||
{{- $httpRoute := .Values.httpRoute | default dict -}}
|
||||
{{- if and $httpRoute.enabled .Values.ingress.enabled -}}
|
||||
{{- fail "ingress.enabled and httpRoute.enabled are both true - set exactly one of them. The Ingress and the HTTPRoute would publish the same Service under the same hostnames over two different data paths, which is already a conflict at DNS level: one name, two addresses, and which one a client reaches is luck. Note that ingress.enabled DEFAULTS TO TRUE in this chart, so switching to Gateway mode means setting ingress.enabled: false explicitly. A migration runs over a SECOND hostname (give httpRoute.hostnames a name the Ingress does not serve) and never over parallel operation of both." -}}
|
||||
{{- end -}}
|
||||
{{- if $httpRoute.enabled -}}
|
||||
{{- $parentRefs := $httpRoute.parentRefs | default list -}}
|
||||
{{- if not $parentRefs -}}
|
||||
{{- fail "httpRoute.enabled is true but httpRoute.parentRefs is empty - an HTTPRoute without a parent attaches to no Gateway. It is created, it is schema-valid, and it routes NOTHING, with no event and no condition that says so; the only symptom is a hostname that does not answer. Name the cluster's Gateway, e.g. httpRoute.parentRefs: [{name: public, namespace: gateway}]." -}}
|
||||
{{- end -}}
|
||||
{{- $hostnames := $httpRoute.hostnames | default list -}}
|
||||
{{- if not $hostnames -}}
|
||||
{{- fail "httpRoute.enabled is true but httpRoute.hostnames is empty - there is no hostname to publish. Unlike most charts here this one has NO ingress.domain to fall back to, and ingress.hosts is deliberately not reused: its entries carry tlsSecretName values that address nothing once TLS sits on the Gateway's listener. An HTTPRoute with no hostnames also does not render nothing - it matches EVERY request reaching its listener, so on a shared Gateway this release would answer for hostnames belonging to other releases. Set the public names explicitly, e.g. httpRoute.hostnames: [rss-bridge.example.com, feeds.example.com]." -}}
|
||||
{{- end -}}
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-httproute
|
||||
spec:
|
||||
parentRefs:
|
||||
{{- toYaml $parentRefs | nindent 4 }}
|
||||
hostnames:
|
||||
{{- toYaml $hostnames | nindent 4 }}
|
||||
rules:
|
||||
{{- /*
|
||||
The Ingress counterpart is `path: / , pathType: Prefix` on the one backend
|
||||
Service, repeated once per host rule - RSS-Bridge is served at the root and
|
||||
has no second path, so one rule covers all hostnames of this object.
|
||||
|
||||
The port is the Service's port NUMBER and not its name: backendRefs takes a
|
||||
PortNumber, so unlike the Ingress - which references the targetPort by the
|
||||
name rss-bridge-port - this reference cannot be made by name, and the 80
|
||||
below has to track rss-bridge.service.yaml by hand.
|
||||
ci/run-httproute-match-test.sh is what holds that pair: it fails when a
|
||||
backendRef names a Service, or a port, the same render does not create.
|
||||
*/}}
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: {{ .Release.Name }}-{{ .Chart.Name }}-service
|
||||
port: 80
|
||||
{{- end }}
|
||||
@@ -55,21 +55,23 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"description": "Gates the whole Ingress template (issue #93). Nothing outside the Ingress template reads an ingress value in this chart - the container takes no host in its environment - so switching it off frees every value below (guideline 1, checked rather than assumed).",
|
||||
"description": "Gates the whole Ingress template (issue #93). Nothing outside the Ingress template reads an ingress value in this chart - the container takes no host in its environment - so switching it off frees every value below (guideline 1, checked rather than assumed). Mutually exclusive with httpRoute.enabled (Gitea #114) - the render aborts when both are true - and the default here is TRUE, so Gateway mode needs this set to false explicitly. Re-checked for #114, the sweep in which three charts turned out to compute a value from this switch that silently flipped in Gateway mode: this chart computes none. Outside the Ingress template the only readers of an ingress value are NOTES.txt, which knows its own mode, and the tlsGroups helper, which is called only from behind this switch.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"clusterIssuer": {
|
||||
"description": "Not read in Gateway mode: the chart renders no Certificate there. Required only while ingress.enabled, because its single read lives inside the Ingress template behind that switch.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"className": {
|
||||
"description": "Not read in Gateway mode: the class is a property of the Gateway there, and the Gateway belongs to the platform.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"annotations": {
|
||||
"description": "Extra Ingress annotations, merged with the cert-manager annotation the chart always sets. Free-form keys by nature, so this object stays open.",
|
||||
"description": "Extra Ingress annotations, merged with the cert-manager annotation the chart always sets. Free-form keys by nature, so this object stays open. Not read in Gateway mode: the Gateway API has no annotation channel for controller behaviour. Measured on the live object (2026-10-13): the running Ingress carries no nginx.ingress.kubernetes.io annotation at all, so unlike most charts of the sweep this one loses nothing by that today - an absence of evidence about this installation, not a guarantee about another.",
|
||||
"type": "object"
|
||||
},
|
||||
"hosts": {
|
||||
"description": "Hosts this Ingress serves. Each entry carries a host and an optional tlsSecretName; entries sharing a secret name are grouped into one tls entry. Null is accepted by the schema so the template's required() produces the readable error instead of a schema violation.",
|
||||
"description": "Hosts this Ingress serves. Each entry carries a host and an optional tlsSecretName; entries sharing a secret name are grouped into one tls entry. Null is accepted by the schema so the template's required() produces the readable error instead of a schema violation. Not read in Gateway mode, where the public names come from httpRoute.hostnames instead - the required() on this list sits inside the Ingress template behind ingress.enabled and is therefore already conditional on the mode.",
|
||||
"type": ["array", "null"],
|
||||
"items": {
|
||||
"type": "object",
|
||||
@@ -81,16 +83,46 @@
|
||||
"minLength": 1
|
||||
},
|
||||
"tlsSecretName": {
|
||||
"description": "Overrides the conventional tls-<release>-<chart>-ingress name for this host. Set only where an existing certificate must keep its secret name - see the deviation note in values.yaml.",
|
||||
"description": "Overrides the conventional tls-<release>-<chart>-ingress name for this host. Set only where an existing certificate must keep its secret name - see the deviation note in values.yaml. MEANINGLESS IN GATEWAY MODE, where the certificate sits on the Gateway's listener - which is why httpRoute.hostnames is a plain list of strings rather than a reuse of this list.",
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"httpRoute": {
|
||||
"description": "Gateway-API alternative to the Ingress (Gitea #114), and this chart is the last of that sweep. Mutually exclusive with ingress.enabled - the render aborts when both are true, naming both value paths; note that ingress.enabled defaults to TRUE here, so this mode needs it set to false explicitly. The chart renders only an HTTPRoute with parentRefs; class and certificate sit on the Gateway and belong to the platform. ONE object carries every hostname, because nothing differs per host - all hostnames serve the same Service at '/'. The helper rss-bridge.tlsGroups is inert in this mode: with TLS on the listener there is nothing left to group by secret name. The Gateway-API CRDs must be present in the cluster, because the chart cannot detect them.",
|
||||
"type": ["object", "null"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"parentRefs": {
|
||||
"description": "The Gateway(s) the route attaches to. Required while httpRoute.enabled is true, enforced by required()-equivalent in the template (an empty list aborts the render) - a JSON Schema \"required\" cannot do it, because the key ships as an empty list and is therefore present. Entries are the Gateway API's ParentReference and are passed through unchanged.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/parentRef"
|
||||
}
|
||||
},
|
||||
"hostnames": {
|
||||
"description": "The public names of this release in Gateway mode. Required while httpRoute.enabled is true - the template aborts on an empty list, which a JSON Schema \"required\" cannot express because the key ships as an empty list. Its own value rather than a fallback or a reuse: this chart has no ingress.domain to fall back to, and ingress.hosts entries carry tlsSecretName values that address nothing once TLS sits on the Gateway's listener. Unlike freesailarr and homeassistant - which reject a hostnames key outright because a chart-global list could not say which app or host entry it belonged to - this chart serves one Service on one path, so a chart-global list is unambiguous. An empty list would not render nothing: a route without hostnames matches every request reaching its listener.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"parentRef": {
|
||||
"description": "A Gateway API ParentReference, passed verbatim into HTTPRoute.spec.parentRefs. Deliberately left OPEN (no additionalProperties: false), for the same reason probes and security contexts are: Kubernetes owns this schema, the Gateway API adds fields to it across releases, and a closed list here would reject a field only upstream knows about. What the chart can assert is that \"name\" is there - it is required by the API and a reference without it attaches to nothing, which is the silent failure this chart aborts the render over.",
|
||||
"type": "object",
|
||||
"required": ["name"]
|
||||
},
|
||||
"resources": {
|
||||
"description": "May be null / empty: the chart then falls back to its default requests AND its explicit limits (issue #99). Reproducing only the requests would let limitFactor compute a memory limit below the measured peak.",
|
||||
"type": ["object", "null"],
|
||||
|
||||
@@ -186,15 +186,55 @@ ingress:
|
||||
# takes no domain in its environment and nginx serves as default_server
|
||||
# without a server_name - so switching the Ingress off frees every value
|
||||
# below, and none of them needs a separate required().
|
||||
#
|
||||
# MUTUALLY EXCLUSIVE WITH httpRoute.enabled (Gitea #114) - the render aborts
|
||||
# when both are true, naming both value paths. Note the default here is TRUE,
|
||||
# so switching to Gateway mode means setting this to false explicitly.
|
||||
#
|
||||
# Re-checked for #114, because this is the value that trips charts up in the
|
||||
# Gateway mode: anything COMPUTED from ingress.enabled flips when the mode
|
||||
# changes, and three charts of the sweep (sure, freesailarr,
|
||||
# ytdlp-web-player) had exactly such a value - one of them a silent
|
||||
# authentication bypass. This chart has none. The grep was run over the whole
|
||||
# chart directory: outside the Ingress template the only readers of an
|
||||
# ingress value are NOTES.txt (which knows its own mode) and the tlsGroups
|
||||
# helper (called only from behind this switch). RSS-Bridge takes no base URL
|
||||
# and no hostname in its environment, so there is nothing here that could
|
||||
# come out wrong while the pod stayed Ready - no "published" helper needed.
|
||||
enabled: true
|
||||
# NOT READ IN GATEWAY MODE: the chart renders no Certificate there, so there
|
||||
# is nothing for cert-manager to do on behalf of this release. Required only
|
||||
# while ingress.enabled - the single read lives inside the Ingress template,
|
||||
# behind that switch.
|
||||
clusterIssuer: null
|
||||
# NOT READ IN GATEWAY MODE: the class is a property of the Gateway there, and
|
||||
# the Gateway belongs to the platform (cluster-config).
|
||||
className: nginx
|
||||
# Extra annotations for the Ingress; merged with the cert-manager
|
||||
# cluster-issuer annotation the chart always sets.
|
||||
#
|
||||
# NOT READ IN GATEWAY MODE: the Gateway API has no annotation channel for
|
||||
# controller behaviour, so anything put here is gone in that mode.
|
||||
#
|
||||
# Unlike most charts of the sweep, this one loses NOTHING by that today, and
|
||||
# it was measured rather than assumed (2026-10-13, read-only kubectl against
|
||||
# the live object): the running Ingress carries the cert-manager
|
||||
# cluster-issuer annotation plus Helm and Rancher/Fleet bookkeeping, and not
|
||||
# one nginx.ingress.kubernetes.io annotation. Group 3 of the sweep found an
|
||||
# operator-set annotation filling a chart's gap on four of its six charts -
|
||||
# that screen came back empty here. An absence of evidence about THIS
|
||||
# installation is not a guarantee about yours: whatever you put here still
|
||||
# disappears in Gateway mode.
|
||||
annotations: {}
|
||||
# The hosts this Ingress serves. Required - the chart ships no default,
|
||||
# because hostnames are installation data and have no business in a chart.
|
||||
#
|
||||
# NOT READ IN GATEWAY MODE, and this is the one value of the block where that
|
||||
# needed a decision rather than a note - see httpRoute.hostnames below. The
|
||||
# required() on this list lives inside the Ingress template, behind
|
||||
# ingress.enabled, so it is already conditional on the mode and demands
|
||||
# nothing in Gateway mode.
|
||||
#
|
||||
# Each entry is a host plus an OPTIONAL tlsSecretName:
|
||||
#
|
||||
# hosts:
|
||||
@@ -223,4 +263,90 @@ ingress:
|
||||
# place today and turns the eventual consolidation onto one certificate - or
|
||||
# the retirement of the legacy hostnames - into a values change instead of a
|
||||
# template change (the explicit ask from cluster-config#33).
|
||||
#
|
||||
# tlsSecretName IS MEANINGLESS IN GATEWAY MODE - the certificate sits on the
|
||||
# Gateway's listener - which is why httpRoute.hostnames below is a plain list
|
||||
# of strings rather than a reuse of this one.
|
||||
hosts: null
|
||||
|
||||
# THE GATEWAY-API ALTERNATIVE TO THE INGRESS ABOVE (Gitea #114), and this chart
|
||||
# is the LAST of that sweep - 22 charts carried an Ingress template, 21 an
|
||||
# HTTPRoute template, and the difference was this one. It was held back because
|
||||
# its install-test fails on the Gitea runner (#51), not for anything about its
|
||||
# shape, and that test is still red: the failure is a known, bounded
|
||||
# environment defect and no finding about this mode.
|
||||
#
|
||||
# Off by default, so an existing release is unaffected. Mutually exclusive with
|
||||
# ingress.enabled - the render aborts when both are true, naming both value
|
||||
# paths. Note that ingress.enabled DEFAULTS TO TRUE here, so this mode needs
|
||||
# ingress.enabled: false set explicitly.
|
||||
#
|
||||
# The chart renders ONLY an HTTPRoute with parentRefs - no Gateway, no
|
||||
# gatewayClassName, no Certificate and no implementation-specific policy
|
||||
# object. Class and certificate belong to the Gateway and therefore to the
|
||||
# platform (cluster-config), which is what keeps this chart independent of
|
||||
# whether the cluster runs nginx-gateway-fabric, Cilium, Envoy Gateway or
|
||||
# Istio.
|
||||
#
|
||||
# ONE OBJECT FOR EVERY HOSTNAME, because nothing differs per host: all three
|
||||
# hostnames of the live installation serve the same Service at "/", measured on
|
||||
# the running Ingress. spec.hostnames is a list and its rules apply to every
|
||||
# hostname of the object, so one object is enough - unlike homeassistant (paths
|
||||
# differ per host) or matrix-synapse (different paths and backends).
|
||||
#
|
||||
# WHAT BECOMES INERT, AND IT IS A SIMPLIFICATION RATHER THAN A LOSS:
|
||||
# rss-bridge.tlsGroups, the helper that groups hosts by TLS secret name so the
|
||||
# three grown certificates keep their names. With TLS on the listener there is
|
||||
# nothing left for it to group, and this mode never calls it.
|
||||
#
|
||||
# The Gateway-API CRDs must be installed in the cluster: the chart does not and
|
||||
# cannot detect them (.Capabilities.APIVersions is unreliable at template
|
||||
# time), so with httpRoute.enabled: true and no CRDs the INSTALL fails.
|
||||
httpRoute:
|
||||
enabled: false
|
||||
# The Gateway(s) this route attaches to - a platform object, usually in
|
||||
# another namespace, which must allow this namespace in its listener's
|
||||
# allowedRoutes. One entry per parent, the fields are the Gateway API's
|
||||
# ParentReference (name, and optionally namespace, sectionName, port, group,
|
||||
# kind), passed through unchanged:
|
||||
#
|
||||
# parentRefs:
|
||||
# - name: public
|
||||
# namespace: gateway
|
||||
# sectionName: https
|
||||
#
|
||||
# REQUIRED while httpRoute.enabled is true - the render aborts on an empty
|
||||
# list, because a route without a parent is created, is valid and routes
|
||||
# nothing, with no event to say so.
|
||||
parentRefs: []
|
||||
# The public names of this release in Gateway mode. REQUIRED while
|
||||
# httpRoute.enabled is true - the render aborts on an empty list.
|
||||
#
|
||||
# Its own value, and both halves of that are deliberate:
|
||||
#
|
||||
# Why not a fallback like the other charts: most of them have an
|
||||
# ingress.domain - one public name - and an empty hostnames list falls back
|
||||
# to it so there is a single source of truth. This chart has no
|
||||
# ingress.domain; it has a LIST of hosts, so there is no single name to fall
|
||||
# back to.
|
||||
#
|
||||
# Why not a reuse of ingress.hosts: those entries carry an optional
|
||||
# tlsSecretName, which exists only to keep three grown certificates alive on
|
||||
# their existing secret names, and which addresses nothing once TLS sits on
|
||||
# the Gateway's listener. Reusing the list would drag a structure whose
|
||||
# second field is meaningless into this mode and invite somebody to set it
|
||||
# there. (freesailarr and homeassistant REJECT a hostnames key outright, for
|
||||
# the opposite reason: a chart-global list could not say which app or which
|
||||
# host entry it belonged to. Here there is one Service on one path, so a
|
||||
# chart-global list says exactly one thing - which is why this chart gets the
|
||||
# key those two refuse.)
|
||||
#
|
||||
# An empty list does NOT render nothing: an HTTPRoute without hostnames
|
||||
# matches every request that reaches its listener, so on a shared Gateway
|
||||
# this release would answer for hostnames belonging to other releases. Hence
|
||||
# the abort.
|
||||
#
|
||||
# hostnames:
|
||||
# - rss-bridge.example.com
|
||||
# - feeds.example.com
|
||||
hostnames: []
|
||||
Reference in new issue
Block a user