Skip to content

refactor: replace pre-built SigV4 body signing with lazy BodySigner closure passed through request handlers - #4735

Merged
Pratham-Mishra04 merged 1 commit into
devfrom
06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook
Jun 27, 2026
Merged

Pratham-Mishra04 merged 1 commit into
devfrom
06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook

Conversation

@Pratham-Mishra04

Copy link
Copy Markdown
Collaborator

Summary

Replaces the pre-build-and-sign approach for Bedrock Mantle SigV4 authentication with a BodySigner callback that is invoked after the request handler has marshaled the body. This ensures the signature always covers the exact bytes sent on the wire, eliminating the previous double-marshal pattern where the body was built once for signing and again inside the handler.

Changes

  • Introduces a new BodySigner type (func(jsonData []byte) (map[string]string, *schemas.BifrostError)) in core/providers/utils/bodysigner.go. Handlers call it after building the request body and apply the returned headers to the outgoing request.
  • Adds the signer parameter to HandleOpenAIChatCompletionRequest, HandleOpenAIChatCompletionStreaming, HandleOpenAIResponsesRequest, HandleOpenAIResponsesStreaming, HandleAnthropicChatCompletionRequest, HandleAnthropicChatCompletionStreaming, HandleAnthropicResponsesRequest, and HandleAnthropicResponsesStream. All existing callers pass nil.
  • Rewrites Bedrock Mantle's SigV4 paths (mantleChatCompletions, mantleChatCompletionsStream, mantleResponses, mantleResponsesStream) to construct a BodySigner closure when no API key is present, instead of pre-building the body, signing it, and merging the signature headers into extraHeaders. The Bearer path no longer needs a separate early-return branch.
  • Removes the now-unnecessary maps import and the intermediate extraHeaders map copies in the Mantle code paths.

Type of change

  • Bug fix
  • Refactor
  • Feature
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./...

For Bedrock Mantle with SigV4 (empty key value), verify that requests to chat completions, streaming chat completions, responses, and streaming responses are signed correctly and accepted by the Bedrock endpoint. For Bearer key paths, confirm that no signing is attempted and the Authorization header is set as expected.

Breaking changes

  • Yes
  • No

Security considerations

The BodySigner callback signs the exact serialized bytes that are placed on the wire. Previously, the body was serialized twice (once for signing, once inside the handler), which could in theory produce a signature mismatch if marshaling were non-deterministic. This change closes that gap by signing after the final body is set.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Pratham-Mishra04, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 14 minutes and 47 seconds. Learn how PR review limits work.

To continue reviewing without waiting, enable usage-based billing in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 40196d5a-40f3-4cd5-a94b-1669216a6cdb

📥 Commits

Reviewing files that changed from the base of the PR and between d3fb617 and 0ffa262.

📒 Files selected for processing (20)
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/bedrock/mantle.go
  • core/providers/cerebras/cerebras.go
  • core/providers/fireworks/fireworks.go
  • core/providers/groq/groq.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/nebius/nebius.go
  • core/providers/ollama/ollama.go
  • core/providers/openai/openai.go
  • core/providers/opencode/opencode.go
  • core/providers/openrouter/openrouter.go
  • core/providers/parasail/parasail.go
  • core/providers/perplexity/perplexity.go
  • core/providers/sgl/sgl.go
  • core/providers/utils/bodysigner.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/providers/xai/xai.go
📝 Walkthrough

Walkthrough

OpenAI and Anthropic request handlers now accept optional body signers and apply returned headers when present. Mantle wires SigV4 signers into those handlers, and provider call sites were updated to pass the expanded argument lists.

Changes

Signed request plumbing

