From 2a65654962f9875767052e182cd313a7c92ea4c9 Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Tue, 20 Oct 2026 08:52:38 -0400 Subject: [PATCH] e2e: retry a refused ingress handshake that ends without the router's alert TestIngressAuthentication proves a refusal by the router's TLS alert. The router closes the connection right after sending it, and the port-forward or Go's HTTP/2 client sometimes reports that close first, as "http2: client conn could not be established", so the test failed with the refusal unproven. A failure without an alert is now retried on a fresh port-forward, three times at most; an alert is still required to pass. --- .../suites/ingressauth/ingressauth_test.go | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/internal/e2e/suites/ingressauth/ingressauth_test.go b/internal/e2e/suites/ingressauth/ingressauth_test.go index 16509ccc4c..15224938de 100644 --- a/internal/e2e/suites/ingressauth/ingressauth_test.go +++ b/internal/e2e/suites/ingressauth/ingressauth_test.go @@ -185,6 +185,12 @@ func isRemoteTLSAlert(err error) bool { return errors.As(err, &opErr) && opErr.Op == "remote error" } +// refusalAttempts bounds the tries one refused client gets, each on a fresh +// port-forward. The router closes right after its alert, and the port-forward +// or Go's HTTP/2 client sometimes reports that close first ("http2: client +// conn could not be established"), so the alert never reaches the test. +const refusalAttempts = 3 + // TestIngressAuthentication checks each kind of client against both TLS // listeners. // @@ -192,7 +198,9 @@ func isRemoteTLSAlert(err error) bool { // shown to carry the allowlisted client through: a port-forward tears down its // whole tunnel once one forwarded connection fails, so a shared one would turn // every check after the first refusal into a dial error. The refusal itself -// has to be a TLS alert from the router, which a broken tunnel cannot fake. +// has to be a TLS alert from the router, which a broken tunnel cannot fake; a +// failure without one is retried on a fresh port-forward, refusalAttempts +// times at most. func TestIngressAuthentication(t *testing.T) { requireStaticMTLS(t) ctx := context.Background() @@ -212,22 +220,28 @@ func TestIngressAuthentication(t *testing.T) { {name: "allowlisted SPIFFE ID signed by an untrusted CA", cert: &foreign}, } { t.Run(tc.name, func(t *testing.T) { - address := forwardRouterPort(t, ctx, listener.servicePort) + for attempt := 1; ; attempt++ { + address := forwardRouterPort(t, ctx, listener.servicePort) - status, err := listener.request(ctx, address, routerTLSConfig(t, ctx, &allowed)) - if err != nil { - t.Fatalf("allowlisted client %s got no response: %v", e2e.RouterClientSPIFFEID(e2e.RouterClientServiceAccount), err) - } - t.Logf("allowlisted client let through (status %d)", status) + status, err := listener.request(ctx, address, routerTLSConfig(t, ctx, &allowed)) + if err != nil { + t.Fatalf("allowlisted client %s got no response: %v", e2e.RouterClientSPIFFEID(e2e.RouterClientServiceAccount), err) + } + t.Logf("allowlisted client let through (status %d)", status) - status, err = listener.request(ctx, address, routerTLSConfig(t, ctx, tc.cert)) - if err == nil { - t.Fatalf("router let the client through (status %d); want the TLS handshake refused", status) - } - if !isRemoteTLSAlert(err) { - t.Fatalf("request failed without a TLS alert from the router, so the refusal is unproven: %v", err) + status, err = listener.request(ctx, address, routerTLSConfig(t, ctx, tc.cert)) + if err == nil { + t.Fatalf("router let the client through (status %d); want the TLS handshake refused", status) + } + if isRemoteTLSAlert(err) { + t.Logf("refused: %v", err) + return + } + if attempt == refusalAttempts { + t.Fatalf("request failed without a TLS alert from the router %d times, so the refusal is unproven: %v", attempt, err) + } + t.Logf("attempt %d failed without a TLS alert from the router; retrying on a fresh port-forward: %v", attempt, err) } - t.Logf("refused: %v", err) }) } })