TUN-10388: Use pointer for suggested protocol
Check / check (1.22.x, macos-latest) (push) Has been cancelled
Check / check (1.22.x, ubuntu-latest) (push) Has been cancelled
Check / check (1.22.x, windows-latest) (push) Has been cancelled
Semgrep config / semgrep/ci (push) Has been cancelled

Switching `SuggestedProtocol` to a pointer, so we can pass nil whenever both QUIC and HTTP2 fail. We should not be suggesting anything when all our protocols have failed.
This commit is contained in:
Miguel da Costa Martins Marcelino
2026-04-29 13:36:38 +00:00
parent f827e6216b
commit cf17ba93b2
3 changed files with 53 additions and 29 deletions
+24 -7
View File
@@ -110,9 +110,19 @@ func summaryLine(r Report) string {
case r.hasHardFail():
return "SUMMARY: Environment has critical failures. cloudflared may not be able to establish a tunnel."
case r.hasWarn():
return fmt.Sprintf("SUMMARY: Environment ready with degraded transport. cloudflared will proceed using '%s'.", r.SuggestedProtocol)
if r.SuggestedProtocol == nil {
return "SUMMARY: Environment ready with degraded transport."
}
protocol := r.SuggestedProtocol.String()
return fmt.Sprintf("SUMMARY: Environment ready with degraded transport. cloudflared will proceed using '%s'.", protocol)
default:
return fmt.Sprintf("SUMMARY: Environment is healthy. cloudflared will use '%s' as primary protocol.", r.SuggestedProtocol)
if r.SuggestedProtocol == nil {
return "SUMMARY: Environment is healthy."
}
protocol := r.SuggestedProtocol.String()
return fmt.Sprintf("SUMMARY: Environment is healthy. cloudflared will use '%s' as primary protocol.", protocol)
}
}
@@ -210,9 +220,16 @@ func (r Report) LogEvent(logger *zerolog.Logger) {
Msg(logMsgPrecheck)
}
logger.Info().
Str(logFieldRunID, runID).
Bool(logFieldHardFail, r.hasHardFail()).
Str(logFieldSuggestedProtocol, r.SuggestedProtocol.String()).
Msg(logMsgPrecheckComplete)
if r.SuggestedProtocol != nil {
logger.Info().
Str(logFieldRunID, runID).
Bool(logFieldHardFail, r.hasHardFail()).
Str(logFieldSuggestedProtocol, r.SuggestedProtocol.String()).
Msg(logMsgPrecheckComplete)
} else {
logger.Info().
Str(logFieldRunID, runID).
Bool(logFieldHardFail, r.hasHardFail()).
Msg(logMsgPrecheckComplete)
}
}
+26 -20
View File
@@ -23,7 +23,7 @@ var fixedRunID = uuid.MustParse("00000000-0000-0000-0000-000000000001")
func allPassReport() Report {
return Report{
RunID: fixedRunID,
SuggestedProtocol: connection.QUIC,
SuggestedProtocol: new(connection.QUIC),
Results: []CheckResult{
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region1.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region2.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
@@ -39,7 +39,7 @@ func allPassReport() Report {
func quicBlockedReport() Report {
return Report{
RunID: fixedRunID,
SuggestedProtocol: connection.HTTP2,
SuggestedProtocol: new(connection.HTTP2),
Results: []CheckResult{
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region1.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region2.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
@@ -62,7 +62,7 @@ func quicBlockedReport() Report {
func apiFailReport() Report {
return Report{
RunID: fixedRunID,
SuggestedProtocol: connection.QUIC,
SuggestedProtocol: new(connection.QUIC),
Results: []CheckResult{
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region1.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region2.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
@@ -84,7 +84,7 @@ func apiFailReport() Report {
func bothTransportsBlockedReport() Report {
return Report{
RunID: fixedRunID,
SuggestedProtocol: connection.HTTP2,
SuggestedProtocol: nil,
Results: []CheckResult{
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region1.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
{Type: ProbeTypeDNS, Component: "DNS Resolution", Target: "region2.v2.argotunnel.com", ProbeStatus: Pass, Details: "Resolved successfully"},
@@ -112,7 +112,7 @@ func bothTransportsBlockedReport() Report {
func dnsFailReport() Report {
return Report{
RunID: fixedRunID,
SuggestedProtocol: connection.HTTP2,
SuggestedProtocol: nil,
Results: []CheckResult{
{
Type: ProbeTypeDNS,
@@ -218,7 +218,7 @@ func TestString_DNSFail(t *testing.T) {
func TestString_EmptyResults(t *testing.T) {
t.Parallel()
r := Report{RunID: fixedRunID, SuggestedProtocol: connection.QUIC}
r := Report{RunID: fixedRunID, SuggestedProtocol: new(connection.QUIC)}
out := r.String()
// Must not panic and must still emit a valid skeleton.
assert.Contains(t, out, "CONNECTIVITY PRE-CHECKS")
@@ -230,15 +230,15 @@ func TestString_EmptyResults(t *testing.T) {
// logEntry is a helper struct to unmarshal a single JSON log line emitted by LogEvent.
type logEntry struct {
Level string `json:"level"`
RunID string `json:"run_id"`
Component string `json:"component"`
Target string `json:"target"`
Status string `json:"status"`
Details string `json:"details"`
Message string `json:"message"`
HardFail *bool `json:"hard_fail"`
SuggestedProtocol string `json:"suggested_protocol"`
Level string `json:"level"`
RunID string `json:"run_id"`
Component string `json:"component"`
Target string `json:"target"`
Status string `json:"status"`
Details string `json:"details"`
Message string `json:"message"`
HardFail *bool `json:"hard_fail"`
SuggestedProtocol *string `json:"suggested_protocol"`
}
// captureLogLines runs LogEvent against a buffer-backed zerolog logger and
@@ -299,7 +299,8 @@ func TestLogEvent_AllPass(t *testing.T) {
assert.Equal(t, fixedRunID.String(), summary.RunID)
require.NotNil(t, summary.HardFail)
assert.False(t, *summary.HardFail)
assert.Equal(t, "quic", summary.SuggestedProtocol)
require.NotNil(t, summary.SuggestedProtocol)
assert.Equal(t, "quic", *summary.SuggestedProtocol)
}
func TestLogEvent_QuicBlocked(t *testing.T) {
@@ -318,7 +319,8 @@ func TestLogEvent_QuicBlocked(t *testing.T) {
summary := entries[len(entries)-1]
require.NotNil(t, summary.HardFail)
assert.False(t, *summary.HardFail)
assert.Equal(t, "http2", summary.SuggestedProtocol)
require.NotNil(t, summary.SuggestedProtocol)
assert.Equal(t, "http2", *summary.SuggestedProtocol)
assert.Equal(t, fixedRunID.String(), summary.RunID)
}
@@ -342,7 +344,8 @@ func TestLogEvent_APIFail(t *testing.T) {
summary := entries[len(entries)-1]
require.NotNil(t, summary.HardFail)
assert.False(t, *summary.HardFail)
assert.Equal(t, "quic", summary.SuggestedProtocol)
require.NotNil(t, summary.SuggestedProtocol)
assert.Equal(t, "quic", *summary.SuggestedProtocol)
}
func TestLogEvent_BothTransportsBlocked(t *testing.T) {
@@ -359,6 +362,7 @@ func TestLogEvent_BothTransportsBlocked(t *testing.T) {
summary := entries[len(entries)-1]
require.NotNil(t, summary.HardFail)
assert.True(t, *summary.HardFail)
assert.Nil(t, summary.SuggestedProtocol)
}
func TestLogEvent_DNSFail(t *testing.T) {
@@ -381,11 +385,12 @@ func TestLogEvent_DNSFail(t *testing.T) {
summary := entries[len(entries)-1]
require.NotNil(t, summary.HardFail)
assert.True(t, *summary.HardFail)
assert.Nil(t, summary.SuggestedProtocol)
}
func TestLogEvent_EmptyReport(t *testing.T) {
t.Parallel()
r := Report{RunID: fixedRunID, SuggestedProtocol: connection.HTTP2}
r := Report{RunID: fixedRunID, SuggestedProtocol: new(connection.HTTP2)}
entries := captureLogLines(t, r)
// No result lines, only the summary.
@@ -394,7 +399,8 @@ func TestLogEvent_EmptyReport(t *testing.T) {
assert.Equal(t, fixedRunID.String(), entries[0].RunID)
require.NotNil(t, entries[0].HardFail)
assert.False(t, *entries[0].HardFail)
assert.Equal(t, "http2", entries[0].SuggestedProtocol)
require.NotNil(t, entries[0].SuggestedProtocol)
assert.Equal(t, "http2", *entries[0].SuggestedProtocol)
}
// hasHardFail / hasWarn helper tests
+3 -2
View File
@@ -90,8 +90,9 @@ type Report struct {
Results []CheckResult
// SuggestedProtocol is the connection protocol the pre-checks recommend
// based on transport probe results.
SuggestedProtocol connection.Protocol
// based on transport probe results. Nil when no valid protocol is available
// (e.g., when both transports fail or DNS is unresolvable).
SuggestedProtocol *connection.Protocol
}
// Config controls the behavior of a pre-check Run().