diff --git a/CI-CD.md b/CI-CD.md index b5b7597..ccfd7d1 100644 --- a/CI-CD.md +++ b/CI-CD.md @@ -141,7 +141,9 @@ The third job that ignores the changed-chart matrix, and for the same reason as **The real Gateway-API CRDs in the install-test close none of these gaps**, which is the whole reason this job exists next to them: the Gateway-API schema accepts an empty `parentRefs` list, a `backendRefs` entry pointing at a Service that was never created, and a prefix-stripping rewrite with no redirect beside it. The CRDs prove the object is *well-formed*; this test proves it *points somewhere*, and *somewhere right*. -The third finding is a **pairing within one `HTTPRoute` object**, and the scope is deliberate: Gateway-API matching precedence is a property of a single route, so a redirect in a *different* route — a different hostname — says nothing about this one. Precedence also makes it a question of existence rather than of order, because an `Exact` path match outranks every prefix match: the redirect rule wins wherever it is emitted, and a chart's rule ordering stays a rendering convention. [freesailarr](freesailarr) is the first chart it applies to; [bulwark](bulwark), the second `rewrite-target` chart, meets the same check when group 3 of the sweep lands — which is why the rule lives in the harness and not in one chart's template. +The third finding is a **pairing within one `HTTPRoute` object**, and the scope is deliberate: Gateway-API matching precedence is a property of a single route, so a redirect in a *different* route — a different hostname — says nothing about this one. Precedence also makes it a question of existence rather than of order, because an `Exact` path match outranks every prefix match: the redirect rule wins wherever it is emitted, and a chart's rule ordering stays a rendering convention. + +[freesailarr](freesailarr) is the first chart it applies to — **and, after group 3, still the only one.** The line that used to stand here said [bulwark](bulwark) was the second `rewrite-target` chart and would meet the same check when group 3 landed. Group 3 landed and it does not: **bulwark has one Ingress object, no `rewrite-target`, and cannot have one** — `NEXT_PUBLIC_BASE_PATH` is compiled into its bundle, so it cannot be served under a sub-path and its route is one rule at `/` with no `URLRewrite` filter. Every occurrence of the string `rewrite-target` in that chart is an explanation of *why it does not help*, and #114's measured table arrived at "bulwark, freesailarr" by grepping for the string rather than for the annotation. **The script's own header carried the same claim and was corrected in the same round.** The check still runs over every chart for the reason it always did — the mistake arrives by copy into a chart whose own diff nobody reads for it — not because a second chart is known to need it. The port half is a genuinely new exposure rather than a hypothetical. An Ingress backend references its Service port **by name**; `backendRefs` takes a `PortNumber` and cannot. So from now on the number in the route and the port in the Service are kept in step by hand, and this test is what holds that pair. @@ -151,9 +153,14 @@ Three things to know before touching it: - **What is deliberately not checked.** *That traffic flows* — no Gateway controller runs in CI and none will, so `Accepted: True` is not obtainable and that claim is made nowhere in this pipeline. *That any redirect is ever served* — the pairing check proves the rendered **object** carries a `RequestRedirect` rule on the bare prefix and nothing beyond that: whether an implementation honours the `statusCode` or declines it and fails the whole route is outside what a render can see. *Mutual exclusion with the Ingress* — each chart aborts its own render when `ingress.enabled` and `httpRoute.enabled` are both true, which is where it belongs: this test renders one configuration per chart and a rule here would have to assume the switch is chart-global, which may not survive the multi-app charts of the sweep. *Cross-namespace and non-Service backends*, and a rule carrying no `backendRefs` at all (legal for a filter-only rule such as a redirect) — all three are **reported as "not checked", never counted as passing**. Note that the two interact honestly: the redirect rule the pairing check demands is itself backend-less, so a chart that satisfies the check also earns one "not checked" line, and both verdicts are correct at once. - **Two anti-vacuum guards**, because the convention ships `httpRoute.enabled: false` and this test would otherwise be green over nothing. `ci/httproute/.yaml` is a render-only overlay applied **last** whose one job is to put a chart into Gateway mode — and a chart that *has* one and still renders no route **fails**. On top of that, a run in which **no assertion at all** held fails. `cyberchef` is exercised through its ordinary install-test fixture (which installs in Gateway mode); every other converted chart through its overlay. - **For a multi-app chart the overlay has a second job**: it must enter **every** shape the template has, or the branch nobody exercised is the one that breaks. `ci/httproute/freesailarr.yaml` moves one app onto a host of its own on top of the fixture's shared host, so the shared-host route *and* a per-app route both render — and it leaves `mediathekarr` published-off, which exercises the per-app selector in the negative direction as well. It also keeps qBittorrent **on** the shared host, which is what makes the prefix/redirect pairing fire for a real chart rather than cover nothing. +- **And a multi-object overlay has to enter every object**, which group 3 made routine: `ci/httproute/keycloak.yaml` covers the public *and* the admin route (the admin parent falling back to the chart-global one, which is the branch an installation takes), and `ci/httproute/matrix-synapse.yaml` covers the homeserver *and* the delegation route — two hostnames, two paths and two **different** backends, which is the only overlay in the repo where the two `backendRefs` resolve to different Services. +- **One overlay has to *supply* hostnames**, and only one: `ci/httproute/homeassistant.yaml`. That chart has no `ingress.domain`, so its hostnames come from `ingress.hosts`, whose default is the scaffold placeholder — one host with one root path. The overlay therefore sets two entries, the second with **two** paths including an `Exact` one, because that second entry is what proves the chart renders **one object per host entry** rather than one object with several hostnames. For that chart the overlay also **adds** coverage rather than trading it: `ingress.enabled` defaults to `false` there and the fixture does not switch it on, so the install-test had never exercised a routing object at all. Same situation as [garage](garage). +- **A render-*failure* path cannot live here**, and two of group 3's guards are exactly that. This test only runs renders it expects to succeed, so homeassistant's `pathType: ImplementationSpecific` abort on a non-root path, and ytdlp-web-player's refusal to publish the app and its oauth2-proxy on one host, were exercised by hand instead. Where a guard matters, the chart's page says so and the PR records the exercise — a check that would have to assert a failing render belongs in the chart's own `fail`, not here. - **What the overlays do *not* cover is the text of `NOTES.txt`.** The Gateway branch of a chart's notes is *executed* by this test (a template error in it fails the job — verified by breaking one on purpose), but `helm template` does not print notes and the install-test installs in Ingress mode. So the notes' Gateway wording is reviewed by reading, never by a check. -Measured in CI (run 719, the pilot): **30 charts, 4 assertions held**, whole job 13 s including checkout and the Helm setup, no cluster. Group 1 of the sweep took that to 20 assertions over 10 charts and group 2 to 36 over 15 — the sweep adds charts, not checks. The prefix/redirect pairing of Gitea #118 is the first *check* added since the pilot rather than a chart, which brings it to **37 over 15**: one assertion for freesailarr's `/qbittorrent`, plus one further "not checked" line for the backend-less redirect rule it demands. The fail path was exercised rather than assumed: a Service renamed in the route, a port the Service does not expose, a port left out entirely, an emptied `parentRefs` with the chart's own guard disabled, an overlay that renders no route, a run with zero assertions, and — for the pairing — both the redirect rule deleted outright and the redirect pointed at a path other than the one stripped; each produced a `FAIL` naming both sides and a non-zero exit. +Measured in CI (run 719, the pilot): **30 charts, 4 assertions held**, whole job 13 s including checkout and the Helm setup, no cluster. Group 1 of the sweep took that to 20 assertions over 10 charts and group 2 to 36 over 15 — the sweep adds charts, not checks. The prefix/redirect pairing of Gitea #118 is the first *check* added since the pilot rather than a chart, which brought it to 37 over 15: one assertion for freesailarr's `/qbittorrent`, plus one further "not checked" line for the backend-less redirect rule it demands. + +**Group 3 takes it to `56` assertions over `21` charts**, which is the sweep finished except for the frozen `rss-bridge`. Its 19 come from six charts, and three of them contribute more than one route: `keycloak` **4** (public + admin), `matrix-synapse` **4** (homeserver + delegation, two different backends), `homeassistant` **5** (two routes, three rules), `bulwark` **2**, `stalwart` **2**, `ytdlp-web-player` **2**. The fail path was exercised rather than assumed: a Service renamed in the route, a port the Service does not expose, a port left out entirely, an emptied `parentRefs` with the chart's own guard disabled, an overlay that renders no route, a run with zero assertions, and — for the pairing — both the redirect rule deleted outright and the redirect pointed at a path other than the one stripped; each produced a `FAIL` naming both sides and a non-zero exit. ### 6. `trivy-config` (reporting only)