Layer / File(s) Summary
OpenAI body signing
core/providers/utils/bodysigner.go, core/providers/openai/openai.go
BodySigner is added, and the OpenAI chat completion and responses handlers accept it, sign finalized JSON bodies when provided, and update in-file call sites to pass nil.
Anthropic body signing
core/providers/anthropic/anthropic.go
completeRequest accepts BodySigner and signs unary request bodies when provided; Anthropic chat and responses handlers forward it, and their streaming paths sign the built request body when present.
Mantle SigV4 wiring
core/providers/bedrock/mantle.go
mantleChatCompletions, mantleChatCompletionsStream, mantleResponses, and mantleResponsesStream create BodySigner closures for SigV4 cases and pass them into the OpenAI-compatible helpers.
Chat and stream call-site updates
core/providers/azure/azure.go, core/providers/cerebras/cerebras.go, core/providers/fireworks/fireworks.go, core/providers/groq/groq.go, core/providers/huggingface/huggingface.go, core/providers/mistral/mistral.go, core/providers/nebius/nebius.go, core/providers/ollama/ollama.go, core/providers/openrouter/openrouter.go, core/providers/opencode/opencode.go, core/providers/parasail/parasail.go, core/providers/perplexity/perplexity.go, core/providers/sgl/sgl.go, core/providers/vertex/vertex.go, core/providers/vllm/vllm.go, core/providers/xai/xai.go
Chat completion and chat-stream handler calls across Azure, Cerebras, Fireworks, Groq, HuggingFace, Mistral, Nebius, Ollama, OpenRouter, Opencode, Parasail, Perplexity, SGL, Vertex, vLLM, and xAI pass nil for the new signer argument.
Response call-site updates
core/providers/azure/azure.go, core/providers/fireworks/fireworks.go, core/providers/openrouter/openrouter.go, core/providers/vertex/vertex.go, core/providers/xai/xai.go
Responses and responses-stream handler calls across Azure, Fireworks, OpenRouter, Vertex, and xAI pass nil for the new signer argument.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • maximhq/bifrost#1662: Also changes shared OpenAI handler signatures and matching nil call-site wiring.

Suggested reviewers

  • akshaydeo
  • danpiths
  • roroghost17

Poem

I thumped through headers, neat and light,
Then signed each request just right.
The burrow hummed in stream and spin,
With Mantle hops and Anthropic grin.
Carrots clap: the bytes are in!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main refactor to lazy BodySigner-based request signing.
Description check ✅ Passed The description matches the template well and covers summary, changes, testing, breaking changes, security, and checklist items.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Safe to merge for the targeted use case (non-large-payload SigV4 Bedrock Mantle requests); the streaming handlers have a known gap where LP passthrough and body-signing cannot be composed correctly, which the team is addressing in a dedicated follow-up.

The core signing seam works correctly for the intended path: non-streaming handlers reach the signer only after the large-payload early-return guard so jsonData is always the real body; streaming handlers call the signer on the same bytes that setStreamingRequestBody will place on the wire in normal mode. The mantleSigV4Headers improvement propagating x-amz-* from extraHeaders into the canonical request is a net correctness win. However, streaming handlers have no guard preventing the signer from receiving a nil slice when the large-payload passthrough reader is active, which will produce a SHA-256 over zero bytes while the wire body is the unbuffered passthrough content — a confirmed failure mode for anyone combining SigV4 Mantle with large-payload streaming. That interaction is already acknowledged and tracked for a follow-up; the refactor itself does not make the non-streaming path worse.

core/providers/openai/openai.go and core/providers/anthropic/anthropic.go streaming handlers (HandleOpenAIChatCompletionStreaming, HandleOpenAIResponsesStreaming, HandleAnthropicChatCompletionStreaming, HandleAnthropicResponsesStream) — these are the sites where the large-payload passthrough + signer guard needs to be added in the follow-up.

Important Files Changed

