fix: preserve bridge auth for nested provider forwarding

This commit is contained in:
Haitao Pan 2026-04-14 15:18:59 +08:00
parent eaf0a6255f
commit 28ea0c8c52
2 changed files with 62 additions and 2 deletions

View File

@ -218,9 +218,13 @@ func sanitizeExternalACPParams(method string, params map[string]any) map[string]
delete(next, "resolvedGatewayProviderId")
delete(next, "resolvedModel")
delete(next, "resolvedSkills")
delete(next, inboundAuthorizationHeaderKey)
// Gateway-only fields are irrelevant in ACP single-agent forwarding.
normalizedMethod := strings.TrimSpace(method)
// Bridge-compatible upstream ACP services may need the inbound bearer token
// in params so they can forward auth again during nested provider execution.
if normalizedMethod != "session.start" && normalizedMethod != "session.message" {
delete(next, inboundAuthorizationHeaderKey)
}
// Gateway-only fields are irrelevant in ACP single-agent forwarding.
if normalizedMethod == "session.start" || normalizedMethod == "session.message" {
delete(next, "executionTarget")
delete(next, "agentId")

View File

@ -140,6 +140,62 @@ func TestBuiltInProviderReusesInboundBridgeBearerWhenUpstreamAuthUnset(t *testin
}
}
func TestBuiltInProviderPreservesInboundBridgeAuthParamForNestedForwarding(t *testing.T) {
externalServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if got := r.Header.Get("Authorization"); got != "Bearer bridge-token" {
t.Fatalf("expected inbound bridge bearer header, got %q", got)
}
defer func() {
_ = r.Body.Close()
}()
var request map[string]any
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
t.Fatalf("decode request: %v", err)
}
params := asMap(request["params"])
if got := params[inboundAuthorizationHeaderKey]; got != "Bearer bridge-token" {
t.Fatalf("expected nested bridge auth param to be preserved, got %#v", params)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"jsonrpc": "2.0",
"id": "run-auth-nested-forward",
"result": map[string]any{
"success": true,
"output": "forwarded-nested-auth-ok",
},
})
}))
defer externalServer.Close()
t.Setenv("INTERNAL_SERVICE_TOKEN", "")
t.Setenv("BRIDGE_AUTH_TOKEN", "")
server := NewServer()
setTestBridgeProvider(server, syncedProvider{
ProviderID: "codex",
Label: "Codex",
Endpoint: externalServer.URL,
Enabled: true,
})
recorder := httptest.NewRecorder()
request := httptest.NewRequest(
http.MethodPost,
"http://127.0.0.1/acp/rpc",
strings.NewReader(`{"jsonrpc":"2.0","id":"run-auth-nested-forward","method":"session.start","params":{"sessionId":"s1","threadId":"t1","taskPrompt":"hello","workingDirectory":"`+t.TempDir()+`","routing":{"routingMode":"explicit","explicitExecutionTarget":"singleAgent","explicitProviderId":"codex"}}}`),
)
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", "Bearer bridge-token")
server.HandleRPC(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", recorder.Code)
}
if !strings.Contains(recorder.Body.String(), "forwarded-nested-auth-ok") {
t.Fatalf("expected forwarded provider response, got %q", recorder.Body.String())
}
}
func TestProductionProviderCatalogFallsBackToBridgeAuthToken(t *testing.T) {
t.Setenv("INTERNAL_SERVICE_TOKEN", "")
t.Setenv("BRIDGE_AUTH_TOKEN", "bridge-auth-token")