Gateway API conformance — re-run rev2 (2026-06-25)¶
A second run of the upstream Kubernetes Gateway API conformance suite
(sigs.k8s.io/gateway-api/conformance @ v1.5.1) against talos-main, now
at aether 0.43.0 (rev 70). This re-run measures the delta from the
2026-06-25 baseline after three changes landed:
- (a) Namespace-agnostic edge Gateway reconcile + status — the edge
controller now caches/lists Gateways and Routes cluster-wide and publishes
Accepted/Programmed(and per-listenerattachedRoutes,ResolvedRefs) for class-aetherGateways in any namespace (#323). - (b)
GatewayClass.status.supportedFeaturesis now advertised, so the suite self-configures (skips unimplemented features instead of failing). - (c) HTTPRoute
RequestHeaderModifier/ResponseHeaderModifier+RequestRedirect+URLRewritefilters (#319, #322).
Aether was not modified or redeployed for this run. All
gateway-conformance-* namespaces were cleaned up afterward (verified removed).
TL;DR¶
| Profile | Setup | Tests run | PASS | FAIL | SKIP (by feature) | Verdict |
|---|---|---|---|---|---|---|
| GATEWAY-HTTP (north-south) | PASSED ✅ | 37 | 6 | 31 | 31 | The big unlock: NamespacesMustBeReady now passes — every class-aether Gateway in gateway-conformance-infra reaches Accepted=True + Programmed=True, so the suite enumerates and runs the whole profile for the first time. The 6 passes are all status-only tests. Every test that needs live traffic through a Gateway fails on the missing per-Gateway address. |
| MESH-HTTP (east-west / GAMMA) | passed | 7 | 4 | 3 | 0 | Unchanged from baseline. The redirect/header-modifier filters that now ship at the route level are not applied on the GAMMA transparent-capture path, so the same two filter tests still fail. |
Headline delta: GATEWAY-HTTP went from 0 tests run (aborted in Setup) → 37 tests run, 6 PASS / 31 FAIL. MESH-HTTP is flat at 4/3 — the shipped filters did not move the mesh number.
How it was run¶
Same programmatic runner approach as the baseline: a standalone Go test
(conformance/aether_rev2_test.go, not committed — a one-off diagnostic in a
checkout of gateway-api v1.5.1, which wires the replace
sigs.k8s.io/gateway-api => ../ for the nested conformance module) drives
suite.NewConformanceTestSuite directly:
GatewayClassName: "aether", controllergateway.aether.io/edge.ManifestFS: conformance.Manifests(required when calling the suite programmatically — only the CLI wires the embedded base/mesh manifest FS).AllowCRDsMismatch: true— talos-main carries standard and experimental Gateway API CRDs (aether's L4 routes); benign for these two profiles.- GATEWAY-HTTP: supported features inferred from
GatewayClass.status.supportedFeatures(the rev2 unlock —SupportedFeatures/ExemptFeaturesleft empty,EnableAllSupportedFeatures=false). The suite read the advertised set{Gateway, GatewayPort8080, HTTPRoute, GRPCRoute, HTTPRouteMethodMatching, HTTPRouteRequestTimeout, HTTPRouteResponseHeaderModification}and the GATEWAY-HTTP profile injected its mandatoryReferenceGranton top — so the effective set the suite tested was those 7 plusReferenceGrant. Everything else was skipped cleanly (not failed) — confirming (b) works as intended. - MESH-HTTP: mesh support cannot be inferred from a GatewayClass, so
{Mesh, HTTPRoute, HTTPRouteResponseHeaderModification, HTTPRouteMethodMatching, HTTPRouteRequestTimeout}were advertised explicitly (as the baseline did). - For GATEWAY-HTTP the per-Gateway address / traffic budgets
(
GatewayMustHaveAddress,MaxTimeToConsistency,RequestTimeout) were shortened so the many address-dependent tests fail fast rather than each burning the full 5-minute default (this only changes how quickly a doomed test gives up; it does not change pass/fail).
DELTA vs baseline¶
| Baseline (0.42.0, rev 68) | rev2 (0.43.0, rev 70) | Delta | |
|---|---|---|---|
| GATEWAY-HTTP Setup | ❌ blocked in Setup (Gateways never got status → NamespacesMustBeReady timed out) |
✅ passes (all 4 infra Gateways Accepted+Programmed) |
Unblocked |
| GATEWAY-HTTP tests run | 0 | 37 | +37 |
| GATEWAY-HTTP PASS | 0 | 6 | +6 |
| GATEWAY-HTTP FAIL | 0 | 31 (Core 28, Extended 3) | +31 (now visible) |
GatewayClass supportedFeatures |
absent (features passed manually) | advertised; suite inferred + skipped cleanly | Works |
| MESH-HTTP PASS / FAIL | 4 / 3 | 4 / 3 | 0 (no change) |
MESH RequestHeaderModifier |
FAIL | FAIL | unchanged |
MESH RedirectHostAndStatus |
FAIL | FAIL | unchanged |
MESH Weight |
FAIL | FAIL | unchanged |
The expectation going in was that the two filter-gap mesh tests would now PASS (filters shipped). They did not — see below.
MESH-HTTP — still 4 PASS / 3 FAIL (filters don't reach the capture path)¶
Profile report: pass=4 fail=3 skip=0.
PASS (4): MeshBasic, MeshHTTPRouteSimpleSameNamespace,
MeshHTTPRouteMatching, MeshTrafficSplit.
FAIL (3): MeshHTTPRouteRequestHeaderModifier,
MeshHTTPRouteRedirectHostAndStatus, MeshHTTPRouteWeight.
The important finding: the RequestHeaderModifier and redirect filters did
ship (#319/#322) and are advertised — but they are applied on the edge /
route-level HTTPRoute path, not on the GAMMA transparent-capture path that
the MESH profile exercises. The conformance signal is unambiguous:
MeshHTTPRouteRedirectHostAndStatus:
wanted status code to be one of [302], got 200
i.e. the request still reaches the backend (200) instead of being turned into a
3xx redirect — identical to the baseline behavior. The header-modifier subtests
likewise time out waiting for the modified header that never arrives. MeshWeight
remains a stricter weighted-distribution assertion that doesn't converge on the
capture path (MeshTrafficSplit, the looser split test, still passes).
Conclusion: filter translation needs to be wired into the mesh/capture route generation, not only the edge. This is the single biggest remaining blocker for MESH-HTTP.
GATEWAY-HTTP — now runs: 6 PASS / 31 FAIL¶
Profile report: Core pass=5 fail=28, Extended pass=1 fail=3 → 6 PASS / 31
FAIL / 0 skip-in-profile (31 further tests skipped by unadvertised feature —
by design).
The 6 PASS — all status / reconcile, zero traffic¶
| Test | What it proves |
|---|---|
GatewayModifyListeners |
Listener add/remove re-reconciles + status updates. |
GatewayObservedGenerationBump |
Gateway status observedGeneration tracks spec. |
GatewayWithAttachedRoutesWithPort8080 |
attachedRoutes count + ResolvedRefs for a port-8080 listener. |
HTTPRouteObservedGenerationBump |
HTTPRoute status observedGeneration tracks spec. |
GatewaySecretReferenceGrantAllInNamespace |
Gateway TLS secret accepted via an all-in-namespace ReferenceGrant. |
GatewaySecretReferenceGrantSpecific |
…and via a specifically-named grant. |
Every one of these asserts status conditions only — exactly the surface (a)+(b) unlocked. No request is ever sent through the Gateway.
The 31 FAIL — three buckets¶
1. Missing per-Gateway address → no live traffic (the dominant bucket).
The edge is still one Deployment on one LoadBalancer (192.168.100.101) with
no per-Gateway address allocation: every conformance Gateway is
Programmed=True but its .status.addresses is empty. The suite's traffic
tests call WaitForGatewayAddress first and fail with:
error waiting for Gateway to have at least one IP address in status
This fails ~17 Core tests that need to route a request through a specific
Gateway: HTTPRouteSimpleSameNamespace, HTTPRouteMatching,
HTTPRouteMatchingAcrossRoutes, HTTPRouteHeaderMatching,
HTTPRouteExactPathMatching, HTTPRoutePathMatchOrder,
HTTPRouteListenerHostnameMatching, HTTPRouteHostnameIntersection,
HTTPRouteHTTPSListener, HTTPRouteWeight, HTTPRouteServiceTypes,
HTTPRouteRedirectHostAndStatus, HTTPRouteRequestHeaderModifier,
HTTPRouteInvalidNonExistentBackendRef, HTTPRouteInvalidBackendRefUnknownKind,
HTTPRouteInvalidParentRefNotMatchingSectionName, plus the Extended trio
HTTPRouteMethodMatching, HTTPRouteResponseHeaderModifier,
HTTPRouteTimeoutRequest. This confirms the #1-agent finding precisely:
status/setup passes, but the single shared edge address with no per-Gateway
allocation means every live-traffic test fails at the address step.
2. ReferenceGrant / cross-namespace enforcement not in the routing model
(~8 tests). GatewaySecretInvalidReferenceGrant,
GatewaySecretMissingReferenceGrant, HTTPRouteCrossNamespace,
HTTPRouteInvalidCrossNamespaceBackendRef,
HTTPRouteInvalidCrossNamespaceParentRef, HTTPRouteInvalidReferenceGrant,
HTTPRoutePartiallyInvalidViaInvalidReferenceGrant, HTTPRouteReferenceGrant.
Aether's data-plane cluster name is namespace-free (<svc>.<meshDomain>), so
cross-namespace backendRef enforcement (allow with a grant, reject without
one) is not modeled. Note the two positive secret-grant tests (specific +
all-in-namespace) do pass — aether honors a present grant for a TLS secret;
it's the negative/enforcement and cross-namespace-backend cases that fail.
3. Status edge-cases (~3 tests). GatewayClassObservedGenerationBump
(observedGeneration should increment — the GatewayClass status generation isn't
bumped on spec change), and GatewayInvalidRouteKind (listener ResolvedRefs
must go False with reason InvalidRouteKinds and surface the supported kinds —
not produced correctly). GatewayInvalidTLSConfiguration also fails here
(invalid-cert listener status expectations).
Inferred-features confirmation¶
The suite logged:
Supported features for GatewayClass aether: [ReferenceGrant GRPCRoute Gateway
GatewayPort8080 HTTPRoute HTTPRouteMethodMatching HTTPRouteRequestTimeout
HTTPRouteResponseHeaderModification]
ReferenceGrant is the GATEWAY-HTTP profile's mandatory feature, auto-added on
top of the 7 aether advertises. All other features (redirect status codes,
rewrite, mirror, CORS, backend-protocol, static addresses, listener-sets,
BackendTLSPolicy, client-cert, …) were skipped, not failed — (b) working.
Prioritized blockers (what to do next)¶
| Priority | Blocker | Profile | Impact |
|---|---|---|---|
| P0 (GW) | Per-Gateway address allocation. One edge Deployment / one LB (192.168.100.101) with no per-Gateway .status.addresses. |
GATEWAY-HTTP | Converts the single largest bucket (~17 Core + 3 Extended traffic tests) from FAIL toward PASS. Needs either per-Gateway LB addresses or a shared-address/host-multiplexing model the suite tolerates (publish a reachable address in .status.addresses and route by host). |
| P0 (Mesh) | Apply HTTPRoute filters on the GAMMA / transparent-capture path. Redirect + request/response header-modifier translate at the edge but not on capture. | MESH-HTTP | Converts MeshHTTPRouteRequestHeaderModifier + MeshHTTPRouteRedirectHostAndStatus from FAIL to PASS (~6/7 target). |
| P1 | ReferenceGrant cross-namespace enforcement (reject cross-ns backendRef without a grant; honor with one). |
GATEWAY-HTTP | ~8 Core tests; mandatory feature of the profile. |
| P2 | RequestMirror filter (advertised as Planned). |
both | Unlocks HTTPRouteRequestMirror* (currently skipped, not failed). |
| P2 | Status edge-cases: GatewayClass observedGeneration bump; listener InvalidRouteKinds ResolvedRefs+supportedKinds; invalid-TLS listener status. |
GATEWAY-HTTP | ~3 Core status tests. |
| P3 | Mesh interception model: tighten weighted distribution on capture (MeshHTTPRouteWeight); decide arbitrary-Service interception vs. aether's generated mesh VIPs. |
MESH-HTTP | Last mesh FAIL after filters land. |
Reproduction¶
Identical to the baseline: a ~130-LOC standalone test in a gateway-api v1.5.1
checkout under conformance/, gated by AETHER_REV2=1, run with GOWORK=off.
Two subtests: TestAetherRev2Mesh (explicit mesh features) and
TestAetherRev2Gateway (features inferred from
GatewayClass.status.supportedFeatures). Non-obvious requirements when driving
the suite programmatically: set ManifestFS = conformance.Manifests, set
AllowCRDsMismatch on the mixed-channel cluster, and — for the inference path —
leave SupportedFeatures/ExemptFeatures empty with
EnableAllSupportedFeatures=false so the suite reads the GatewayClass status.