| name | gateway-api |
| description | Compatibility notes for Edgion's Gateway API handling, including intentional deviations and not-implemented features. |
Gateway API Compatibility Notes
Use this note when changing Gateway API behavior in Edgion and you need to understand intentional compatibility boundaries.
File index
| File | Content |
|---|
| 01-not-implemented.md | Gateway API features not implemented or postponed: addresses reporting, cross-type Hostname conflict detection, infrastructure, ListenerSet, HTTPRouteRequestMultipleMirrors, GatewayFrontendClientCertificateValidation (status OK, enforcement not conformant), BackendTrafficPolicy, TLSRouteModeMixed, TLS profile; completed items: BackendTLSPolicy incl. SANValidation ✅. The authoritative declared/skipped feature lists are the SUPPORTED_FEATURES / UNSUPPORTED_OR_SKIPPED_FEATURES constants in edgion-resources/src/resources/gateway_class.rs (this file only records rationale). |
| 02-conformance-testing.md | How to run, debug, and incrementally validate Gateway API conformance tests: script usage, granularity control, port-forward, debugging tips |
| 03-conformance-workflow.md | Cross-session workflow: drive conformance tests one item at a time (environment check → feature analysis → run → diagnose → record) |
| 05-batch-conformance-debugging.md | Log collection, timeline correlation, and root-cause localization for batch conformance failures (Batch 7 specific) |
| 06-conformance-debug-cookbook.md | Conformance troubleshooting cookbook: pre-flight checks, common failure modes (namespace deleted, ports not bound, stale processes, etc.), efficient run tips |
Latest conformance results (feature-04-06, 2026-04-07)
ALL PASS (in-cluster mode, split-profile run)
Profile declaration status
| Profile | Declared | Result |
|---|
GATEWAY-HTTP | ✅ | Core 33/33, Extended 32/32 — FULL PASS |
GATEWAY-GRPC | ✅ | Core 13/13 — FULL PASS |
GATEWAY-TLS | ✅ | Core 18/18, Extended 3/3 — FULL PASS |
MESH-* | ❌ | Not applicable (Edgion is not a service mesh) |
How to run
HTTP/GRPC and TLS must be run separately (port 443 conflict; see cookbook 2.3.1):
./scripts/in-cluster-runner.sh --clean-slate \
--conformance-profiles "GATEWAY-HTTP,GATEWAY-GRPC" --timeout 30m
./scripts/in-cluster-runner.sh --clean-slate \
--conformance-profiles "GATEWAY-TLS" --timeout 30m
Reports: edgion-tests/conformance/reports/
Issues fixed in this round
| Issue | Root cause | Fix |
|---|
| Controller periodically restarting (~27s) | tokio::time::timeout(25s) started timing from boot | tokio::select! — timing starts only after a signal |
| TLS cert x509 CA:FALSE | upstream conformance suite self-signed cert lacked IsCA:true | Verified that v1.5.1 tests don't trigger this path; no patch needed |
| Stale TLS-backend cert cache | Pod did not reload after Secret recreation | --clean-slate automatically rolls out the TLS backend |
Configuration location: edgion-tests/conformance/conformance_test.go (opts.ConformanceProfiles)
TLS Certificate Selection
Edgion intentionally does not support cross-port TLS certificate fallback, but does
support catch-all (no hostname) listener certificate selection as a per-listener fallback.
What Edgion does
- TLS certificate selection must match the current listener port.
- Lookup priority per port: exact hostname > wildcard hostname > catch-all (no hostname) listener.
- A listener without
hostname serves as the catch-all fallback for its port — its certificate is used when no hostname-specific listener matches the SNI.
- Only the first catch-all listener per port is kept; duplicates are logged as warnings.
- If no match exists (no hostname-specific and no catch-all), certificate selection fails.
- Explicit
fallback_sni remains an Edgion-specific override for clients that send no SNI at all.
What Edgion does not do
- No search across all listener ports for a usable certificate
- No implicit fallback from one listener's certificate to another listener on a different port
Why catch-all TLS matching is limited to per-listener scope
Gateway API allows a Listener without hostname, meaning the listener matches all hostnames
at the routing level. Edgion honors this by using the catch-all listener's certificate as a
per-listener fallback when no hostname-specific listener matches the SNI. The certificate may not
be valid for every SNI, but this matches Gateway API conformance expectations — the catch-all
listener is the correct fallback within its listener scope.
Why cross-listener fallback is not supported
Gateway listeners are listener-scoped (keyed by ListenerKey = "{addr}/{protocol}"). Allowing a fallback that ignores the listener key breaks listener isolation and can select the wrong certificate when the same hostname is configured differently on multiple listeners.
Edgion treats (ListenerKey, sni) as the required lookup key for Gateway TLS.
EdgionTls binding rule
For EdgionTls, controller-side listener resolution is required before the resource can enter the matcher.
- If parent refs resolve to listener keys (
ListenerKey), the TLS resource is admitted into the matcher.
- If no listener key is resolved, the TLS resource is skipped from the matcher.
- This state should be reflected in status instead of being hidden behind a global fallback.
parentRef Resolution: both-absent Fallback
Per Gateway API spec, when a parentRef specifies neither port nor
sectionName, the resource MUST attach to all listeners of the referenced
Gateway. This applies to:
TLSRoute (port resolution in tls_route.rs)
EdgionTls (port resolution in edgion_tls.rs)
HTTPRoute / GRPCRoute (hostname resolution in hostname_resolution.rs)
Bug history (2026-03): The original implementation only handled port set
or sectionName set, missing the both-absent fallback. This caused TLSRoute
and EdgionTls to silently get resolved_listeners = None (now Vec<ListenerKey>)
when parentRef had only name + namespace.
Test coverage: TLSRoute/BothAbsentParentRef and
EdgionTls/BothAbsentParentRef integration tests verify this behavior.
EdgionTls Requeue via gateway_route_index
EdgionTls must register in gateway_route_index via its on_change() method.
Without this, when a Gateway is added or its listeners change, EdgionTls would
not be requeued to re-resolve its listener ports.
Bug history (2026-03): EdgionTls originally had no on_change() at all.
If EdgionTls was processed before its Gateway during init, resolved_listeners
would permanently be empty with no requeue mechanism. Fixed by adding
on_change() with update_gateway_route_index() and on_delete() with
remove_from_gateway_route_index().
Rule: Any handler that calls lookup_gateway() in parse() MUST register
in gateway_route_index via on_change() so that Gateway changes trigger
requeue. Currently this applies to: TLSRoute, EdgionTls, HTTPRoute, GRPCRoute,
TCPRoute, UDPRoute.
Implementation guidance
When editing TLS matching:
- keep
EdgionTls matching listener-scoped (keyed by ListenerKey)
- keep Gateway TLS matching listener-scoped
- catch-all (no hostname) listeners are valid per-listener fallbacks — do not remove this support
- do not reintroduce cross-listener fallback lookup
- prefer explicit status/reporting over implicit matcher fallback