Filename Overview
core/providers/utils/bodysigner.go New file introducing the BodySigner type alias; clean, minimal, and correctly documented.
core/providers/bedrock/mantle.go Core refactor site: signer closures are correctly constructed per-call and are nil on the Bearer path; BearerAuthHeader correctly returns {} when key is empty so no spurious Authorization header is sent on the SigV4 path; mantleSigV4Headers correctly propagates x-amz-* extraHeaders into the signing request (new in this PR). The non-streaming LP passthrough early-return guard in the OpenAI handler prevents the signer from being called with a nil body, but the streaming paths have a known LP+SigV4 gap being tracked separately.
core/providers/openai/openai.go Non-streaming handler correctly calls signer after CheckContextAndGetRequestBody (LP passthrough returns early beforehand, so jsonData is always non-nil when signer fires). Streaming handler calls signer on jsonBody before setStreamingRequestBody; the LP passthrough + signer interaction for streaming is a confirmed gap tracked in a follow-up.
core/providers/anthropic/anthropic.go Signer added to completeRequest, HandleAnthropicChatCompletionRequest, HandleAnthropicChatCompletionStreaming, HandleAnthropicResponsesRequest, and HandleAnthropicResponsesStream. All native Anthropic callers pass nil. Streaming handlers have the same LP passthrough gap as the OpenAI streaming handlers. The defer-based resp release on signer error paths is syntactically correct Go.
core/providers/azure/azure.go Mechanical nil additions for the new signer parameter on all four call sites; no behavior change for Azure.
core/providers/vertex/vertex.go Mechanical nil additions for the new signer parameter; no behavior change for Vertex.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller as Caller (e.g. BedrockProvider)
    participant Handler as OpenAI/Anthropic Handler
    participant Signer as BodySigner closure
    participant AWS as AWS SigV4 (mantleSigV4Headers)
    participant Endpoint as Bedrock Mantle Endpoint

    Caller->>Handler: HandleOpenAIChatCompletionRequest(..., signer)
    Handler->>Handler: CheckContextAndGetRequestBody() → jsonData
    alt "signer != nil (SigV4 path)"
        Handler->>Signer: signer(jsonData)
        Signer->>AWS: mantleSigV4Headers(jsonData, url, accept, key, region, extraHeaders)
        AWS->>AWS: SHA256(jsonData), build canonical request
        AWS-->>Signer: "{Authorization, X-Amz-Date, x-amz-content-sha256, Accept}"
        Signer-->>Handler: sigHeaders
        Handler->>Handler: req.Header.Set(sigHeaders...)
    end
    Handler->>Handler: req.SetBody(jsonData)
    Handler->>Endpoint: POST with SigV4 headers + body
    Endpoint-->>Handler: 200 OK
    Handler-->>Caller: BifrostChatResponse
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller as Caller (e.g. BedrockProvider)
    participant Handler as OpenAI/Anthropic Handler
    participant Signer as BodySigner closure
    participant AWS as AWS SigV4 (mantleSigV4Headers)
    participant Endpoint as Bedrock Mantle Endpoint

    Caller->>Handler: HandleOpenAIChatCompletionRequest(..., signer)
    Handler->>Handler: CheckContextAndGetRequestBody() → jsonData
    alt "signer != nil (SigV4 path)"
        Handler->>Signer: signer(jsonData)
        Signer->>AWS: mantleSigV4Headers(jsonData, url, accept, key, region, extraHeaders)
        AWS->>AWS: SHA256(jsonData), build canonical request
        AWS-->>Signer: "{Authorization, X-Amz-Date, x-amz-content-sha256, Accept}"
        Signer-->>Handler: sigHeaders
        Handler->>Handler: req.Header.Set(sigHeaders...)
    end
    Handler->>Handler: req.SetBody(jsonData)
    Handler->>Endpoint: POST with SigV4 headers + body
    Endpoint-->>Handler: 200 OK
    Handler-->>Caller: BifrostChatResponse
Loading

Reviews (7): Last reviewed commit: "refactor: sign request body inside share..." | Re-trigger Greptile

