feat: Gateway-API as an alternative to the Ingress in eight charts (#114, group 1) #116

Merged
jklein merged 1 commits from feat/gateway-api-group-1 into main 2026-10-12 19:46:15 +02:00
Member

Group 1 of the #114 sweep: the eight charts that render exactly one Ingress object and set no behaviour-bearing nginx annotation — bentopdf, garage, patchmon, rallly, searxng, sure, urlaubsverwaltung, voucher-vault. One PR, eight charts, eight minor bumps.

The form is the one PR #115 fixed and template-chart/templates/xxx.httproute.yaml carries; nothing about it was renegotiated. Per chart: an httpRoute block (enabled/parentRefs/hostnames, off by default), a template rendering only an HTTPRoute with parentRefs — no Gateway, no gatewayClassName, no Certificate, no implementation-specific policy object — render aborts on both modes at once (naming both value paths), on an empty parentRefs and on a missing hostname, empty hostnames meaning [ingress.domain], a values.schema.json entry closed against unknown keys with an open parentRef definition, and a NOTES.txt that names the active mode.

The minor proof: eight helm template diffs against origin/main

Rendered with each chart's own ci/<chart>/test-values.yaml (chart defaults alone do not render — the required() secret refs fire first), against the origin/main tree exported with git archive:

Chart helm template vs origin/main
bentopdf empty (195 lines)
garage empty (525 lines)
patchmon empty (275 lines)
rallly empty (200 lines)
searxng empty (260 lines)
sure two YAML comment lines; every rendered value identical — empty diff over 387 lines / 7 documents once indented # lines are dropped, # Source: headers kept
urlaubsverwaltung empty (239 lines)
voucher-vault empty (315 lines)

sure's two lines are the comment its shared env helper emits into the manifest; the explanation moved into a {{/* */}} block that is not rendered, precisely so future edits to the rationale do not show up as diffs in a deployed object. RAILS_ASSUME_SSL/RAILS_FORCE_SSL render "true" before and after.

ingress.clusterIssuer: a no-op in all eight, so nothing was changed

Checked per chart rather than assumed, and the pilot's finding holds eight more times: the only required() on ingress.clusterIssuer sits inside <chart>.ingress.yaml, already behind {{- if .Values.ingress.enabled }}. NOTES.txt reads it only in the ingress.enabled branch and without required(). So "require it conditionally" would have changed no behaviour in any of the eight, and no template was rebuilt for it. The descriptions were corrected where they claimed something that is now false — that is documentation, not a code path.

ingress.domain is the opposite question and the answer differs per chart:

Chart second reader of ingress.domain, with its own required() required in Gateway mode because
bentopdf none the HTTPRoute's hostname fallback
garage none the HTTPRoute's hostname fallback
patchmon CORS_ORIGIN (Deployment) — plus the probes' Host header, which uses ` default ""` and demands nothing
rallly NEXT_PUBLIC_BASE_URL the app, in every mode
searxng SEARXNG_BASE_URL the app, in every mode
sure APP_DOMAIN, WEBAUTHN_RP_ID, WEBAUTHN_ALLOWED_ORIGINS the app, in every mode
urlaubsverwaltung none (UV_MAIL_APPLICATIONURL is a hardcoded placeholder) the HTTPRoute's hostname fallback
voucher-vault Django's DOMAIN → ALLOWED_HOSTS the app, in every mode

Each chart's values comment and schema description now say which of these two it is; three of them (bentopdf, garage, urlaubsverwaltung) previously said "with the Ingress off, domain is free", which stopped being true the moment a second routing template reads it.

Three findings that were not in the plan

1. sure derived its TLS flags from ingress.enabled alone. RAILS_ASSUME_SSL and RAILS_FORCE_SSL were rendered from .Values.ingress.enabled — exactly right while an Ingress was the only way to publish. Gateway mode sets ingress.enabled: false by construction (the modes are mutually exclusive) while TLS is still terminated, now at the Gateway's listener. Both flags would have come out false: Rails would not trust the forwarded scheme, would hand out session cookies without the Secure attribute over a TLS connection, would send no HSTS and would build absolute URLs — mail links, OIDC redirects — as http://. Nothing fails; the pod is Ready and the UI works.

They now read a new sure.publishedOverTls helper, i.e. ingress.enabled OR httpRoute.enabled. With httpRoute.enabled at its default of false that expression is ingress.enabled, which is why the chart stays Minor and the default render is unchanged. Measured in all three modes: Ingress true/true, Gateway true/true, both off false/false.

This is the generalizable one. freesailarr (group 2) and ytdlp-web-player (group 3) also read .Values.ingress.enabled outside their Ingress templates — named in README so the later groups look rather than discover.

2. garage asserted something this PR makes false. Its Ingress template header and its schema both stated, under "guideline 1, checked in both directions", that nothing outside that template reads ingress.domain, so switching the Ingress off freed domain as well as clusterIssuer. garage.httproute.yaml is now a second reader, so the claim holds only while both modes are off. Corrected in both places rather than left standing. garage.s3.rootDomain stays uncoupled — a wildcard vhost suffix and the single host a route answers on are still different things.

3. garage depends on a proxy-body-size it does not set — so the issue's list of five is a list of six. #114 and README name bulwark, calibre-web-automated, outline, paperless-ngx, zipline as the charts that lose their upload limit in Gateway mode, measured on charts that hardcode the annotation. garage sets annotations: {} and therefore passed group 1's screen — but its values comment tells the operator to set nginx.ingress.kubernetes.io/proxy-body-size: "0", because ingress-nginx's 1 MB default truncates S3 uploads. For an object store that is not a detail; it is where PUTs start failing by size. proxy-body-size has no Gateway-API counterpart, so garage's Gateway-mode NOTES.txt prints that the limit is the Gateway's and has to be raised there, and README now names it as a sixth affected chart with the distinction spelled out: "sets no behaviour-bearing annotation" is not the same question as "needs none", and the sweep screens on the second one.

This did not warrant halting the group: the fix fits entirely inside the prescribed form (a NOTES.txt line and a values comment — no new value, no policy object), and the group-1 criterion as written is satisfied by the chart. It is reported here because the criterion is what needs amending for groups 2 and 3, not this chart.

Annotation guidance moved into the Gateway branch

Two of the eight document ingress.annotations as the lever for something the app cannot do itself — the same shape as the pilot's "put auth in front of it" note:

  • bentopdf — the X-Robots-Tag snippet that keeps a public instance out of search indexes (ROBOTS_NOINDEX cannot run on a read-only root filesystem), and the repair for a controller that overrides the .mjs MIME type or strips the two cross-origin headers. Gateway branch now says both are gone from the chart. The cross-origin headers themselves are sent by the image, so they still arrive in both modes — that note became "two headers have to survive your proxy" with a mode-aware curl, since it is a thing to check rather than configure.
  • searxng — the Authentik forward-auth block, documented as where a login belongs for an app that has none. Gateway branch says the channel does not exist in the chart at all, and that the rate limiter is unaffected because it runs inside SearXNG against a Valkey, not at the proxy.

The remaining six carry no behaviour-bearing guidance; their annotations comments gained the standard "no counterpart in Gateway mode" paragraph, and patchmon/sure additionally say what does not live there (the WebSocket upgrade works on a plain route, TRUST_PROXY and the TLS flags are environment variables).

garage: the decision and why

garage ships ingress.enabled: false, so by default it publishes nothing in either mode — correct and unchanged. Two consequences:

  • Its fixture keeps the Ingress on, and the route gets a render overlay. ci/garage/test-values.yaml sets ingress.enabled: true deliberately, so the install-test proves the Service port it references by name (s3) exists. An HTTPRoute cannot make that reference — backendRefs takes a PortNumber — so flipping the fixture to Gateway mode would have traded a check that catches a renamed port for one that does not, and given up garage's only Ingress coverage, for a CRD schema cyberchef's fixture already exercises against the real Gateway-API CRDs. Same reasoning applied to the other seven: install-test stays in Ingress mode, the route is held at render level, which is where its two silent failure modes live.
  • It is the one chart whose backendRefs port is rendered from a value. garage.ports.s3 is configurable, so a literal 3900 in the route would be a lie the moment anyone changes it. The route renders the port from the same garage.settings helper garage.service.yaml uses, so the two cannot drift by construction — and the assertion resolves it: backendRefs[0] resolves to Service httproute-garage-service:3900. That the test checks Service and port is exactly what makes this provable.

Verification

Run locally, all green:

  • ci/helm-dependencies.sh per chart; helm lint --strict ×8 at defaults and ×8 with CI values + Gateway overlay — 0 failed in all 16.
  • helm package ×8 — the eight bumped versions build.
  • ci/run-httproute-match-test.sh: 10 charts checked, 20 assertions held, 0 failed, 0 not checked — up from 4 assertions over 2 charts (cyberchef, template-chart). Each of the eight contributes "1 parentRef public/gateway" + "backendRefs[0] resolves to <release>-<chart>-service:<port>".
  • ci/run-quantity-render-test.sh: 28 exercised, 0 failed. ci/run-selector-match-test.sh: 0 failed.
  • 88 render/schema assertions across the eight charts, both directions — 6 rejections each (both modes on, naming both value paths; empty parentRefs; no hostname at all; an unknown key under httpRoute; a parentRef without name; a hostnames entry of the wrong type) and 5 acceptances each (a valid Gateway config; explicit hostnames; an extra ParentReference field upstream may add, proving the definition stays open; httpRoute: erased to YAML null rendering no route, #99; chart defaults rendering no route).
  • NOTES.txt rendered in all three modes for all eight charts (24 renders, 0 failures) — worth doing explicitly, because CI renders NOTES only through the install-test, whose fixtures stay in Ingress mode, so the Gateway branch is reached by no pipeline stage for these charts.

Not verified, and not claimed

  • That traffic flows. No Gateway controller runs in CI and none will. Green means a schema-valid object and a Ready pod, not that the route routes.
  • No runtime check of any kind was run locally: no k3d, no Docker, no Trivy, no cluster. The install-test and trivy config results in this PR are whatever the pipeline produces.
  • helm install --dry-run could not be used for the NOTES check — this workspace's service account may not read httproutes — so NOTES were rendered offline by copying each chart's NOTES.txt into a throwaway template. That proves the template compiles and every branch evaluates; it says nothing about a cluster.

Scope and what stays open

Untouched, as scoped: rss-bridge (frozen for changes, #51), group 2 (calibre-web-automated, outline, paperless-ngx, zipline, freesailarr), group 3 (homeassistant, keycloak, bulwark, matrix-synapse, stalwart, ytdlp-web-player).

Keyword is Part of #114, not Fixes. Twelve charts remain plus rss-bridge — and #114 cannot be closed while #51 is open, because rss-bridge renders an Ingress and is frozen, so the sweep cannot reach completion by working through the groups alone. Whoever lands the last group should expect to leave #114 open and say why.

Wiki: the eight chart pages, Lessons-Learned (the ingress.enabled-derived-value class, which groups 2 and 3 will meet again). No new Charts row and no _Sidebar entry — the charts already exist. Chart-Style-Guide §4 unchanged: the convention was not altered, only applied.

Part of #114

Group 1 of the #114 sweep: the eight charts that render **exactly one** Ingress object and set **no** behaviour-bearing nginx annotation — `bentopdf`, `garage`, `patchmon`, `rallly`, `searxng`, `sure`, `urlaubsverwaltung`, `voucher-vault`. One PR, eight charts, eight **minor** bumps. The form is the one PR #115 fixed and `template-chart/templates/xxx.httproute.yaml` carries; nothing about it was renegotiated. Per chart: an `httpRoute` block (`enabled`/`parentRefs`/`hostnames`, off by default), a template rendering **only** an `HTTPRoute` with `parentRefs` — no Gateway, no `gatewayClassName`, no Certificate, no implementation-specific policy object — render aborts on both modes at once (naming both value paths), on an empty `parentRefs` and on a missing hostname, empty `hostnames` meaning `[ingress.domain]`, a `values.schema.json` entry closed against unknown keys with an open `parentRef` definition, and a `NOTES.txt` that names the active mode. ## The minor proof: eight `helm template` diffs against `origin/main` Rendered with each chart's own `ci/<chart>/test-values.yaml` (chart defaults alone do not render — the `required()` secret refs fire first), against the `origin/main` tree exported with `git archive`: | Chart | `helm template` vs `origin/main` | | --- | --- | | `bentopdf` | **empty** (195 lines) | | `garage` | **empty** (525 lines) | | `patchmon` | **empty** (275 lines) | | `rallly` | **empty** (200 lines) | | `searxng` | **empty** (260 lines) | | `sure` | **two YAML comment lines**; every rendered *value* identical — empty diff over 387 lines / 7 documents once indented `#` lines are dropped, `# Source:` headers kept | | `urlaubsverwaltung` | **empty** (239 lines) | | `voucher-vault` | **empty** (315 lines) | `sure`'s two lines are the comment its shared env helper emits into the manifest; the explanation moved into a `{{/* */}}` block that is *not* rendered, precisely so future edits to the rationale do not show up as diffs in a deployed object. `RAILS_ASSUME_SSL`/`RAILS_FORCE_SSL` render `"true"` before and after. ## `ingress.clusterIssuer`: a no-op in all eight, so nothing was changed Checked per chart rather than assumed, and the pilot's finding holds eight more times: the **only** `required()` on `ingress.clusterIssuer` sits inside `<chart>.ingress.yaml`, already behind `{{- if .Values.ingress.enabled }}`. `NOTES.txt` reads it only in the `ingress.enabled` branch and without `required()`. So "require it conditionally" would have changed no behaviour in any of the eight, and no template was rebuilt for it. The *descriptions* were corrected where they claimed something that is now false — that is documentation, not a code path. `ingress.domain` is the opposite question and the answer differs per chart: | Chart | second reader of `ingress.domain`, with its own `required()` | required in Gateway mode because | | --- | --- | --- | | `bentopdf` | none | the HTTPRoute's hostname fallback | | `garage` | none | the HTTPRoute's hostname fallback | | `patchmon` | `CORS_ORIGIN` (Deployment) — plus the probes' `Host` header, which uses `| default ""` and demands nothing | the app, in every mode | | `rallly` | `NEXT_PUBLIC_BASE_URL` | the app, in every mode | | `searxng` | `SEARXNG_BASE_URL` | the app, in every mode | | `sure` | `APP_DOMAIN`, `WEBAUTHN_RP_ID`, `WEBAUTHN_ALLOWED_ORIGINS` | the app, in every mode | | `urlaubsverwaltung` | none (`UV_MAIL_APPLICATIONURL` is a hardcoded placeholder) | the HTTPRoute's hostname fallback | | `voucher-vault` | Django's `DOMAIN` → `ALLOWED_HOSTS` | the app, in every mode | Each chart's values comment and schema description now say which of these two it is; three of them (`bentopdf`, `garage`, `urlaubsverwaltung`) previously said "with the Ingress off, `domain` is free", which stopped being true the moment a second routing template reads it. ## Three findings that were not in the plan **1. `sure` derived its TLS flags from `ingress.enabled` alone.** `RAILS_ASSUME_SSL` and `RAILS_FORCE_SSL` were rendered from `.Values.ingress.enabled` — exactly right while an Ingress was the only way to publish. Gateway mode sets `ingress.enabled: false` **by construction** (the modes are mutually exclusive) while TLS is still terminated, now at the Gateway's listener. Both flags would have come out `false`: Rails would not trust the forwarded scheme, would hand out session cookies **without the Secure attribute over a TLS connection**, would send no HSTS and would build absolute URLs — mail links, OIDC redirects — as `http://`. Nothing fails; the pod is Ready and the UI works. They now read a new `sure.publishedOverTls` helper, i.e. `ingress.enabled OR httpRoute.enabled`. With `httpRoute.enabled` at its default of `false` that expression **is** `ingress.enabled`, which is why the chart stays Minor and the default render is unchanged. Measured in all three modes: Ingress `true/true`, Gateway `true/true`, both off `false/false`. This is the generalizable one. `freesailarr` (group 2) and `ytdlp-web-player` (group 3) also read `.Values.ingress.enabled` outside their Ingress templates — named in README so the later groups look rather than discover. **2. `garage` asserted something this PR makes false.** Its Ingress template header and its schema both stated, under "guideline 1, checked in both directions", that *nothing* outside that template reads `ingress.domain`, so switching the Ingress off freed `domain` as well as `clusterIssuer`. `garage.httproute.yaml` is now a second reader, so the claim holds only while **both** modes are off. Corrected in both places rather than left standing. `garage.s3.rootDomain` stays uncoupled — a wildcard vhost suffix and the single host a route answers on are still different things. **3. `garage` depends on a `proxy-body-size` it does not set — so the issue's list of five is a list of six.** #114 and README name `bulwark`, `calibre-web-automated`, `outline`, `paperless-ngx`, `zipline` as the charts that lose their upload limit in Gateway mode, measured on charts that *hardcode* the annotation. `garage` sets `annotations: {}` and therefore passed group 1's screen — but its values comment tells the operator to set `nginx.ingress.kubernetes.io/proxy-body-size: "0"`, because ingress-nginx's 1 MB default truncates S3 uploads. For an object store that is not a detail; it is where PUTs start failing by size. `proxy-body-size` has no Gateway-API counterpart, so `garage`'s Gateway-mode `NOTES.txt` prints that the limit is the Gateway's and has to be raised there, and README now names it as a sixth affected chart with the distinction spelled out: "sets no behaviour-bearing annotation" is not the same question as "needs none", and the sweep screens on the second one. This did not warrant halting the group: the fix fits entirely inside the prescribed form (a `NOTES.txt` line and a values comment — no new value, no policy object), and the group-1 criterion as written is satisfied by the chart. It is reported here because the *criterion* is what needs amending for groups 2 and 3, not this chart. ## Annotation guidance moved into the Gateway branch Two of the eight document `ingress.annotations` as the lever for something the app cannot do itself — the same shape as the pilot's "put auth in front of it" note: - **`bentopdf`** — the `X-Robots-Tag` snippet that keeps a public instance out of search indexes (`ROBOTS_NOINDEX` cannot run on a read-only root filesystem), and the repair for a controller that overrides the `.mjs` MIME type or strips the two cross-origin headers. Gateway branch now says both are gone from the chart. The cross-origin headers themselves are sent by the *image*, so they still arrive in both modes — that note became "two headers have to survive your **proxy**" with a mode-aware `curl`, since it is a thing to check rather than configure. - **`searxng`** — the Authentik forward-auth block, documented as where a login belongs for an app that has none. Gateway branch says the channel does not exist in the chart at all, and that the rate limiter is unaffected because it runs inside SearXNG against a Valkey, not at the proxy. The remaining six carry no behaviour-bearing guidance; their `annotations` comments gained the standard "no counterpart in Gateway mode" paragraph, and `patchmon`/`sure` additionally say what does *not* live there (the WebSocket upgrade works on a plain route, `TRUST_PROXY` and the TLS flags are environment variables). ## `garage`: the decision and why `garage` ships `ingress.enabled: false`, so by default it publishes nothing in **either** mode — correct and unchanged. Two consequences: - **Its fixture keeps the Ingress on, and the route gets a render overlay.** `ci/garage/test-values.yaml` sets `ingress.enabled: true` deliberately, so the install-test proves the Service port it references **by name** (`s3`) exists. An HTTPRoute cannot make that reference — `backendRefs` takes a `PortNumber` — so flipping the fixture to Gateway mode would have traded a check that catches a renamed port for one that does not, *and* given up garage's only Ingress coverage, for a CRD schema `cyberchef`'s fixture already exercises against the real Gateway-API CRDs. Same reasoning applied to the other seven: install-test stays in Ingress mode, the route is held at render level, which is where its two silent failure modes live. - **It is the one chart whose `backendRefs` port is rendered from a value.** `garage.ports.s3` is configurable, so a literal `3900` in the route would be a lie the moment anyone changes it. The route renders the port from the same `garage.settings` helper `garage.service.yaml` uses, so the two cannot drift by construction — and the assertion resolves it: `backendRefs[0] resolves to Service httproute-garage-service:3900`. That the test checks Service **and port** is exactly what makes this provable. ## Verification Run locally, all green: - `ci/helm-dependencies.sh` per chart; `helm lint --strict` ×8 at defaults **and** ×8 with CI values + Gateway overlay — 0 failed in all 16. - `helm package` ×8 — the eight bumped versions build. - `ci/run-httproute-match-test.sh`: **10 charts checked, 20 assertions held, 0 failed, 0 not checked** — up from 4 assertions over 2 charts (`cyberchef`, `template-chart`). Each of the eight contributes "1 parentRef `public/gateway`" + "`backendRefs[0]` resolves to `<release>-<chart>-service:<port>`". - `ci/run-quantity-render-test.sh`: 28 exercised, 0 failed. `ci/run-selector-match-test.sh`: 0 failed. - **88 render/schema assertions** across the eight charts, both directions — 6 rejections each (both modes on, naming both value paths; empty `parentRefs`; no hostname at all; an unknown key under `httpRoute`; a `parentRef` without `name`; a `hostnames` entry of the wrong type) and 5 acceptances each (a valid Gateway config; explicit `hostnames`; an extra `ParentReference` field upstream may add, proving the definition stays open; `httpRoute:` erased to YAML null rendering no route, #99; chart defaults rendering no route). - `NOTES.txt` rendered in **all three modes for all eight charts** (24 renders, 0 failures) — worth doing explicitly, because CI renders NOTES only through the install-test, whose fixtures stay in Ingress mode, so the Gateway branch is reached by no pipeline stage for these charts. ### Not verified, and not claimed - **That traffic flows.** No Gateway controller runs in CI and none will. Green means a schema-valid object and a `Ready` pod, not that the route routes. - **No runtime check of any kind was run locally**: no k3d, no Docker, no Trivy, no cluster. The install-test and `trivy config` results in this PR are whatever the pipeline produces. - `helm install --dry-run` could not be used for the NOTES check — this workspace's service account may not read `httproutes` — so NOTES were rendered offline by copying each chart's `NOTES.txt` into a throwaway template. That proves the template compiles and every branch evaluates; it says nothing about a cluster. ## Scope and what stays open Untouched, as scoped: `rss-bridge` (frozen for changes, #51), group 2 (`calibre-web-automated`, `outline`, `paperless-ngx`, `zipline`, `freesailarr`), group 3 (`homeassistant`, `keycloak`, `bulwark`, `matrix-synapse`, `stalwart`, `ytdlp-web-player`). **Keyword is `Part of #114`, not `Fixes`.** Twelve charts remain plus `rss-bridge` — and #114 **cannot be closed while #51 is open**, because `rss-bridge` renders an Ingress and is frozen, so the sweep cannot reach completion by working through the groups alone. Whoever lands the last group should expect to leave #114 open and say why. Wiki: the eight chart pages, `Lessons-Learned` (the `ingress.enabled`-derived-value class, which groups 2 and 3 will meet again). No new `Charts` row and no `_Sidebar` entry — the charts already exist. `Chart-Style-Guide` §4 unchanged: the convention was not altered, only applied. Part of #114
jlab-bot added 1 commit 2026-10-12 18:08:46 +02:00
feat: Gateway-API as an alternative to the Ingress in eight charts
Validate Helm Charts / Detect changed charts (pull_request) Successful in 5s
Validate Helm Charts / Resource quantities (pull_request) Successful in 15s
Validate Helm Charts / Selector match (pull_request) Successful in 14s
Validate Helm Charts / Build bentopdf (pull_request) Successful in 9s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 17s
Validate Helm Charts / Trivy config bentopdf (pull_request) Successful in 19s
Validate Helm Charts / Build garage (pull_request) Successful in 8s
Validate Helm Charts / Build patchmon (pull_request) Successful in 7s
Validate Helm Charts / Build rallly (pull_request) Successful in 7s
Validate Helm Charts / Build searxng (pull_request) Successful in 6s
Validate Helm Charts / Build sure (pull_request) Successful in 7s
Validate Helm Charts / Build urlaubsverwaltung (pull_request) Successful in 6s
Validate Helm Charts / Trivy config garage (pull_request) Successful in 18s
Validate Helm Charts / Build voucher-vault (pull_request) Successful in 7s
Validate Helm Charts / Trivy config patchmon (pull_request) Successful in 16s
Validate Helm Charts / Trivy config rallly (pull_request) Successful in 18s
Install-test / Install-test bentopdf (pull_request) Successful in 1m10s
Validate Helm Charts / Trivy config searxng (pull_request) Successful in 22s
Validate Helm Charts / Trivy config sure (pull_request) Successful in 18s
Validate Helm Charts / Trivy config urlaubsverwaltung (pull_request) Successful in 17s
Validate Helm Charts / Trivy config voucher-vault (pull_request) Successful in 19s
Install-test / Install-test garage (pull_request) Successful in 1m17s
Install-test / Install-test patchmon (pull_request) Successful in 1m24s
Install-test / Install-test rallly (pull_request) Successful in 1m39s
Install-test / Install-test searxng (pull_request) Successful in 1m7s
Install-test / Install-test sure (pull_request) Successful in 2m39s
Install-test / Install-test voucher-vault (pull_request) Successful in 2m9s
Validate Helm Charts / Install-test (pull_request) Successful in 13m15s
Install-test / Install-test urlaubsverwaltung (pull_request) Successful in 1m50s
Publish BentoPDF Helm Chart / Publish BentoPDF Helm Chart (push) Successful in 10s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 9s
Publish Garage Helm Chart / Publish Garage Helm Chart (push) Successful in 9s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 9s
Publish Rallly Helm Chart / Publish Rallly Helm Chart (push) Successful in 10s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 10s
Publish SearXNG Helm Chart / Publish SearXNG Helm Chart (push) Successful in 10s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 9s
Publish Sure Helm Chart / Publish Sure Helm Chart (push) Successful in 10s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 10s
Publish Urlaubsverwaltung Helm Chart / Publish Urlaubsverwaltung Helm Chart (push) Successful in 10s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 10s
Publish Patchmon Helm Chart / Publish Patchmon Helm Chart (push) Successful in 9s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 10s
Publish VoucherVault Helm Chart / Publish VoucherVault Helm Chart (push) Successful in 10s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 10s
SonarQube Analysis / SonarQube Analysis (push) Successful in 43s
33d7cedbab
Group 1 of the #114 sweep: the charts that render exactly one Ingress object
and set no behaviour-bearing nginx annotation - bentopdf, garage, patchmon,
rallly, searxng, sure, urlaubsverwaltung, voucher-vault.

Each gets the form the pilot (cyberchef, PR #115) fixed and template-chart
carries: an httpRoute block (enabled/parentRefs/hostnames, off by default), a
template rendering ONLY an HTTPRoute with parentRefs - no Gateway, no
gatewayClassName, no Certificate, no implementation-specific policy object -
render aborts on both modes at once (naming both value paths), on an empty
parentRefs and on a missing hostname, empty hostnames meaning [ingress.domain],
a schema entry closed against unknown keys with an open parentRef definition,
and a NOTES.txt that names the active mode and what the mode costs.

Minor, additive, defaults unchanged: `helm template` with each chart's CI
values is byte-identical to origin/main for seven of the eight, and for sure
identical in every rendered value (the diff is two YAML comment lines).

Three findings that were not in the plan, each argued in the file it changes:

  sure derived RAILS_ASSUME_SSL/RAILS_FORCE_SSL from ingress.enabled alone.
  Gateway mode sets that false by construction while TLS is still terminated at
  the Gateway, so both flags would have gone false: insecure cookies, no HSTS,
  http:// links, with a Ready pod and a working UI as the only symptom. They now
  read sure.publishedOverTls (ingress.enabled OR httpRoute.enabled), which is
  ingress.enabled while httpRoute.enabled is false - hence still Minor.

  garage claimed, in its Ingress template and its schema, that nothing outside
  that template reads ingress.domain. The HTTPRoute reads it, so the claim now
  holds only while both modes are off. Corrected rather than left standing.

  garage also depends on an upload limit it does not set: its annotations
  comment tells the operator to set proxy-body-size: "0" because ingress-nginx
  truncates S3 uploads at 1 MB. proxy-body-size has no Gateway-API counterpart,
  so its Gateway-mode NOTES prints that the limit is the Gateway's. README's
  list of affected charts named five and now names garage as a sixth.

clusterIssuer needed no change in any of the eight: its only required() sits
inside the Ingress template behind ingress.enabled, the same no-op the pilot
found. Annotation guidance that stops applying in Gateway mode moved into the
Gateway branch of NOTES.txt for bentopdf (X-Robots-Tag) and searxng
(forward-auth).

CI: one render overlay per chart under ci/httproute/, so the assertion is not
vacuum-green - ci/run-httproute-match-test.sh goes from 4 held assertions over
2 charts to 20 over 10. The install-test fixtures stay in Ingress mode: the
install runs one configuration per chart, cyberchef already pays that price
against the real Gateway-API CRDs, and for garage the Ingress is the only place
its Service port is referenced by NAME.

Not proven, by construction: that traffic flows. No Gateway controller runs in
CI. Not run locally either: k3d, Docker, Trivy.

Part of #114
jklein approved these changes 2026-10-12 19:46:11 +02:00
jklein merged commit 33d7cedbab into main 2026-10-12 19:46:15 +02:00
jklein deleted branch feat/gateway-api-group-1 2026-10-12 19:46:16 +02:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jlab-cluster/helm-charts#116