executeRequest builds + serves + packages a single HTTP request against the wrapped handler. Pulled out of Dispatch so the special-case methods (dispatchItemUpdate, future RMW commands) can reuse the same auth-context + recorder + response-shaping path. Scope enforcement lives in buildAuthedRequest
( ctx context.Context, cmdKey string, user *models.User, method, urlPath string, body []byte, )
| 473 | // through this method. Codex review #369 round 2 caught the leak that |
| 474 | // motivated centralizing the check. |
| 475 | func (d *HTTPHandlerDispatcher) executeRequest( |
| 476 | ctx context.Context, |
| 477 | cmdKey string, |
| 478 | user *models.User, |
| 479 | method, urlPath string, |
| 480 | body []byte, |
| 481 | ) (*mcp.CallToolResult, error) { |
| 482 | req, err := d.buildAuthedRequest(ctx, method, urlPath, body, user) |
| 483 | if err != nil { |
| 484 | return buildRequestErrorResult(cmdKey, err), nil |
| 485 | } |
| 486 | |
| 487 | rec := httptest.NewRecorder() |
| 488 | d.Handler.ServeHTTP(rec, req) |
| 489 | // Use req.Context() (NOT the outer ctx) so the workspace lister |
| 490 | // sees everything buildHTTPRequest + d.Apply attached: |
| 491 | // WithCurrentUser, WithAPITokenAuth, and any TokenAllowedWorkspaces |
| 492 | // the dispatcher's Apply hook layered on. Tests that drive |
| 493 | // executeRequest with context.Background() + a UserResolver get |
| 494 | // the user via req.Context(), not via the outer ctx — without |
| 495 | // this fix the lister would silently return empty hints in |
| 496 | // those test paths and (more critically) in any production |
| 497 | // dispatcher that attaches token state via Apply rather than |
| 498 | // inheriting from the inbound request's ctx. Codex review #379 |
| 499 | // round 1. |
| 500 | return packageHTTPResponse(req.Context(), cmdKey, rec.Result(), d.Lister) |
| 501 | } |
| 502 | |
| 503 | // buildRequestErrorResult maps a buildAuthedRequest failure onto the |
| 504 | // structured error envelope. Extracted from executeRequest (BUG-2305, |