Add WebSocket connectivity check to Duo self-hosted setup verification

Problem

When agentic chat (GitLab Duo Agent Platform) fails to connect, the browser only shows a generic "Duo workflow service not reachable" error. The underlying cause is often a failed WebSocket upgrade handshake on the /api/v4/ai/duo_workflows/ws request — for example when a load balancer or reverse proxy (HAProxy, NGINX) in front of GitLab does not forward the Upgrade/Connection headers, or strips authentication.

The browser WebSocket API deliberately hides the HTTP handshake status and body from JavaScript, so a 403 (auth/pre-auth) or a stuck-at-non-101 (proxy not forwarding upgrade headers) is invisible in the UI. The existing self-hosted diagnostics only test the outbound Rails → Duo Workflow Service gRPC path (list_tools), which can pass while the inbound browser → proxy → Workhorse upgrade path fails.

This cost significant debugging time in a recent customer engagement.

Proposal

Add a WebSocket connectivity check to the gitlab:duo:verify_self_hosted_setup rake task. It performs the same WebSocket upgrade handshake the browser makes, against the instance's own external URL (traversing the same inbound proxy chain), and classifies the result:

  • 101 — healthy
  • 401/403 — reached GitLab but unauthorized (license/seat, or proxy stripped auth)
  • other status — upgrade not completed; load balancer/proxy likely not forwarding Upgrade/Connection headers, with the NGINX directives to fix
  • connection error — instance cannot reach its own external URL

The mechanism lives in a dedicated, unit-tested Gitlab::Duo::Administration::AgentPlatformWebsocketCheck class; the rake task handles presentation and diagnostics output.