feat: add /api/v2/aibridge/serve endpoint (#26506)

Adds a new enterprise-only `GET /api/v2/ai-gateway/serve` endpoint that standalone AI Gateway replicas use to connect to `coderd` over a DRPC-over-WebSocket transport, mirroring the existing in-memory path used by the embedded AI Bridge daemon.

- The endpoint upgrades the HTTP connection to a WebSocket, multiplexes it with yamux, and finally serves the three DRPC services (Recorder, MCPConfigurator, Authorizer).
- The `X-AI-Governance-Gateway-Key` header is used for authentication.
    - The key is looked up by its hashed secret
    - Missing or revoked keys return `401`.
- API version negotiation is enforced via a new `aibridged/proto` version (`v1.0`).
    - Incompatible versions return `400`.
- `FeatureAIBridge` entitlement is required.
- Key liveness (`last_used_at`) is recorded immediately on connection and refreshed every 60 seconds while the session remains open.
  - When key liveness detects the key was deleted (no rows where updated) session is closed.

#### Small refactors

* The three DRPC service registrations are extracted into `aibridgedserver.Register`, shared by both the in-memory and WebSocket paths.

* The literal `256 * 1024` used as the yamux-aligned WebSocket read limit is replaced with the named constant `drpcsdk.YamuxDefaultStreamWindowSize` in all call sites.
  * as noted in review comment https://github.com/coder/coder/pull/26506#discussion_r3461905223 order of `SetReadLimit` and `WebsocketNetConn` calls was fixed.
This commit is contained in:
Paweł Banaszewski
2026-06-26 18:27:37 +02:00
committed by GitHub
parent ad355aeaa9
commit 6189d6e386
17 changed files with 616 additions and 25 deletions
+4
View File
@@ -338,6 +338,10 @@ type Options struct {
// @securitydefinitions.apiKey CoderSessionToken
// @in header
// @name Coder-Session-Token
// @securitydefinitions.apiKey AIGatewayKey
// @in header
// @name X-AI-Governance-Gateway-Key
// New constructs a Coder API handler.
func New(options *Options) *API {
if options == nil {