Comment thread core/providers/openai/openai.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/anthropic/anthropic.go`:
- Around line 240-245: The signing path in anthropic request handling is using
the original jsonBody even when setAnthropicRequestBody switches to
large-payload passthrough and the request body is not actually set, so update
the signer input to use the exact bytes attached/sent on the request. Apply the
same fix in both streaming handlers as well, and in the relevant
request-building functions around setAnthropicRequestBody and signer, ensure any
signer error returns nil, bErr after performing the appropriate stream cleanup.
- Around line 245-247: The signer failure path in the Anthropic request flow
returns before cleanup, leaving acquired fasthttp resources and large-payload
passthrough state behind. Update the signer error handling in the affected
request/streaming paths around signer, resp, and DrainLargePayloadRemainder so
every error return first releases any acquired request/response objects and
drains any remaining large payload data before returning bErr. Ensure the same
cleanup is applied in all three affected locations, including the streaming
handlers.

In `@core/providers/bedrock/mantle.go`:
- Around line 80-82: The Mantle SigV4 signer currently signs only a synthetic
request with Accept, so any signable provider.networkConfig.ExtraHeaders
(especially x-amz-* headers) can be sent unsigned and break verification. Update
the signer closures in the Mantle flow to pass the relevant ExtraHeaders into
mantleSigV4Headers, or derive the canonical request from the prepared request
headers so the signed headers match what is actually sent.

In `@core/providers/openai/openai.go`:
- Around line 853-862: The large-payload passthrough path is returning before
SigV4 signing runs, so Mantle requests with an empty API key can skip request
signing. Move the signer execution ahead of the early return in
handleOpenAILargePayloadPassthrough so sigHeaders are always applied before any
passthrough decision. Also apply the same ordering fix in the corresponding
Responses helper in openai.go, using the same signer and header-setting flow.
- Around line 1054-1063: The signing logic in the streaming request flow is
applied before the final body and headers are fully assembled, so the signature
may not match what is actually sent. Update the streaming chat and responses
paths to call setStreamingRequestBody(...) before invoking signer(...), then
apply the returned signature headers to the request. Use the existing
setStreamingRequestBody and signer calls to ensure the body bytes and
Content-Type are finalized prior to signing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9fc973f3-67a5-4dcc-84a4-f022afe7a996

📥 Commits

Reviewing files that changed from the base of the PR and between 255444b and 6f73e03.

📒 Files selected for processing (20)
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/bedrock/mantle.go
  • core/providers/cerebras/cerebras.go
  • core/providers/fireworks/fireworks.go
  • core/providers/groq/groq.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/nebius/nebius.go
  • core/providers/ollama/ollama.go
  • core/providers/openai/openai.go
  • core/providers/opencode/opencode.go
  • core/providers/openrouter/openrouter.go
  • core/providers/parasail/parasail.go
  • core/providers/perplexity/perplexity.go
  • core/providers/sgl/sgl.go
  • core/providers/utils/bodysigner.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/providers/xai/xai.go

Comment thread core/providers/anthropic/anthropic.go
Comment thread core/providers/anthropic/anthropic.go
Comment thread core/providers/bedrock/mantle.go Outdated
Comment thread core/providers/openai/openai.go
Comment thread core/providers/openai/openai.go
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook branch from 6f73e03 to 36367b7 Compare June 27, 2026 08:45
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-15-refactor_standardize_openai_handlers_across_all_providers branch from 255444b to 5ed0ed4 Compare June 27, 2026 08:45
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 27, 2026
Comment thread core/providers/openai/openai.go
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook branch 2 times, most recently from 45b7753 to ee786b0 Compare June 27, 2026 10:30
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-15-refactor_standardize_openai_handlers_across_all_providers branch 2 times, most recently from 6b75376 to f0c7527 Compare June 27, 2026 13:56
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook branch from ee786b0 to 85f57cb Compare June 27, 2026 13:56

akshaydeo commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Merge activity

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook branch from 85f57cb to d3fb617 Compare June 27, 2026 16:08
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-15-refactor_standardize_openai_handlers_across_all_providers branch from f0c7527 to 453f7e9 Compare June 27, 2026 16:08
@coderabbitai
coderabbitai Bot requested a review from roroghost17 June 27, 2026 16:09
@Pratham-Mishra04
Pratham-Mishra04 changed the base branch from 06-15-refactor_standardize_openai_handlers_across_all_providers to graphite-base/4735 June 27, 2026 16:51
@Pratham-Mishra04
Pratham-Mishra04 changed the base branch from graphite-base/4735 to dev June 27, 2026 16:52
@Pratham-Mishra04
Pratham-Mishra04 dismissed coderabbitai[bot]’s stale review June 27, 2026 16:52

The base branch was changed.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook branch from d3fb617 to 0ffa262 Compare June 27, 2026 16:53
@Pratham-Mishra04
Pratham-Mishra04 merged commit 7268063 into dev Jun 27, 2026
14 of 16 checks passed
@Pratham-Mishra04
Pratham-Mishra04 deleted the 06-26-refactor_sign_request_body_inside_shared_openai_anthropic_handlers_via_a_bodysigner_hook branch June 27, 2026 16:55
akshaydeo pushed a commit that referenced this pull request Jun 30, 2026
… closure passed through request handlers (#4735)

## Summary

Replaces the pre-build-and-sign approach for Bedrock Mantle SigV4 authentication with a `BodySigner` callback that is invoked after the request handler has marshaled the body. This ensures the signature always covers the exact bytes sent on the wire, eliminating the previous double-marshal pattern where the body was built once for signing and again inside the handler.

## Changes

- Introduces a new `BodySigner` type (`func(jsonData []byte) (map[string]string, *schemas.BifrostError)`) in `core/providers/utils/bodysigner.go`. Handlers call it after building the request body and apply the returned headers to the outgoing request.
- Adds the `signer` parameter to `HandleOpenAIChatCompletionRequest`, `HandleOpenAIChatCompletionStreaming`, `HandleOpenAIResponsesRequest`, `HandleOpenAIResponsesStreaming`, `HandleAnthropicChatCompletionRequest`, `HandleAnthropicChatCompletionStreaming`, `HandleAnthropicResponsesRequest`, and `HandleAnthropicResponsesStream`. All existing callers pass `nil`.
- Rewrites Bedrock Mantle's SigV4 paths (`mantleChatCompletions`, `mantleChatCompletionsStream`, `mantleResponses`, `mantleResponsesStream`) to construct a `BodySigner` closure when no API key is present, instead of pre-building the body, signing it, and merging the signature headers into `extraHeaders`. The Bearer path no longer needs a separate early-return branch.
- Removes the now-unnecessary `maps` import and the intermediate `extraHeaders` map copies in the Mantle code paths.

## Type of change

- [ ] Bug fix
- [x] Refactor
- [ ] Feature
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./...
```

For Bedrock Mantle with SigV4 (empty key value), verify that requests to chat completions, streaming chat completions, responses, and streaming responses are signed correctly and accepted by the Bedrock endpoint. For Bearer key paths, confirm that no signing is attempted and the `Authorization` header is set as expected.

## Breaking changes

- [ ] Yes
- [x] No

## Security considerations

The `BodySigner` callback signs the exact serialized bytes that are placed on the wire. Previously, the body was serialized twice (once for signing, once inside the handler), which could in theory produce a signature mismatch if marshaling were non-deterministic. This change closes that gap by signing after the final body is set.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
@coderabbitai coderabbitai Bot mentioned this pull request Jun 30, 2026
7 tasks
R-droid101 pushed a commit to R-droid101/bifrost that referenced this pull request Jul 1, 2026
… closure passed through request handlers (maximhq#4735)

## Summary

Replaces the pre-build-and-sign approach for Bedrock Mantle SigV4 authentication with a `BodySigner` callback that is invoked after the request handler has marshaled the body. This ensures the signature always covers the exact bytes sent on the wire, eliminating the previous double-marshal pattern where the body was built once for signing and again inside the handler.

## Changes

- Introduces a new `BodySigner` type (`func(jsonData []byte) (map[string]string, *schemas.BifrostError)`) in `core/providers/utils/bodysigner.go`. Handlers call it after building the request body and apply the returned headers to the outgoing request.
- Adds the `signer` parameter to `HandleOpenAIChatCompletionRequest`, `HandleOpenAIChatCompletionStreaming`, `HandleOpenAIResponsesRequest`, `HandleOpenAIResponsesStreaming`, `HandleAnthropicChatCompletionRequest`, `HandleAnthropicChatCompletionStreaming`, `HandleAnthropicResponsesRequest`, and `HandleAnthropicResponsesStream`. All existing callers pass `nil`.
- Rewrites Bedrock Mantle's SigV4 paths (`mantleChatCompletions`, `mantleChatCompletionsStream`, `mantleResponses`, `mantleResponsesStream`) to construct a `BodySigner` closure when no API key is present, instead of pre-building the body, signing it, and merging the signature headers into `extraHeaders`. The Bearer path no longer needs a separate early-return branch.
- Removes the now-unnecessary `maps` import and the intermediate `extraHeaders` map copies in the Mantle code paths.

## Type of change

- [ ] Bug fix
- [x] Refactor
- [ ] Feature
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./...
```

For Bedrock Mantle with SigV4 (empty key value), verify that requests to chat completions, streaming chat completions, responses, and streaming responses are signed correctly and accepted by the Bedrock endpoint. For Bearer key paths, confirm that no signing is attempted and the `Authorization` header is set as expected.

## Breaking changes

- [ ] Yes
- [x] No

## Security considerations

The `BodySigner` callback signs the exact serialized bytes that are placed on the wire. Previously, the body was serialized twice (once for signing, once inside the handler), which could in theory produce a signature mismatch if marshaling were non-deterministic. This change closes that gap by signing after the final body is set.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
akshaydeo pushed a commit that referenced this pull request Jul 1, 2026
… closure passed through request handlers (#4735)

## Summary

Replaces the pre-build-and-sign approach for Bedrock Mantle SigV4 authentication with a `BodySigner` callback that is invoked after the request handler has marshaled the body. This ensures the signature always covers the exact bytes sent on the wire, eliminating the previous double-marshal pattern where the body was built once for signing and again inside the handler.

## Changes

- Introduces a new `BodySigner` type (`func(jsonData []byte) (map[string]string, *schemas.BifrostError)`) in `core/providers/utils/bodysigner.go`. Handlers call it after building the request body and apply the returned headers to the outgoing request.
- Adds the `signer` parameter to `HandleOpenAIChatCompletionRequest`, `HandleOpenAIChatCompletionStreaming`, `HandleOpenAIResponsesRequest`, `HandleOpenAIResponsesStreaming`, `HandleAnthropicChatCompletionRequest`, `HandleAnthropicChatCompletionStreaming`, `HandleAnthropicResponsesRequest`, and `HandleAnthropicResponsesStream`. All existing callers pass `nil`.
- Rewrites Bedrock Mantle's SigV4 paths (`mantleChatCompletions`, `mantleChatCompletionsStream`, `mantleResponses`, `mantleResponsesStream`) to construct a `BodySigner` closure when no API key is present, instead of pre-building the body, signing it, and merging the signature headers into `extraHeaders`. The Bearer path no longer needs a separate early-return branch.
- Removes the now-unnecessary `maps` import and the intermediate `extraHeaders` map copies in the Mantle code paths.

## Type of change

- [ ] Bug fix
- [x] Refactor
- [ ] Feature
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./...
```

For Bedrock Mantle with SigV4 (empty key value), verify that requests to chat completions, streaming chat completions, responses, and streaming responses are signed correctly and accepted by the Bedrock endpoint. For Bearer key paths, confirm that no signing is attempted and the `Authorization` header is set as expected.

## Breaking changes

- [ ] Yes
- [x] No

## Security considerations

The `BodySigner` callback signs the exact serialized bytes that are placed on the wire. Previously, the body was serialized twice (once for signing, once inside the handler), which could in theory produce a signature mismatch if marshaling were non-deterministic. This change closes that gap by signing after the final body is set.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
@coderabbitai coderabbitai Bot mentioned this pull request Jul 3, 2026
18 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants